ALL: Sync with ScummVM - rev. 823c2f899b

This commit is contained in:
Pawel Kolodziejski 2016-11-12 08:49:29 +01:00
parent 368d71cfd5
commit 9ba9c69b3f
241 changed files with 35724 additions and 10087 deletions

13
.gitignore vendored
View file

@ -9,6 +9,7 @@ lib*.a
/config.log /config.log
/residualvm /residualvm
/residualvm-static /residualvm-static
/ResidualVMDockTilePlugin*
/config.h /config.h
/config.mk /config.mk
/.gdb_history /.gdb_history
@ -19,6 +20,7 @@ lib*.a
/MT32_CONTROL.ROM /MT32_CONTROL.ROM
/MT32_PCM.ROM /MT32_PCM.ROM
/ResidualVM.app /ResidualVM.app
/residualvm.docktileplugin
/residualvm-ps3.pkg /residualvm-ps3.pkg
/*.ipk /*.ipk
/*.dmg /*.dmg
@ -29,6 +31,7 @@ lib*.a
/Icon.* /Icon.*
/*.m4b /*.m4b
/*.lab /*.lab
/*.dat
/build /build
/staging /staging
@ -79,6 +82,7 @@ project.xcworkspace
/test/*.dSYM /test/*.dSYM
/devtools/create_project/create_project /devtools/create_project/create_project
/devtools/create_translations/create_translations
#ignore thumbnails created by windows #ignore thumbnails created by windows
Thumbs.db Thumbs.db
@ -113,10 +117,15 @@ ipch/
*.vcxproj* *.vcxproj*
*.bat *.bat
*.tss *.tss
*.VC.db
#Ignore default Visual Studio build folders #Ignore default Visual Studio build folders
[Dd]ebug*/ [Dd]ebug/
[Rr]elease*/ [Rr]elease/
[Dd]ebug32/
[Rr]elease32/
[Dd]ebug64/
[Rr]elease64/
LLVM32/ LLVM32/
LLVM64/ LLVM64/

40
.travis.yml Normal file
View file

@ -0,0 +1,40 @@
language:
- cpp
sudo: false
addons:
apt:
packages:
- g++ make
- libsdl1.2-dev
- libjpeg62-turbo-dev
- libmpeg2-4-dev
- libogg-dev
- libvorbis-dev
- libflac-dev
- libmad0-dev
- libpng-dev
- libglew-dev
- libtheora-dev
- libfaad-dev
- libfluidsynth-dev
- libfreetype6-dev
- zlib1g-dev
branches:
only:
- master
compiler:
- gcc
- clang
os:
- linux
script:
- ./configure --enable-all-engines --disable-eventrecorder
- make -j 2
- make test
- make devtools

274
COPYRIGHT
View file

@ -59,214 +59,404 @@ Copyright (C) 2001-2016 by the following:
If you have contributed to this project then you deserve to be on this If you have contributed to this project then you deserve to be on this
list. Contact us (see: AUTHORS) and we'll add you. list. Contact us (see: AUTHORS) and we'll add you.
Tore Anderson Manuel Alfayate
Torbjorn Andersson Torbjorn Andersson
Tore Anderson
Matteo Angelino
Chris Apers Chris Apers
Adrian Astley
Bertrand Augereau
Ori Avtalion Ori Avtalion
Nicolas Bacca Nicolas Bacca
Dobo Balazs
Daniel Balsom
Yotam Barnoy
Fabio Battaglia Fabio Battaglia
Vincent Benony
Alex Bevilacqua
Laurent Blume
Bastien Bouclet Bastien Bouclet
Arnaud Boutonne Arnaud Boutonne
Francois-R Boyer
Peter Bozso
Jurgen Braam Jurgen Braam
Ralph Brorsen Ralph Brorsen
James Brown James Brown
Henry Bush
Stuart Caie Stuart Caie
Rainer Canavan
Ben Castricum
Xiaojun Chen
Jamieson Christian Jamieson Christian
Ryan Clark
William Claydon
Fabien Coeurjoly
Marcus Comstedt Marcus Comstedt
David Corrales-Lopez
Paolo Costabel Paolo Costabel
Robert Crossfield
Thierry Crozat Thierry Crozat
Vyacheslav Dikonov
Paul David Doherty
Martin Doucha
Ivan Dubrov Ivan Dubrov
Frantisek Dufka Frantisek Dufka
Sylvain Dupont
Joachim Eberhard
Thomas Edvalson
Oystein Eftevaag Oystein Eftevaag
Kovacs Endre Janos
David Eriksson David Eriksson
Thomas Fach-Pedersen
Yaroslav Fedevych
Jerome Fisher Jerome Fisher
Hampus Flink
Hans-Joerg Frieden
Greg Frieger
Tom Frost
Stuart George Stuart George
Paul Gilbert Paul Gilbert
Jean Marc Gimenez
Robert Goeffringmann Robert Goeffringmann
Victor Gonzalez
GrajPoPolsku.pl Team
Chris Gray
Jonathan Gray Jonathan Gray
Tobias Gunkel
Benjamin Haisch Benjamin Haisch
Vincent Hamm Vincent Hamm
Ruediger Hanke
Matt Hargett
Andre Heider
Sven Hesse Sven Hesse
Jochen Hoenicke Jochen Hoenicke
Matthew Hoops Matthew Hoops
Max Horn Max Horn
Travis Howell Travis Howell
Janne Huttunen Janne Huttunen
Ravi I.
Felix Jakschitsch Felix Jakschitsch
Kovacs Endre Janos
Jeroen Janssen Jeroen Janssen
Emmanuel Jeandel
Dmitry Jemerov
David Jensen
Florian Kagerer Florian Kagerer
Keith Kaisershot
Filippos Karapetis Filippos Karapetis
Andreas Karlsson Andreas Karlsson
Denis Kasak
Chris Kehler
Robert Kelsen
Ismail Khatib Ismail Khatib
Oliver Kiehl Oliver Kiehl
Martin Kiewitz Martin Kiewitz
Pawel Kolodziejski Pawel Kolodziejski
George Kormendi
Mutwin Kraus Mutwin Kraus
Stefan Kristiansson
Andrew Kurushin Andrew Kurushin
Daniel ter Laan
Hugo Labrande
Christopher T. Lansdown
Sergey Lapin
Angus Lees Angus Lees
Rickard Lind
Max Lingua
Lubomyr Lisen
Ivan Lukyanov
Tomas Maidagan
Hubert Maier
Johannes Manhave
Lothar Serra Mari
Vicent Marti
Claudio Matsuoka Claudio Matsuoka
Thomas Mayer Thomas Mayer
Robert Megone
Vladimir Menshakov
Alyssa Milburn Alyssa Milburn
Neil Millstone Neil Millstone
Dark Minister
Gregory Montoir Gregory Montoir
Peter Moraliyski
Carl Muckenhoupt
Alejandro Gomez de la Munoza
Sean Murray
Kostas Nakos Kostas Nakos
Mikesch Nepomuk Mikesch Nepomuk
Jeremy Newman
Anders Baden Nielsen
Juha Niemimaki
Walter van Niftrik
Nicolas Noble Nicolas Noble
Steffen Nyeland
Rune Orsval
Chris Page
Willem Jan Palenstijn Willem Jan Palenstijn
Stefan Parviainen
Solomon Peachy
Lars Persson Lars Persson
Joost Peters Joost Peters
Tim Phillips Tim Phillips
Robey Pointer
Jordi Vilalta Prat
Magnus Reftel
Christoph Reichenbach
George Reid
Klaus Reimer
Andreas Roever
Edward Rudd Edward Rudd
Toni Saarela
Kari Salminen
Eugene Sandulenko Eugene Sandulenko
Santiago G. Sanz
Simon Sawatzki
Daniel Schepler
Dominik Scherer
Johannes Schickel Johannes Schickel
Luc Schrijvers
Zbynik Schwarz
Keith Scroggins Keith Scroggins
Dan Serban
Lars Skovlund
Paul Smedley
Colin Snover
Tarek Soliman
Einar Johan T. Somaaen
Andre Souza
Robert Spalek
Rink Springer
Won Star Won Star
Markus Strangl
Ludvig Strigeus Ludvig Strigeus
Fedor Strizhniou Fedor Strizhniou
David Symonds David Symonds
Jordi Vilalta Rainer De Temple
Julien Templier
Sean Terrell
Tobia Tesan
Scott Thomas
David Turner
Lionel Ulmer
Mikel Iturbe Urretxa
Hugues Valois
Petr Vyhnak
Chris Warren-Smith
Robin Watts Robin Watts
Lukasz Watka
David Weinehall
Fredrik Wendel
John Willis John Willis
Anton Yarcev
Bas Zoetekouw
Jezar Jezar
n0p n0p
peres peres
Quietust Quietust
ScummBR Team
Raina
Patches contributed by: Patches contributed by:
Laura Abbott "sageofminerva" Laura Abbott "sageofminerva"
Vikram Aggarwal "youngelf" Vikram Aggarwal "youngelf"
the rara avis "theraraavis" Norbert Bajko
Giovanni Bajo
Matan Bareket
Dieter Baron "dillo" Dieter Baron "dillo"
Kevin Becker
Alban Bedel "albeu" Alban Bedel "albeu"
Bodo Bellut "bellut" Bodo Bellut "bellut"
Bramvandijk "bramvandijk" Nagy Bendeguz
Andreas Bierfert "awjb" Andreas Bierfert "awjb"
Kaustav Biswas
Elio Blanca "eblanca76" Elio Blanca "eblanca76"
Martin Bohm
David Breakey "dbreakey" David Breakey "dbreakey"
Michael du Breuil "WickedShell"
Michael Brown
Robert Buchholz "prendi" Robert Buchholz "prendi"
Rainer Canavan "canavan" Sander Buskens
Giulio Camuffo
Kevin Carnes
Mathieu Carot "yokna" Mathieu Carot "yokna"
Stefano Ceccherini "jackburton" Stefano Ceccherini "jackburton"
Travis S Coady "theealien" Travis S Coady "theealien"
Josh Coalson "jcoalson" Josh Coalson "jcoalson"
Curt Coder
Thomas Combeleran "hibernatus" Thomas Combeleran "hibernatus"
Patrick Combet
Kees Cook "keescook" Kees Cook "keescook"
Carlos Corbacho "cathectic" Carlos Corbacho "cathectic"
Andrea Corna
Roberto Costa "fiix76" Roberto Costa "fiix76"
dc france "erwan2004" Eric Culp
dewt "mncl" Alexander Dergunov
Martin Doucha "next_ghost" Alexandre Detiste
Roman Donchenko
Heather Douglass
Michael Drueing "doc_wagon" Michael Drueing "doc_wagon"
Michael du Breuil "WickedShell"
dubsdj
Matthew Duggan "stauff1" Matthew Duggan "stauff1"
Barry Duncan
Olivier Duverne "richiefs" Olivier Duverne "richiefs"
Andrei Dziahel "develop7" Andrei Dziahel "develop7"
John Eckerdal "johneck" John Eckerdal "johneck"
Thomas Fach-Pedersen "madm00se" Abdeselam El-Haman
Florent "flobo" Henrik Engqvist
Florob "florob"
Mike Frysinger "vapier" Mike Frysinger "vapier"
Bence Gazder
Chris Gelatt "kreeblah" Chris Gelatt "kreeblah"
Jens Georg "phako" Jens Georg "phako"
Nicolas George "cigaes" Nicolas George "cigaes"
Martin Gerhardy
Jonathan Gevaryahu "lord_nightmare" Jonathan Gevaryahu "lord_nightmare"
Boris Gnezdilov
Tobias Gruetzmacher "tobig" Tobias Gruetzmacher "tobig"
Damien Guard "damienguard" Damien Guard "damienguard"
Tobias Gunkel "tobigun"
Matti Hamalainen "ccrtnsp" Matti Hamalainen "ccrtnsp"
Matt Hargett "matt_hargett" Lauri Harsila
Stefan Haubenthal "polluks" Stefan Haubenthal "polluks"
Gavin Hayler
Alexander Holler "holler" Alexander Holler "holler"
Enrico Horn
Falk Hueffner "mellum" Falk Hueffner "mellum"
Casey Hutchinson "nnooiissee" Casey Hutchinson "nnooiissee"
j0tt Tomas Jakobsson
Gregor Jasny "gjasny" Gregor Jasny "gjasny"
Jellby "jellby"
Joerg "macdrega"
Matt Johnson "mattjon" Matt Johnson "mattjon"
Nicolas Joly "njoly" Nicolas Joly "njoly"
KeithS "keithscr" Yusuke Kamiyamane
Martin Kennedy
Stephen Kennedy
Sam Kenny "sam_k" Sam Kenny "sam_k"
Koen Kooi "koenkooi" Koen Kooi "koenkooi"
Christoph Korn
Christian Krause
Till Kresslein
Zygmunt Krynicki "zygoon" Zygmunt Krynicki "zygoon"
Janne Kujanpaa "jukuja" Janne Kujanpaa "jukuja"
Neeraj Kumar
Oleksiy Kurochko
Jay Lanagan "r0ni" Jay Lanagan "r0ni"
Norbert Lange "nolange" Norbert Lange "nolange"
Manuel Lauss "mlau2" Manuel Lauss "mlau2"
Rolf Leggewie "leggewie" Rolf Leggewie "leggewie"
Jim Leiterman
Matt Lewandowsky
Chenbo Li
Rob Loach
Duncan Lock "dflock" Duncan Lock "dflock"
Mark Lodato "itsr0y" Mark Lodato "itsr0y"
Fridvin Logi "phillip_j_fry" Fridvin Logi "phillip_j_fry"
Lostech "lostech" Michael Lojkovic
Borja Lorente Escobar
Georg Lukas "ge0rg" Georg Lukas "ge0rg"
Artem Lukoyanov
Michael Madsen "pidgeot" Michael Madsen "pidgeot"
Matthias Mailander
Narek Mailian
Christoph Mallon
Engin Manap
Dmitry Marakasov "amdmi3" Dmitry Marakasov "amdmi3"
Alejandro Marzini "vgvgf" Alejandro Marzini "vgvgf"
Connor McLeod "mcleod2032" Connor McLeod "mcleod2032"
Mickey McMurray "metafox" Mickey McMurray "metafox"
Vladimir Menshakov "megath"
Adam Metcalf "gamblore" Adam Metcalf "gamblore"
Nicola Mettifogo
Frank Meyering "frank_m24" Frank Meyering "frank_m24"
Gael Le Migno "kilobug" Gael Le Migno "kilobug"
Etienne Millon
Andy Molloy "maloi" Andy Molloy "maloi"
Sean Murrau "lightcast" Omer Mor
Armin Mueller "arm_in" Armin Mueller "arm_in"
Sean Murrau "lightcast"
Andrea Musuruane "musuruan" Andrea Musuruane "musuruan"
KO Myung-Hun "lvzuufx" KO Myung-Hun "lvzuufx"
Markus Napp "meist3r" Markus Napp "meist3r"
Peter Naulls "pnaulls" Peter Naulls "pnaulls"
Christian Neumair "mannythegnome" Christian Neumair "mannythegnome"
Nicos "anarxia" Hannes Niederhausen
Juha Niemimaki "capehill"
Markus Niemisto "niemisto" Markus Niemisto "niemisto"
ole Bastien Nocera
Jody Northup
Julian Ospald
Christopher Page
Chris Paras "paras_rasmatazz" Chris Paras "paras_rasmatazz"
Aubin Paul "outlyer" Aubin Paul "outlyer"
Michael Pearce
Vincent Pelletier "subdino" Vincent Pelletier "subdino"
phi1 Jussi Pitkanen
Pix2 "pix2"
Carsten Pohl "carstenpohl" Carsten Pohl "carstenpohl"
Tony Puccinelli
Markus Pyykko "mankeli" Markus Pyykko "mankeli"
Richard "trinity78" Rodrigo Rebello
Felix Riemann "kirschsaft" Alexander Reim
Thomas Richter "thorfdbg" Thomas Richter "thorfdbg"
Felix Riemann "kirschsaft"
Timo Roehling "t1m0" Timo Roehling "t1m0"
Andreas Roever "roever"
Jonathan Rogers "jonner" Jonathan Rogers "jonner"
Enrico Rolfi
Doron Rosenberg
Marek Roth "logicdeluxe" Marek Roth "logicdeluxe"
David Russo
Uwe Ryssel "uweryssel" Uwe Ryssel "uweryssel"
Simon Sawatzki "simsaw"
Scarlatti "escarlate"
Daniel Schepler "dschepler"
Florian Schmitt "fatpenguin" Florian Schmitt "fatpenguin"
Mark Schreiber "mark7" Mark Schreiber "mark7"
Ben Shadwick "benshadwick" Ben Shadwick "benshadwick"
Rodrigo Silva
Jean-Yves Simon "lethalwp" Jean-Yves Simon "lethalwp"
Andrej Sinicyn "andrej4000" Andrej Sinicyn "andrej4000"
Andre Souza "luke_br" Dmitry Smirnov
spookypeanut "spookypeanut"
Steve Stavropoulos "isnothere" Steve Stavropoulos "isnothere"
Daniel Steinberger "amorphousshape" Daniel Steinberger "amorphousshape"
Sven Strothoff "dataslayer" Sven Strothoff "dataslayer"
Andrea Suatoni "mrhandler" Andrea Suatoni "mrhandler"
tbcarey Max Tabachenko
Tim "tipabu" DOSBox Team
Sarien Team
Joel Teichroeb
Jimmi Thogersen
Alexander Tkachov
Pino Toscano
Luigi Toscano "ltosky" Luigi Toscano "ltosky"
Xavier Trochu "xtrochu" Xavier Trochu "xtrochu"
Vasyl Tsvirkunov
Michal Tulacek "tutchek" Michal Tulacek "tutchek"
Michael Udaltsov "cccp99" Michael Udaltsov "cccp99"
Joni Vahamaki
Kristof Vansant "lupusbe" Kristof Vansant "lupusbe"
Aaryaman Vasishta
Tim Walters "realmz" Tim Walters "realmz"
David Weinehall "weine"
Eric A. Welsh "eweish42" Eric A. Welsh "eweish42"
Yudhi Widyatama "yudhi97" Yudhi Widyatama "yudhi97"
Jakub Wilk
Kieron Wilkinson
Robert Wohlrab "moshroum" Robert Wohlrab "moshroum"
Xanathar "xanathar" James Woodcock
Grant Yeager "glo_kidd" Grant Yeager "glo_kidd"
Benjamin W. Zale "junior_aepi" Benjamin W. Zale "junior_aepi"
Yotam Barnoy "bluddy" Kamil Zbrog
Tom Frost "TomFrost" Michal Ziabkowski
Bramvandijk "bramvandijk"
Canadacow
countingpine
Damien
dc france "erwan2004"
dewt "mncl"
dubsdj
Florent "flobo"
Florob "florob"
j0tt
Jellby "jellby"
Joerg "macdrega"
Lostech "lostech"
Nicos "anarxia"
ole
phi1
Pix2 "pix2"
Richard "trinity78"
Scarlatti "escarlate"
the rara avis "theraraavis"
Tim "tipabu"
vandalo
Xanathar "xanathar"

View file

@ -20,7 +20,6 @@
* *
*/ */
#include "audio/softsynth/emumidi.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/error.h" #include "common/error.h"
#include "common/scummsys.h" #include "common/scummsys.h"

View file

@ -25,7 +25,6 @@
#include "common/util.h" #include "common/util.h"
#include "audio/decoders/3do.h" #include "audio/decoders/3do.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/adpcm_intern.h" #include "audio/decoders/adpcm_intern.h"
namespace Audio { namespace Audio {

View file

@ -31,19 +31,12 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#include "common/types.h" #include "common/types.h"
#include "common/substream.h" #include "common/stream.h"
#include "audio/audiostream.h" #include "audio/audiostream.h"
#include "audio/decoders/raw.h"
namespace Common {
class SeekableReadStream;
}
namespace Audio { namespace Audio {
class SeekableAudioStream;
// amount of bytes to be used within the decoder classes as buffers // amount of bytes to be used within the decoder classes as buffers
#define AUDIO_3DO_CACHE_SIZE 1024 #define AUDIO_3DO_CACHE_SIZE 1024

View file

@ -320,10 +320,11 @@ int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
_decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f); _decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f);
_decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[_channels - 1], data & 0x0f); _decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[_channels - 1], data & 0x0f);
} }
_decodedSampleIndex = 0;
} }
// (1 - (count - 1)) ensures that _decodedSamples acts as a FIFO of depth 2 // _decodedSamples acts as a FIFO of depth 2 or 4;
buffer[samples] = _decodedSamples[1 - (_decodedSampleCount - 1)]; buffer[samples] = _decodedSamples[_decodedSampleIndex++];
_decodedSampleCount--; _decodedSampleCount--;
} }
@ -433,7 +434,7 @@ int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) {
return samp; return samp;
} }
RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, ADPCMType type, int rate, int channels, uint32 blockAlign) { SeekableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, ADPCMType type, int rate, int channels, uint32 blockAlign) {
// If size is 0, report the entire size of the stream // If size is 0, report the entire size of the stream
if (!size) if (!size)
size = stream->size(); size = stream->size();

View file

@ -45,7 +45,7 @@ class SeekableReadStream;
namespace Audio { namespace Audio {
class PacketizedAudioStream; class PacketizedAudioStream;
class RewindableAudioStream; class SeekableAudioStream;
// There are several types of ADPCM encoding, only some are supported here // There are several types of ADPCM encoding, only some are supported here
// For all the different encodings, refer to: // For all the different encodings, refer to:
@ -74,7 +74,7 @@ enum ADPCMType {
* @param blockAlign block alignment ??? * @param blockAlign block alignment ???
* @return a new RewindableAudioStream, or NULL, if an error occurred * @return a new RewindableAudioStream, or NULL, if an error occurred
*/ */
RewindableAudioStream *makeADPCMStream( SeekableAudioStream *makeADPCMStream(
Common::SeekableReadStream *stream, Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse, DisposeAfterUse::Flag disposeAfterUse,
uint32 size, ADPCMType type, uint32 size, ADPCMType type,

View file

@ -39,7 +39,7 @@
namespace Audio { namespace Audio {
class ADPCMStream : public RewindableAudioStream { class ADPCMStream : public SeekableAudioStream {
protected: protected:
Common::DisposablePtr<Common::SeekableReadStream> _stream; Common::DisposablePtr<Common::SeekableReadStream> _stream;
int32 _startpos; int32 _startpos;
@ -67,6 +67,8 @@ public:
virtual int getRate() const { return _rate; } virtual int getRate() const { return _rate; }
virtual bool rewind(); virtual bool rewind();
virtual bool seek(const Timestamp &where) { return false; }
virtual Timestamp getLength() const { return -1; }
/** /**
* This table is used by some ADPCM variants (IMA and OKI) to adjust the * This table is used by some ADPCM variants (IMA and OKI) to adjust the
@ -207,6 +209,7 @@ public:
error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM"); error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM");
memset(&_status, 0, sizeof(_status)); memset(&_status, 0, sizeof(_status));
_decodedSampleCount = 0; _decodedSampleCount = 0;
_decodedSampleIndex = 0;
} }
virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); } virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
@ -218,6 +221,7 @@ protected:
private: private:
uint8 _decodedSampleCount; uint8 _decodedSampleCount;
uint8 _decodedSampleIndex;
int16 _decodedSamples[4]; int16 _decodedSamples[4];
}; };

View file

@ -129,6 +129,8 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
foundSSND = true; foundSSND = true;
/* uint32 offset = */ stream->readUint32BE(); /* uint32 offset = */ stream->readUint32BE();
/* uint32 blockAlign = */ stream->readUint32BE(); /* uint32 blockAlign = */ stream->readUint32BE();
if (dataStream)
delete dataStream;
dataStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + length - 8, disposeAfterUse); dataStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + length - 8, disposeAfterUse);
break; break;
case MKTAG('F', 'V', 'E', 'R'): case MKTAG('F', 'V', 'E', 'R'):
@ -154,7 +156,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
return 0; return 0;
default: default:
debug(1, "Skipping AIFF '%s' chunk", tag2str(tag)); debug(1, "Skipping AIFF '%s' chunk", tag2str(tag));
break; break;
} }
stream->seek(pos + length + (length & 1)); // ensure we're also word-aligned stream->seek(pos + length + (length & 1)); // ensure we're also word-aligned
@ -203,7 +205,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
if (codec == MKTAG('s', 'o', 'w', 't')) if (codec == MKTAG('s', 'o', 'w', 't'))
rawFlags |= Audio::FLAG_LITTLE_ENDIAN; rawFlags |= Audio::FLAG_LITTLE_ENDIAN;
return makeRawStream(dataStream, rate, rawFlags); return makeRawStream(dataStream, rate, rawFlags);
} }
case MKTAG('i', 'm', 'a', '4'): case MKTAG('i', 'm', 'a', '4'):
// TODO: Use QT IMA ADPCM // TODO: Use QT IMA ADPCM
@ -212,7 +214,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
case MKTAG('Q', 'D', 'M', '2'): case MKTAG('Q', 'D', 'M', '2'):
// TODO: Need to figure out how to integrate this // TODO: Need to figure out how to integrate this
// (But hopefully never needed) // (But hopefully never needed)
warning("Unhandled AIFF-C QDM2 compression"); warning("Unhandled AIFF-C QDM2 compression");
break; break;
case MKTAG('A', 'D', 'P', '4'): case MKTAG('A', 'D', 'P', '4'):
// ADP4 on 3DO // ADP4 on 3DO

View file

@ -35,6 +35,7 @@
* - sword25 * - sword25
* - touche * - touche
* - tucker * - tucker
* - wintermute
*/ */
#ifndef AUDIO_VORBIS_H #ifndef AUDIO_VORBIS_H

View file

@ -158,7 +158,7 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate,
return true; return true;
} }
RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) { SeekableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
int size, rate; int size, rate;
byte flags; byte flags;
uint16 type; uint16 type;

View file

@ -56,7 +56,7 @@ class SeekableReadStream;
namespace Audio { namespace Audio {
class RewindableAudioStream; class SeekableAudioStream;
/** /**
* Try to load a WAVE from the given seekable stream. Returns true if * Try to load a WAVE from the given seekable stream. Returns true if
@ -82,9 +82,9 @@ extern bool loadWAVFromStream(
* *
* @param stream the SeekableReadStream from which to read the WAVE data * @param stream the SeekableReadStream from which to read the WAVE data
* @param disposeAfterUse whether to delete the stream after use * @param disposeAfterUse whether to delete the stream after use
* @return a new RewindableAudioStream, or NULL, if an error occurred * @return a new SeekableAudioStream, or NULL, if an error occurred
*/ */
RewindableAudioStream *makeWAVStream( SeekableAudioStream *makeWAVStream(
Common::SeekableReadStream *stream, Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse); DisposeAfterUse::Flag disposeAfterUse);

View file

@ -27,7 +27,6 @@
#include "common/textconsole.h" #include "common/textconsole.h"
#include "audio/fmopl.h" #include "audio/fmopl.h"
#include "audio/softsynth/emumidi.h"
namespace Audio { namespace Audio {

View file

@ -140,10 +140,7 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe
} }
_reportHandler = NULL; _reportHandler = NULL;
_synth = NULL; _synth = NULL;
// Unfortunately bugs in the emulator cause inaccurate tuning _outputRate = 0;
// at rates other than 32KHz, thus we produce data at 32KHz and
// rely on Mixer to convert.
_outputRate = 32000; //_mixer->getOutputRate();
_initializing = false; _initializing = false;
// Initialized in open() // Initialized in open()
@ -180,7 +177,6 @@ int MidiDriver_MT32::open() {
if (_isOpen) if (_isOpen)
return MERR_ALREADY_OPEN; return MERR_ALREADY_OPEN;
MidiDriver_Emulated::open();
_reportHandler = new MT32Emu::ReportHandlerScummVM(); _reportHandler = new MT32Emu::ReportHandlerScummVM();
_synth = new MT32Emu::Synth(_reportHandler); _synth = new MT32Emu::Synth(_reportHandler);
@ -212,6 +208,18 @@ int MidiDriver_MT32::open() {
double gain = (double)ConfMan.getInt("midi_gain") / 100.0; double gain = (double)ConfMan.getInt("midi_gain") / 100.0;
_synth->setOutputGain(1.0f * gain); _synth->setOutputGain(1.0f * gain);
_synth->setReverbOutputGain(0.68f * gain); _synth->setReverbOutputGain(0.68f * gain);
// We let the synthesizer play MIDI messages immediately. Our MIDI
// handling is synchronous to sample generation. This makes delaying MIDI
// events result in odd sound output in some cases. For example, the
// shattering window in the Indiana Jones and the Fate of Atlantis intro
// will sound like a bell if we use any delay here.
// Bug #6242 "AUDIO: Built-In MT-32 MUNT Produces Wrong Sounds".
_synth->setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE);
// We need to report the sample rate MUNT renders at as sample rate of our
// AudioStream.
_outputRate = _synth->getStereoOutputSampleRate();
MidiDriver_Emulated::open();
_initializing = false; _initializing = false;

View file

@ -0,0 +1,199 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "backends/audiocd/audiocd-stream.h"
#include "common/textconsole.h"
AudioCDStream::AudioCDStream() : _buffer(), _frame(0), _bufferPos(0), _bufferFrame(0), _forceStop(false) {
}
AudioCDStream::~AudioCDStream() {
// Stop the timer; the subclass needs to do this,
// so this is just a last resort.
stopTimer();
// Clear any buffered frames
emptyQueue();
}
int AudioCDStream::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
// See if any data is left first
while (_bufferPos < kSamplesPerFrame && samples < numSamples)
buffer[samples++] = _buffer[_bufferPos++];
// Bail out if done
if (endOfData())
return samples;
while (samples < numSamples && !endOfData()) {
if (!readNextFrame())
return samples;
// Copy the samples over
for (_bufferPos = 0; _bufferPos < kSamplesPerFrame && samples < numSamples;)
buffer[samples++] = _buffer[_bufferPos++];
}
return samples;
}
bool AudioCDStream::readNextFrame() {
// Fetch a frame from the queue
int16 *buffer;
{
Common::StackLock lock(_mutex);
// Nothing we can do if it's empty
if (_bufferQueue.empty())
return false;
buffer = _bufferQueue.pop();
}
memcpy(_buffer, buffer, kSamplesPerFrame * 2);
delete[] buffer;
_frame++;
return true;
}
bool AudioCDStream::endOfData() const {
return !shouldForceStop() && getStartFrame() + _frame >= getEndFrame() && _bufferPos == kSamplesPerFrame;
}
bool AudioCDStream::seek(const Audio::Timestamp &where) {
// Stop the timer
stopTimer();
// Clear anything out of the queue
emptyQueue();
// Convert to the frame number
// Really not much else needed
_bufferPos = kSamplesPerFrame;
_frame = where.convertToFramerate(kFramesPerSecond).totalNumberOfFrames();
_bufferFrame = _frame;
// Start the timer again
startTimer();
return true;
}
Audio::Timestamp AudioCDStream::getLength() const {
return Audio::Timestamp(0, getEndFrame() - getStartFrame(), kFramesPerSecond);
}
void AudioCDStream::timerProc(void *refCon) {
static_cast<AudioCDStream *>(refCon)->onTimer();
}
void AudioCDStream::onTimer() {
// The goal here is to do as much work in this timer instead
// of doing it in the readBuffer() call, which is the mixer.
// If we're done, bail.
if (shouldForceStop() || getStartFrame() + _bufferFrame >= getEndFrame())
return;
// Get a quick count of the number of items in the queue
// We don't care that much; we only need a quick estimate
_mutex.lock();
uint32 queueCount = _bufferQueue.size();
_mutex.unlock();
// If we have enough audio buffered, bail out
if (queueCount >= kBufferThreshold)
return;
while (!shouldForceStop() && queueCount < kBufferThreshold && getStartFrame() + _bufferFrame < getEndFrame()) {
int16 *buffer = new int16[kSamplesPerFrame];
// Figure out the MSF of the frame we're looking for
int frame = _bufferFrame + getStartFrame();
// Request to read that frame
if (!readFrame(frame, buffer)) {
warning("Failed to read CD audio");
forceStop();
return;
}
_bufferFrame++;
// Now push the buffer onto the queue
Common::StackLock lock(_mutex);
_bufferQueue.push(buffer);
queueCount = _bufferQueue.size();
}
}
void AudioCDStream::startTimer(bool fillBuffer) {
_forceStop = false;
if (fillBuffer) {
onTimer();
}
g_system->getTimerManager()->installTimerProc(timerProc, 10 * 1000, this, "AudioCDStream");
}
void AudioCDStream::stopTimer() {
forceStop();
g_system->getTimerManager()->removeTimerProc(timerProc);
}
void AudioCDStream::emptyQueue() {
while (!_bufferQueue.empty())
delete[] _bufferQueue.pop();
}
bool AudioCDStream::shouldForceStop() const {
Common::StackLock lock(_forceStopMutex);
return _forceStop;
}
void AudioCDStream::forceStop() {
Common::StackLock lock(_forceStopMutex);
_forceStop = true;
}

View file

@ -0,0 +1,108 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_AUDIOCD_AUDIOCD_STREAM_H
#define BACKENDS_AUDIOCD_AUDIOCD_STREAM_H
#include "audio/audiostream.h"
#include "common/mutex.h"
#include "common/queue.h"
#include "common/timer.h"
class AudioCDStream : public Audio::SeekableAudioStream {
public:
AudioCDStream();
~AudioCDStream();
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return true; }
int getRate() const { return 44100; }
bool endOfData() const;
bool seek(const Audio::Timestamp &where);
Audio::Timestamp getLength() const;
protected:
virtual uint getStartFrame() const = 0;
virtual uint getEndFrame() const = 0;
virtual bool readFrame(int frame, int16 *buffer) = 0;
void startTimer(bool fillBuffer = false);
void stopTimer();
enum {
kBytesPerFrame = 2352,
kSamplesPerFrame = kBytesPerFrame / 2
};
enum {
kSecondsPerMinute = 60,
kFramesPerSecond = 75
};
enum {
// Keep about a second's worth of audio in the buffer
kBufferThreshold = kFramesPerSecond
};
private:
int16 _buffer[kSamplesPerFrame];
int _frame;
uint _bufferPos;
Common::Queue<int16 *> _bufferQueue;
int _bufferFrame;
Common::Mutex _mutex;
bool _forceStop;
bool shouldForceStop() const;
void forceStop();
Common::Mutex _forceStopMutex;
bool readNextFrame();
static void timerProc(void *refCon);
void onTimer();
void emptyQueue();
};
#endif

View file

@ -48,26 +48,31 @@ public:
}; };
/** /**
* @name Emulated playback functions * Initialize the specified CD drive for audio playback.
* Engines should call these functions. Not all platforms * @return true if the CD drive was inited successfully
* support cd playback, and these functions should try to
* emulate it.
*/ */
//@{ virtual bool open() = 0;
/**
* Close the currently open CD drive
*/
virtual void close() = 0;
/** /**
* Start audio CD playback * Start audio CD playback
* @param track the track to play. * @param track the track to play.
* @param numLoops how often playback should be repeated (-1 = infinitely often). * @param numLoops how often playback should be repeated (<=0 means infinitely often).
* @param startFrame the frame at which playback should start (75 frames = 1 second). * @param startFrame the frame at which playback should start (75 frames = 1 second).
* @param duration the number of frames to play. * @param duration the number of frames to play.
* @param only_emulate determines if the track should be emulated only * @param onlyEmulate determines if the track should be emulated only
* @note The @c onlyEmulate parameter is deprecated.
* @return @c true if the track started playing, @c false otherwise
*/ */
virtual void play(int track, int numLoops, int startFrame, int duration, bool only_emulate = false) = 0; virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false) = 0;
/** /**
* Get if audio is being played. * Get if audio is being played.
* @return true if CD or emulated audio is playing * @return true if CD audio is playing
*/ */
virtual bool isPlaying() const = 0; virtual bool isPlaying() const = 0;
@ -82,12 +87,12 @@ public:
virtual void setBalance(int8 balance) = 0; virtual void setBalance(int8 balance) = 0;
/** /**
* Stop CD or emulated audio playback. * Stop audio playback.
*/ */
virtual void stop() = 0; virtual void stop() = 0;
/** /**
* Update CD or emulated audio status. * Update audio status.
*/ */
virtual void update() = 0; virtual void update() = 0;
@ -96,50 +101,6 @@ public:
* @return a Status struct with playback data. * @return a Status struct with playback data.
*/ */
virtual Status getStatus() const = 0; virtual Status getStatus() const = 0;
//@}
/**
* @name Real CD audio methods
* These functions should be called from the emulated
* ones if they can't emulate the audio playback.
*/
//@{
/**
* Initialize the specified CD drive for audio playback.
* @param drive the drive id
* @return true if the CD drive was inited successfully
*/
virtual bool openCD(int drive) = 0;
/**
* Poll CD status.
* @return true if CD audio is playing
*/
virtual bool pollCD() const = 0;
/**
* Start CD audio playback.
* @param track the track to play.
* @param num_loops how often playback should be repeated (-1 = infinitely often).
* @param start_frame the frame at which playback should start (75 frames = 1 second).
* @param duration the number of frames to play.
*/
virtual void playCD(int track, int num_loops, int start_frame, int duration) = 0;
/**
* Stop CD audio playback.
*/
virtual void stopCD() = 0;
/**
* Update CD audio status.
*/
virtual void updateCD() = 0;
//@}
}; };
#endif #endif

View file

@ -22,6 +22,7 @@
#include "backends/audiocd/default/default-audiocd.h" #include "backends/audiocd/default/default-audiocd.h"
#include "audio/audiostream.h" #include "audio/audiostream.h"
#include "common/config-manager.h"
#include "common/system.h" #include "common/system.h"
DefaultAudioCDManager::DefaultAudioCDManager() { DefaultAudioCDManager::DefaultAudioCDManager() {
@ -37,7 +38,25 @@ DefaultAudioCDManager::DefaultAudioCDManager() {
assert(_mixer); assert(_mixer);
} }
void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool only_emulate) { DefaultAudioCDManager::~DefaultAudioCDManager() {
// Subclasses should call close as well
close();
}
bool DefaultAudioCDManager::open() {
// For emulation, opening is always valid
close();
return true;
}
void DefaultAudioCDManager::close() {
// Only need to stop for emulation
stop();
}
bool DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
stop();
if (numLoops != 0 || startFrame != 0) { if (numLoops != 0 || startFrame != 0) {
_cd.track = track; _cd.track = track;
_cd.numLoops = numLoops; _cd.numLoops = numLoops;
@ -55,9 +74,6 @@ void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int du
for (int i = 0; !stream && i < 2; ++i) for (int i = 0; !stream && i < 2; ++i)
stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]); stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]);
// Stop any currently playing emulated track
_mixer->stopHandle(_handle);
if (stream != 0) { if (stream != 0) {
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75); Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : stream->getLength(); Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : stream->getLength();
@ -70,12 +86,11 @@ void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int du
_emulating = true; _emulating = true;
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle, _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance); Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
} else { return true;
_emulating = false;
if (!only_emulate)
playCD(track, numLoops, startFrame, duration);
} }
} }
return false;
} }
void DefaultAudioCDManager::stop() { void DefaultAudioCDManager::stop() {
@ -83,52 +98,32 @@ void DefaultAudioCDManager::stop() {
// Audio CD emulation // Audio CD emulation
_mixer->stopHandle(_handle); _mixer->stopHandle(_handle);
_emulating = false; _emulating = false;
} else {
// Real Audio CD
stopCD();
} }
} }
bool DefaultAudioCDManager::isPlaying() const { bool DefaultAudioCDManager::isPlaying() const {
if (_emulating) { // Audio CD emulation
// Audio CD emulation if (_emulating)
return _mixer->isSoundHandleActive(_handle); return _mixer->isSoundHandleActive(_handle);
} else {
// Real Audio CD // The default class only handles emulation
return pollCD(); return false;
}
} }
void DefaultAudioCDManager::setVolume(byte volume) { void DefaultAudioCDManager::setVolume(byte volume) {
_cd.volume = volume; _cd.volume = volume;
if (_emulating) {
// Audio CD emulation
if (_mixer->isSoundHandleActive(_handle))
_mixer->setChannelVolume(_handle, _cd.volume);
} else {
// Real Audio CD
// Unfortunately I can't implement this atm // Audio CD emulation
// since SDL doesn't seem to offer an interface method for this. if (_emulating && isPlaying())
_mixer->setChannelVolume(_handle, _cd.volume);
// g_system->setVolumeCD(_cd.volume);
}
} }
void DefaultAudioCDManager::setBalance(int8 balance) { void DefaultAudioCDManager::setBalance(int8 balance) {
_cd.balance = balance; _cd.balance = balance;
if (_emulating) {
// Audio CD emulation
if (isPlaying())
_mixer->setChannelBalance(_handle, _cd.balance);
} else {
// Real Audio CD
// Unfortunately I can't implement this atm // Audio CD emulation
// since SDL doesn't seem to offer an interface method for this. if (_emulating && isPlaying())
_mixer->setChannelBalance(_handle, _cd.balance);
// g_system->setBalanceCD(_cd.balance);
}
} }
void DefaultAudioCDManager::update() { void DefaultAudioCDManager::update() {
@ -142,8 +137,6 @@ void DefaultAudioCDManager::update() {
// or not. // or not.
_emulating = false; _emulating = false;
} }
} else {
updateCD();
} }
} }
@ -152,3 +145,21 @@ DefaultAudioCDManager::Status DefaultAudioCDManager::getStatus() const {
info.playing = isPlaying(); info.playing = isPlaying();
return info; return info;
} }
bool DefaultAudioCDManager::openRealCD() {
Common::String cdrom = ConfMan.get("cdrom");
// Try to parse it as an int
char *endPos;
int drive = strtol(cdrom.c_str(), &endPos, 0);
// If not an integer, treat as a drive path
if (endPos == cdrom.c_str())
return openCD(cdrom);
if (drive < 0)
return false;
return openCD(drive);
}

View file

@ -26,29 +26,48 @@
#include "backends/audiocd/audiocd.h" #include "backends/audiocd/audiocd.h"
#include "audio/mixer.h" #include "audio/mixer.h"
namespace Common {
class String;
} // End of namespace Common
/** /**
* The default audio cd manager. Implements emulation of audio cd playback. * The default audio cd manager. Implements emulation of audio cd playback.
*/ */
class DefaultAudioCDManager : public AudioCDManager { class DefaultAudioCDManager : public AudioCDManager {
public: public:
DefaultAudioCDManager(); DefaultAudioCDManager();
virtual ~DefaultAudioCDManager() {} virtual ~DefaultAudioCDManager();
void play(int track, int numLoops, int startFrame, int duration, bool only_emulate = false); virtual bool open();
void stop(); virtual void close();
bool isPlaying() const; virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
void setVolume(byte volume); virtual void stop();
void setBalance(int8 balance); virtual bool isPlaying() const;
void update(); virtual void setVolume(byte volume);
virtual void setBalance(int8 balance);
virtual void update();
virtual Status getStatus() const; // Subclasses should override for better status results virtual Status getStatus() const; // Subclasses should override for better status results
virtual bool openCD(int drive) { return false; }
virtual void updateCD() {}
virtual bool pollCD() const { return false; }
virtual void playCD(int track, int num_loops, int start_frame, int duration) {}
virtual void stopCD() {}
protected: protected:
/**
* Open a CD using the cdrom config variable
*/
bool openRealCD();
/**
* Open a CD using the specified drive index
* @param drive The index of the drive
* @note The index is implementation-defined, but 0 is always the best choice
*/
virtual bool openCD(int drive) { return false; }
/**
* Open a CD from a specific drive
* @param drive The name of the drive/path
* @note The drive parameter is platform-specific
*/
virtual bool openCD(const Common::String &drive) { return false; }
Audio::SoundHandle _handle; Audio::SoundHandle _handle;
bool _emulating; bool _emulating;

View file

@ -0,0 +1,471 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
// Enable all forbidden symbols to allow us to include and use necessary APIs.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "backends/audiocd/linux/linux-audiocd.h"
#ifdef USE_LINUXCD
#include "backends/audiocd/audiocd-stream.h"
#include "backends/audiocd/default/default-audiocd.h"
#include "common/array.h"
#include "common/config-manager.h"
#include "common/str.h"
#include "common/debug.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
enum {
kLeadoutTrack = 0xAA
};
enum {
kBytesPerFrame = 2352,
kSamplesPerFrame = kBytesPerFrame / 2
};
enum {
kSecondsPerMinute = 60,
kFramesPerSecond = 75
};
enum {
// Keep about a second's worth of audio in the buffer
kBufferThreshold = kFramesPerSecond
};
static int getFrameCount(const cdrom_msf0 &msf) {
int time = msf.minute;
time *= kSecondsPerMinute;
time += msf.second;
time *= kFramesPerSecond;
time += msf.frame;
return time;
}
// Helper function to convert an error code into a human-readable message
static Common::String getErrorMessage(int errorCode) {
char buf[256];
buf[0] = 0;
#ifdef _GNU_SOURCE
// glibc sucks
return Common::String(strerror_r(errorCode, buf, sizeof(buf)));
#else
strerror_r(errorCode, buf, sizeof(buf));
return Common::String(buf);
#endif
}
class LinuxAudioCDStream : public AudioCDStream {
public:
LinuxAudioCDStream(int fd, const cdrom_tocentry &startEntry, const cdrom_tocentry &endEntry);
~LinuxAudioCDStream();
protected:
uint getStartFrame() const;
uint getEndFrame() const;
bool readFrame(int frame, int16 *buffer);
private:
int _fd;
const cdrom_tocentry &_startEntry, &_endEntry;
};
LinuxAudioCDStream::LinuxAudioCDStream(int fd, const cdrom_tocentry &startEntry, const cdrom_tocentry &endEntry) :
_fd(fd), _startEntry(startEntry), _endEntry(endEntry) {
// We fill the buffer here already to prevent any out of sync issues due
// to the CD not yet having spun up.
startTimer(true);
}
LinuxAudioCDStream::~LinuxAudioCDStream() {
stopTimer();
}
bool LinuxAudioCDStream::readFrame(int frame, int16 *buffer) {
// Create the argument
union {
cdrom_msf msf;
char buffer[kBytesPerFrame];
} arg;
int seconds = frame / kFramesPerSecond;
frame %= kFramesPerSecond;
int minutes = seconds / kSecondsPerMinute;
seconds %= kSecondsPerMinute;
// Request to read that frame
// We don't use CDROMREADAUDIO, as it seems to cause kernel
// panics on ejecting discs. Probably bad to eject the disc
// while playing, but at least let's try to prevent that case.
arg.msf.cdmsf_min0 = minutes;
arg.msf.cdmsf_sec0 = seconds;
arg.msf.cdmsf_frame0 = frame;
// The "end" part is irrelevant (why isn't cdrom_msf0 the type
// instead?)
if (ioctl(_fd, CDROMREADRAW, &arg) < 0) {
warning("Failed to CD read audio: %s", getErrorMessage(errno).c_str());
return false;
}
memcpy(buffer, arg.buffer, kBytesPerFrame);
return true;
}
uint LinuxAudioCDStream::getStartFrame() const {
return getFrameCount(_startEntry.cdte_addr.msf);
}
uint LinuxAudioCDStream::getEndFrame() const {
return getFrameCount(_endEntry.cdte_addr.msf);
}
class LinuxAudioCDManager : public DefaultAudioCDManager {
public:
LinuxAudioCDManager();
~LinuxAudioCDManager();
bool open();
void close();
bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
protected:
bool openCD(int drive);
bool openCD(const Common::String &drive);
private:
struct Device {
Device(const Common::String &n, dev_t d) : name(n), device(d) {}
Common::String name;
dev_t device;
};
typedef Common::Array<Device> DeviceList;
DeviceList scanDevices();
bool tryAddDrive(DeviceList &devices, const Common::String &drive);
bool tryAddDrive(DeviceList &devices, const Common::String &drive, dev_t device);
bool tryAddDrive(DeviceList &devices, dev_t device);
bool tryAddPath(DeviceList &devices, const Common::String &path);
bool tryAddGamePath(DeviceList &devices);
bool loadTOC();
static bool hasDevice(const DeviceList &devices, dev_t device);
int _fd;
cdrom_tochdr _tocHeader;
Common::Array<cdrom_tocentry> _tocEntries;
};
static bool isTrayEmpty(int errorNumber) {
switch (errorNumber) {
case EIO:
case ENOENT:
case EINVAL:
#ifdef ENOMEDIUM
case ENOMEDIUM:
#endif
return true;
}
return false;
}
LinuxAudioCDManager::LinuxAudioCDManager() {
_fd = -1;
memset(&_tocHeader, 0, sizeof(_tocHeader));
}
LinuxAudioCDManager::~LinuxAudioCDManager() {
close();
}
bool LinuxAudioCDManager::open() {
close();
if (openRealCD())
return true;
return DefaultAudioCDManager::open();
}
void LinuxAudioCDManager::close() {
DefaultAudioCDManager::close();
if (_fd < 0)
return;
::close(_fd);
memset(&_tocHeader, 0, sizeof(_tocHeader));
_tocEntries.clear();
}
bool LinuxAudioCDManager::openCD(int drive) {
DeviceList devices = scanDevices();
if (drive >= (int)devices.size())
return false;
_fd = ::open(devices[drive].name.c_str(), O_RDONLY | O_NONBLOCK, 0);
if (_fd < 0)
return false;
if (!loadTOC()) {
close();
return false;
}
return true;
}
bool LinuxAudioCDManager::openCD(const Common::String &drive) {
DeviceList devices;
if (!tryAddDrive(devices, drive) && !tryAddPath(devices, drive))
return false;
_fd = ::open(devices[0].name.c_str(), O_RDONLY | O_NONBLOCK, 0);
if (_fd < 0)
return false;
if (!loadTOC()) {
close();
return false;
}
return true;
}
bool LinuxAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
// Prefer emulation
if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
return true;
// If we're set to only emulate, or have no CD drive, return here
if (onlyEmulate || _fd < 0)
return false;
// HACK: For now, just assume that track number is right
// That only works because ScummVM uses the wrong track number anyway
if (track >= (int)_tocEntries.size() - 1) {
warning("No such track %d", track);
return false;
}
// Bail if the track isn't an audio track
if ((_tocEntries[track].cdte_ctrl & 0x04) != 0) {
warning("Track %d is not audio", track);
return false;
}
// Create the AudioStream and play it
debug(1, "Playing CD track %d", track);
Audio::SeekableAudioStream *audioStream = new LinuxAudioCDStream(_fd, _tocEntries[track], _tocEntries[track + 1]);
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
Audio::Timestamp end = (duration == 0) ? audioStream->getLength() : Audio::Timestamp(0, startFrame + duration, 75);
// Fake emulation since we're really playing an AudioStream
_emulating = true;
_mixer->playStream(
Audio::Mixer::kMusicSoundType,
&_handle,
Audio::makeLoopingAudioStream(audioStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops),
-1,
_cd.volume,
_cd.balance,
DisposeAfterUse::YES,
true);
return true;
}
LinuxAudioCDManager::DeviceList LinuxAudioCDManager::scanDevices() {
DeviceList devices;
// Try to use the game's path first as the device
tryAddGamePath(devices);
// Try adding the default CD-ROM
tryAddDrive(devices, "/dev/cdrom");
// TODO: Try others?
return devices;
}
bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, const Common::String &drive) {
struct stat stbuf;
if (stat(drive.c_str(), &stbuf) < 0)
return false;
// Must be a character or block device
if (!S_ISCHR(stbuf.st_mode) && !S_ISBLK(stbuf.st_mode))
return false;
return tryAddDrive(devices, drive, stbuf.st_rdev);
}
bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, const Common::String &drive, dev_t device) {
if (hasDevice(devices, device))
return true;
// Try opening the device and seeing if it is a CD-ROM drve
int fd = ::open(drive.c_str(), O_RDONLY | O_NONBLOCK, 0);
if (fd >= 0) {
cdrom_subchnl info;
info.cdsc_format = CDROM_MSF;
bool isCD = ioctl(fd, CDROMSUBCHNL, &info) == 0 || isTrayEmpty(errno);
::close(fd);
if (isCD) {
devices.push_back(Device(drive, device));
return true;
}
}
return false;
}
bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, dev_t device) {
// Construct the block name
// TODO: libblkid's blkid_devno_to_devname is exactly what we look for.
// This requires an external dependency though.
Common::String name = Common::String::format("/dev/block/%d:%d", major(device), minor(device));
return tryAddDrive(devices, name, device);
}
bool LinuxAudioCDManager::tryAddPath(DeviceList &devices, const Common::String &path) {
struct stat stbuf;
if (stat(path.c_str(), &stbuf) < 0)
return false;
return tryAddDrive(devices, stbuf.st_dev);
}
bool LinuxAudioCDManager::tryAddGamePath(DeviceList &devices) {
if (!ConfMan.hasKey("path"))
return false;
return tryAddPath(devices, ConfMan.get("path"));
}
bool LinuxAudioCDManager::loadTOC() {
if (_fd < 0)
return false;
if (ioctl(_fd, CDROMREADTOCHDR, &_tocHeader) < 0)
return false;
debug(4, "CD: Start Track: %d, End Track %d", _tocHeader.cdth_trk0, _tocHeader.cdth_trk1);
for (int i = _tocHeader.cdth_trk0; i <= _tocHeader.cdth_trk1; i++) {
cdrom_tocentry entry;
memset(&entry, 0, sizeof(entry));
entry.cdte_track = i;
entry.cdte_format = CDROM_MSF;
if (ioctl(_fd, CDROMREADTOCENTRY, &entry) < 0)
return false;
#if 0
debug("Entry:");
debug("\tTrack: %d", entry.cdte_track);
debug("\tAdr: %d", entry.cdte_adr);
debug("\tCtrl: %d", entry.cdte_ctrl);
debug("\tFormat: %d", entry.cdte_format);
debug("\tMSF: %d:%d:%d", entry.cdte_addr.msf.minute, entry.cdte_addr.msf.second, entry.cdte_addr.msf.frame);
debug("\tMode: %d\n", entry.cdte_datamode);
#endif
_tocEntries.push_back(entry);
}
// Fetch the leadout so we can get the length of the last frame
cdrom_tocentry entry;
memset(&entry, 0, sizeof(entry));
entry.cdte_track = kLeadoutTrack;
entry.cdte_format = CDROM_MSF;
if (ioctl(_fd, CDROMREADTOCENTRY, &entry) < 0)
return false;
#if 0
debug("Lead out:");
debug("\tTrack: %d", entry.cdte_track);
debug("\tAdr: %d", entry.cdte_adr);
debug("\tCtrl: %d", entry.cdte_ctrl);
debug("\tFormat: %d", entry.cdte_format);
debug("\tMSF: %d:%d:%d", entry.cdte_addr.msf.minute, entry.cdte_addr.msf.second, entry.cdte_addr.msf.frame);
debug("\tMode: %d\n", entry.cdte_datamode);
#endif
_tocEntries.push_back(entry);
return true;
}
bool LinuxAudioCDManager::hasDevice(const DeviceList &devices, dev_t device) {
for (DeviceList::const_iterator it = devices.begin(); it != devices.end(); it++)
if (it->device == device)
return true;
return false;
}
AudioCDManager *createLinuxAudioCDManager() {
return new LinuxAudioCDManager();
}
#endif // USE_LINUXCD

View file

@ -0,0 +1,62 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_AUDIOCD_LINUX_H
#define BACKENDS_AUDIOCD_LINUX_H
#include "common/scummsys.h"
#ifdef USE_LINUXCD
class AudioCDManager;
/**
* Create an audio CD manager using the Linux CDROM API
*/
AudioCDManager *createLinuxAudioCDManager();
#endif
#endif

View file

@ -0,0 +1,306 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifdef MACOSX
#include <sys/stat.h>
#include <sys/mount.h>
#include <limits.h>
#include "common/scummsys.h"
#include "audio/audiostream.h"
#include "audio/decoders/aiff.h"
#include "audio/timestamp.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/fs.h"
#include "common/hashmap.h"
#include "common/textconsole.h"
#include "backends/audiocd/default/default-audiocd.h"
#include "backends/audiocd/macosx/macosx-audiocd.h"
#include "backends/fs/stdiostream.h"
// Partially based on SDL's code
/**
* The Mac OS X audio cd manager. Implements real audio cd playback.
*/
class MacOSXAudioCDManager : public DefaultAudioCDManager {
public:
MacOSXAudioCDManager() {}
~MacOSXAudioCDManager();
bool open();
void close();
bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
protected:
bool openCD(int drive);
bool openCD(const Common::String &drive);
private:
struct Drive {
Drive(const Common::String &m, const Common::String &d, const Common::String &f) :
mountPoint(m), deviceName(d), fsType(f) {}
Common::String mountPoint;
Common::String deviceName;
Common::String fsType;
};
typedef Common::Array<Drive> DriveList;
DriveList detectAllDrives();
DriveList detectCDDADrives();
bool findTrackNames(const Common::String &drivePath);
Common::HashMap<uint, Common::String> _trackMap;
};
MacOSXAudioCDManager::~MacOSXAudioCDManager() {
close();
}
bool MacOSXAudioCDManager::open() {
close();
if (openRealCD())
return true;
return DefaultAudioCDManager::open();
}
/**
* Find the base disk number of device name.
* Returns -1 if mount point is not /dev/disk*
*/
static int findBaseDiskNumber(const Common::String &diskName) {
if (!diskName.hasPrefix("/dev/disk"))
return -1;
const char *startPtr = diskName.c_str() + 9;
char *endPtr;
int baseDiskNumber = strtol(startPtr, &endPtr, 10);
if (startPtr == endPtr)
return -1;
return baseDiskNumber;
}
bool MacOSXAudioCDManager::openCD(int drive) {
DriveList allDrives = detectAllDrives();
if (allDrives.empty())
return false;
DriveList cddaDrives;
// Try to get the volume related to the game's path
if (ConfMan.hasKey("path")) {
Common::String gamePath = ConfMan.get("path");
struct statfs gamePathStat;
if (statfs(gamePath.c_str(), &gamePathStat) == 0) {
int baseDiskNumber = findBaseDiskNumber(gamePathStat.f_mntfromname);
if (baseDiskNumber >= 0) {
// Look for a CDDA drive with the same base disk number
for (uint32 i = 0; i < allDrives.size(); i++) {
if (allDrives[i].fsType == "cddafs" && findBaseDiskNumber(allDrives[i].deviceName) == baseDiskNumber) {
debug(1, "Preferring drive '%s'", allDrives[i].mountPoint.c_str());
cddaDrives.push_back(allDrives[i]);
allDrives.remove_at(i);
break;
}
}
}
}
}
// Add the remaining CDDA drives to the CDDA list
for (uint32 i = 0; i < allDrives.size(); i++)
if (allDrives[i].fsType == "cddafs")
cddaDrives.push_back(allDrives[i]);
if (drive >= (int)cddaDrives.size())
return false;
debug(1, "Using '%s' as the CD drive", cddaDrives[drive].mountPoint.c_str());
return findTrackNames(cddaDrives[drive].mountPoint);
}
bool MacOSXAudioCDManager::openCD(const Common::String &drive) {
DriveList drives = detectAllDrives();
for (uint32 i = 0; i < drives.size(); i++) {
if (drives[i].fsType != "cddafs")
continue;
if (drives[i].mountPoint == drive || drives[i].deviceName == drive) {
debug(1, "Using '%s' as the CD drive", drives[i].mountPoint.c_str());
return findTrackNames(drives[i].mountPoint);
}
}
return false;
}
void MacOSXAudioCDManager::close() {
DefaultAudioCDManager::close();
_trackMap.clear();
}
enum {
// Some crazy high number that we'll never actually hit
kMaxDriveCount = 256
};
MacOSXAudioCDManager::DriveList MacOSXAudioCDManager::detectAllDrives() {
// Fetch the lists of drives
struct statfs driveStats[kMaxDriveCount];
int foundDrives = getfsstat(driveStats, sizeof(driveStats), MNT_WAIT);
if (foundDrives <= 0)
return DriveList();
DriveList drives;
for (int i = 0; i < foundDrives; i++)
drives.push_back(Drive(driveStats[i].f_mntonname, driveStats[i].f_mntfromname, driveStats[i].f_fstypename));
return drives;
}
bool MacOSXAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
// Prefer emulation
if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
return true;
// If we're set to only emulate, or have no CD drive, return here
if (onlyEmulate || !_trackMap.contains(track))
return false;
if (!numLoops && !startFrame)
return false;
// Now load the AIFF track from the name
Common::String fileName = _trackMap[track];
Common::SeekableReadStream *stream = StdioStream::makeFromPath(fileName.c_str(), false);
if (!stream) {
warning("Failed to open track '%s'", fileName.c_str());
return false;
}
Audio::AudioStream *audioStream = Audio::makeAIFFStream(stream, DisposeAfterUse::YES);
if (!audioStream) {
warning("Track '%s' is not an AIFF track", fileName.c_str());
return false;
}
Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(audioStream);
if (!seekStream) {
warning("Track '%s' is not seekable", fileName.c_str());
return false;
}
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : seekStream->getLength();
// Fake emulation since we're really playing an AIFF file
_emulating = true;
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
Audio::makeLoopingAudioStream(seekStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
return true;
}
bool MacOSXAudioCDManager::findTrackNames(const Common::String &drivePath) {
Common::FSNode directory(drivePath);
if (!directory.exists()) {
warning("Directory '%s' does not exist", drivePath.c_str());
return false;
}
if (!directory.isDirectory()) {
warning("'%s' is not a directory", drivePath.c_str());
return false;
}
Common::FSList children;
if (!directory.getChildren(children, Common::FSNode::kListFilesOnly)) {
warning("Failed to find children for '%s'", drivePath.c_str());
return false;
}
for (uint32 i = 0; i < children.size(); i++) {
if (!children[i].isDirectory()) {
Common::String fileName = children[i].getName();
if (fileName.hasSuffix(".aiff") || fileName.hasSuffix(".cdda")) {
uint j = 0;
// Search for the track ID in the file name.
for (; j < fileName.size() && !Common::isDigit(fileName[j]); j++)
;
const char *trackIDString = fileName.c_str() + j;
char *endPtr = nullptr;
long trackID = strtol(trackIDString, &endPtr, 10);
if (trackIDString != endPtr && trackID > 0 && trackID < UINT_MAX) {
_trackMap[trackID - 1] = drivePath + '/' + fileName;
} else {
warning("Invalid track file name: '%s'", fileName.c_str());
}
}
}
}
return true;
}
AudioCDManager *createMacOSXAudioCDManager() {
return new MacOSXAudioCDManager();
}
#endif // MACOSX

View file

@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_AUDIOCD_MACOSX_H
#define BACKENDS_AUDIOCD_MACOSX_H
#include "common/scummsys.h"
#ifdef MACOSX
class AudioCDManager;
/**
* Create an audio CD manager for Mac OS X
*/
AudioCDManager *createMacOSXAudioCDManager();
#endif
#endif //

View file

@ -43,10 +43,16 @@ SdlAudioCDManager::SdlAudioCDManager()
} }
SdlAudioCDManager::~SdlAudioCDManager() { SdlAudioCDManager::~SdlAudioCDManager() {
if (_cdrom) { close();
SDL_CDStop(_cdrom); }
SDL_CDClose(_cdrom);
} bool SdlAudioCDManager::open() {
close();
if (openRealCD())
return true;
return DefaultAudioCDManager::open();
} }
bool SdlAudioCDManager::openCD(int drive) { bool SdlAudioCDManager::openCD(int drive) {
@ -67,44 +73,69 @@ bool SdlAudioCDManager::openCD(int drive) {
return (_cdrom != NULL); return (_cdrom != NULL);
} }
void SdlAudioCDManager::stopCD() { void SdlAudioCDManager::close() {
DefaultAudioCDManager::close();
if (_cdrom) {
SDL_CDStop(_cdrom);
SDL_CDClose(_cdrom);
_cdrom = 0;
}
}
void SdlAudioCDManager::stop() {
DefaultAudioCDManager::stop();
// Stop CD Audio in 1/10th of a second // Stop CD Audio in 1/10th of a second
_cdStopTime = SDL_GetTicks() + 100; _cdStopTime = SDL_GetTicks() + 100;
_cdNumLoops = 0; _cdNumLoops = 0;
} }
void SdlAudioCDManager::playCD(int track, int num_loops, int start_frame, int duration) { bool SdlAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
if (!num_loops && !start_frame) // Prefer emulation
return; if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
return true;
if (!_cdrom) // If we're set to only emulate, or have no CD, return here
return; if (onlyEmulate || !_cdrom)
return false;
if (!numLoops && !startFrame)
return false;
// FIXME: Explain this.
if (duration > 0) if (duration > 0)
duration += 5; duration += 5;
_cdTrack = track; _cdTrack = track;
_cdNumLoops = num_loops; _cdNumLoops = numLoops;
_cdStartFrame = start_frame; _cdStartFrame = startFrame;
SDL_CDStatus(_cdrom); SDL_CDStatus(_cdrom);
if (start_frame == 0 && duration == 0) if (startFrame == 0 && duration == 0)
SDL_CDPlayTracks(_cdrom, track, 0, 1, 0); SDL_CDPlayTracks(_cdrom, track, 0, 1, 0);
else else
SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration); SDL_CDPlayTracks(_cdrom, track, startFrame, 0, duration);
_cdDuration = duration; _cdDuration = duration;
_cdStopTime = 0; _cdStopTime = 0;
_cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS; _cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS;
return true;
} }
bool SdlAudioCDManager::pollCD() const { bool SdlAudioCDManager::isPlaying() const {
if (DefaultAudioCDManager::isPlaying())
return true;
if (!_cdrom) if (!_cdrom)
return false; return false;
return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) == CD_PLAYING)); return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) == CD_PLAYING));
} }
void SdlAudioCDManager::updateCD() { void SdlAudioCDManager::update() {
DefaultAudioCDManager::update();
if (!_cdrom) if (!_cdrom)
return; return;

View file

@ -37,12 +37,15 @@ public:
SdlAudioCDManager(); SdlAudioCDManager();
virtual ~SdlAudioCDManager(); virtual ~SdlAudioCDManager();
virtual bool open();
virtual void close();
virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
virtual void stop();
virtual bool isPlaying() const;
virtual void update();
protected: protected:
virtual bool openCD(int drive); virtual bool openCD(int drive);
virtual void updateCD();
virtual bool pollCD() const;
virtual void playCD(int track, int num_loops, int start_frame, int duration);
virtual void stopCD();
SDL_CD *_cdrom; SDL_CD *_cdrom;
int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration; int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;

View file

@ -0,0 +1,362 @@
/**
* @file ntddcdrm.h
* Copyright 2012, 2013 MinGW.org project
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* Created by Casper S. Hornstrup <chorns@users.sourceforge.net> */
#ifndef __NTDDCDRM_H
#define __NTDDCDRM_H
#if 0 // Added to make MSVC happy.
#pragma GCC system_header
#include <_mingw.h>
#endif
/*
* CDROM IOCTL interface.
*/
#ifdef __cplusplus
extern "C" {
#endif
#if 0 // Added to make MSVC happy.
#include "ntddk.h"
#include "ntddstor.h"
#endif
#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
#define IOCTL_CDROM_CHECK_VERIFY \
CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_FIND_NEW_DEVICES \
CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_GET_CONTROL \
CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \
CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_GET_LAST_SESSION \
CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_GET_VOLUME \
CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_PAUSE_AUDIO \
CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_PLAY_AUDIO_MSF \
CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_RAW_READ \
CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
#define IOCTL_CDROM_READ_Q_CHANNEL \
CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_READ_TOC \
CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_READ_TOC_EX \
CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_RESUME_AUDIO \
CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_SEEK_AUDIO_MSF \
CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_SET_VOLUME \
CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_SIMBAD \
CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_CDROM_STOP_AUDIO \
CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
#define MAXIMUM_NUMBER_TRACKS 100
#define MAXIMUM_CDROM_SIZE 804
#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2
typedef struct _TRACK_DATA {
UCHAR Reserved;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TrackNumber;
UCHAR Reserved1;
UCHAR Address[4];
} TRACK_DATA, *PTRACK_DATA;
/* CDROM_DISK_DATA.DiskData flags */
#define CDROM_DISK_AUDIO_TRACK 0x00000001
#define CDROM_DISK_DATA_TRACK 0x00000002
typedef struct _CDROM_DISK_DATA {
ULONG DiskData;
} CDROM_DISK_DATA, *PCDROM_DISK_DATA;
typedef struct _CDROM_PLAY_AUDIO_MSF {
UCHAR StartingM;
UCHAR StartingS;
UCHAR StartingF;
UCHAR EndingM;
UCHAR EndingS;
UCHAR EndingF;
} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;
/* CDROM_READ_TOC_EX.Format constants */
#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00
#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01
#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02
#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03
#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04
#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05
typedef struct _CDROM_READ_TOC_EX {
UCHAR Format : 4;
UCHAR Reserved1 : 3;
UCHAR Msf : 1;
UCHAR SessionTrack;
UCHAR Reserved2;
UCHAR Reserved3;
} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
typedef struct _CDROM_SEEK_AUDIO_MSF {
UCHAR M;
UCHAR S;
UCHAR F;
} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;
/* CDROM_SUB_Q_DATA_FORMAT.Format constants */
#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00
#define IOCTL_CDROM_CURRENT_POSITION 0x01
#define IOCTL_CDROM_MEDIA_CATALOG 0x02
#define IOCTL_CDROM_TRACK_ISRC 0x03
typedef struct _CDROM_SUB_Q_DATA_FORMAT {
UCHAR Format;
UCHAR Track;
} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
typedef struct _CDROM_TOC {
UCHAR Length[2];
UCHAR FirstTrack;
UCHAR LastTrack;
TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
} CDROM_TOC, *PCDROM_TOC;
#define CDROM_TOC_SIZE sizeof(CDROM_TOC)
typedef struct _CDROM_TOC_ATIP_DATA_BLOCK {
UCHAR CdrwReferenceSpeed : 3;
UCHAR Reserved3 : 1;
UCHAR WritePower : 3;
UCHAR True1 : 1;
UCHAR Reserved4 : 6;
UCHAR UnrestrictedUse : 1;
UCHAR Reserved5 : 1;
UCHAR A3Valid : 1;
UCHAR A2Valid : 1;
UCHAR A1Valid : 1;
UCHAR Reserved6 : 3;
UCHAR IsCdrw : 1;
UCHAR True2 : 1;
UCHAR Reserved7;
UCHAR LeadInMsf[3];
UCHAR Reserved8;
UCHAR LeadOutMsf[3];
UCHAR Reserved9;
UCHAR A1Values[3];
UCHAR Reserved10;
UCHAR A2Values[3];
UCHAR Reserved11;
UCHAR A3Values[3];
UCHAR Reserved12;
} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK;
#if 0 // Added to make MSVC happy.
typedef struct _CDROM_TOC_ATIP_DATA {
UCHAR Length[2];
UCHAR Reserved1;
UCHAR Reserved2;
CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0];
CDROM_TOC_ATIP_DATA_BLOCK Descriptors[1];
} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA;
#endif
/* CDROM_TOC_CD_TEXT_DATA_BLOCK.PackType constants */
#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80
#define CDROM_CD_TEXT_PACK_PERFORMER 0x81
#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82
#define CDROM_CD_TEXT_PACK_COMPOSER 0x83
#define CDROM_CD_TEXT_PACK_ARRANGER 0x84
#define CDROM_CD_TEXT_PACK_MESSAGES 0x85
#define CDROM_CD_TEXT_PACK_DISC_ID 0x86
#define CDROM_CD_TEXT_PACK_GENRE 0x87
#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88
#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89
#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e
#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f
#if 0 // Added to make MSVC happy.
typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {
UCHAR PackType;
UCHAR TrackNumber : 7;
UCHAR ExtensionFlag : 1;
UCHAR SequenceNumber;
UCHAR CharacterPosition : 4;
UCHAR BlockNumber : 3;
UCHAR Unicode : 1;
_ANONYMOUS_UNION union {
UCHAR Text[12];
WCHAR WText[6];
} DUMMYUNIONNAME;
UCHAR CRC[2];
} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;
typedef struct _CDROM_TOC_CD_TEXT_DATA {
UCHAR Length[2];
UCHAR Reserved1;
UCHAR Reserved2;
CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0];
} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;
#endif
/* CDROM_TOC_FULL_TOC_DATA_BLOCK.Adr constants */
#define ADR_NO_MODE_INFORMATION 0x0
#define ADR_ENCODES_CURRENT_POSITION 0x1
#define ADR_ENCODES_MEDIA_CATALOG 0x2
#define ADR_ENCODES_ISRC 0x3
typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK {
UCHAR SessionNumber;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR Reserved1;
UCHAR Point;
UCHAR MsfExtra[3];
UCHAR Zero;
UCHAR Msf[3];
} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK;
#if 0 // Added to make MSVC happy.
typedef struct _CDROM_TOC_FULL_TOC_DATA {
UCHAR Length[2];
UCHAR FirstCompleteSession;
UCHAR LastCompleteSession;
CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0];
} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA;
typedef struct _CDROM_TOC_PMA_DATA {
UCHAR Length[2];
UCHAR Reserved1;
UCHAR Reserved2;
CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0];
} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA;
#endif
/* SUB_Q_HEADER.AudioStatus constants */
#define AUDIO_STATUS_NOT_SUPPORTED 0x00
#define AUDIO_STATUS_IN_PROGRESS 0x11
#define AUDIO_STATUS_PAUSED 0x12
#define AUDIO_STATUS_PLAY_COMPLETE 0x13
#define AUDIO_STATUS_PLAY_ERROR 0x14
#define AUDIO_STATUS_NO_STATUS 0x15
typedef struct _SUB_Q_HEADER {
UCHAR Reserved;
UCHAR AudioStatus;
UCHAR DataLength[2];
} SUB_Q_HEADER, *PSUB_Q_HEADER;
typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
SUB_Q_HEADER Header;
UCHAR FormatCode;
UCHAR Reserved[3];
UCHAR Reserved1 : 7;
UCHAR Mcval :1;
UCHAR MediaCatalog[15];
} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
typedef struct _SUB_Q_TRACK_ISRC {
SUB_Q_HEADER Header;
UCHAR FormatCode;
UCHAR Reserved0;
UCHAR Track;
UCHAR Reserved1;
UCHAR Reserved2 : 7;
UCHAR Tcval : 1;
UCHAR TrackIsrc[15];
} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;
typedef struct _SUB_Q_CURRENT_POSITION {
SUB_Q_HEADER Header;
UCHAR FormatCode;
UCHAR Control : 4;
UCHAR ADR : 4;
UCHAR TrackNumber;
UCHAR IndexNumber;
UCHAR AbsoluteAddress[4];
UCHAR TrackRelativeAddress[4];
} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;
typedef union _SUB_Q_CHANNEL_DATA {
SUB_Q_CURRENT_POSITION CurrentPosition;
SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog;
SUB_Q_TRACK_ISRC TrackIsrc;
} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;
/* CDROM_AUDIO_CONTROL.LbaFormat constants */
#define AUDIO_WITH_PREEMPHASIS 0x1
#define DIGITAL_COPY_PERMITTED 0x2
#define AUDIO_DATA_TRACK 0x4
#define TWO_FOUR_CHANNEL_AUDIO 0x8
typedef struct _CDROM_AUDIO_CONTROL {
UCHAR LbaFormat;
USHORT LogicalBlocksPerSecond;
} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL;
typedef struct _VOLUME_CONTROL {
UCHAR PortVolume[4];
} VOLUME_CONTROL, *PVOLUME_CONTROL;
typedef enum _TRACK_MODE_TYPE {
YellowMode2,
XAForm2,
CDDA
} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
typedef struct __RAW_READ_INFO {
LARGE_INTEGER DiskOffset;
ULONG SectorCount;
TRACK_MODE_TYPE TrackMode;
} RAW_READ_INFO, *PRAW_READ_INFO;
#ifdef __cplusplus
}
#endif
#endif /* __NTDDCDRM_H */

View file

@ -0,0 +1,388 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
#include "backends/audiocd/win32/win32-audiocd.h"
#include "audio/audiostream.h"
#include "backends/audiocd/audiocd-stream.h"
#include "backends/audiocd/default/default-audiocd.h"
#include "common/array.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/mutex.h"
#include "common/queue.h"
#include "common/str.h"
#include "common/timer.h"
#include <winioctl.h>
#if _MSC_VER < 1900
// WORKAROUND: Older versions of MSVC might not supply DDK headers by default.
// Visual Studio 2015 contains the required headers. We use a compatability
// header from MinGW's w32api for all older versions.
// TODO: Limit this to the Visual Studio versions which actually require this.
#include "msvc/ntddcdrm.h"
#elif defined(__MINGW32__) && !defined(__MINGW64__)
// Classic MinGW uses non standard paths for DDK headers.
#include <ddk/ntddcdrm.h>
#else
#include <ntddcdrm.h>
#endif
class Win32AudioCDStream : public AudioCDStream {
public:
Win32AudioCDStream(HANDLE handle, const TRACK_DATA &startEntry, const TRACK_DATA &endEntry);
~Win32AudioCDStream();
protected:
uint getStartFrame() const;
uint getEndFrame() const;
bool readFrame(int frame, int16 *buffer);
private:
HANDLE _driveHandle;
const TRACK_DATA &_startEntry, &_endEntry;
enum {
// The CD-ROM pre-gap is 2s
kPreGapFrames = kFramesPerSecond * 2
};
static int getFrameCount(const TRACK_DATA &data) {
int time = data.Address[1];
time *= kSecondsPerMinute;
time += data.Address[2];
time *= kFramesPerSecond;
time += data.Address[3];
return time;
}
};
Win32AudioCDStream::Win32AudioCDStream(HANDLE handle, const TRACK_DATA &startEntry, const TRACK_DATA &endEntry) :
_driveHandle(handle), _startEntry(startEntry), _endEntry(endEntry) {
// We fill the buffer here already to prevent any out of sync issues due
// to the CD not yet having spun up.
startTimer(true);
}
Win32AudioCDStream::~Win32AudioCDStream() {
stopTimer();
}
uint Win32AudioCDStream::getStartFrame() const {
return getFrameCount(_startEntry);
}
uint Win32AudioCDStream::getEndFrame() const {
return getFrameCount(_endEntry);
}
bool Win32AudioCDStream::readFrame(int frame, int16 *buffer) {
// Request to read that frame
RAW_READ_INFO readAudio;
memset(&readAudio, 0, sizeof(readAudio));
readAudio.DiskOffset.QuadPart = (frame - kPreGapFrames) * 2048;
readAudio.SectorCount = 1;
readAudio.TrackMode = CDDA;
DWORD bytesReturned;
return DeviceIoControl(
_driveHandle,
IOCTL_CDROM_RAW_READ,
&readAudio,
sizeof(readAudio),
buffer,
kBytesPerFrame,
&bytesReturned,
NULL);
}
class Win32AudioCDManager : public DefaultAudioCDManager {
public:
Win32AudioCDManager();
~Win32AudioCDManager();
bool open();
void close();
bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
protected:
bool openCD(int drive);
bool openCD(const Common::String &drive);
private:
bool loadTOC();
typedef Common::Array<char> DriveList;
DriveList detectDrives();
bool tryAddDrive(char drive, DriveList &drives);
HANDLE _driveHandle;
int _firstTrack, _lastTrack;
Common::Array<TRACK_DATA> _tocEntries;
};
Win32AudioCDManager::Win32AudioCDManager() {
_driveHandle = INVALID_HANDLE_VALUE;
_firstTrack = _lastTrack = 0;
}
Win32AudioCDManager::~Win32AudioCDManager() {
close();
}
bool Win32AudioCDManager::open() {
close();
if (openRealCD())
return true;
return DefaultAudioCDManager::open();
}
bool Win32AudioCDManager::openCD(int drive) {
// Fetch the drive list
DriveList drives = detectDrives();
if (drive >= (int)drives.size())
return false;
debug(1, "Opening CD drive %c:\\", drives[drive]);
// Construct the drive path and try to open it
Common::String drivePath = Common::String::format("\\\\.\\%c:", drives[drive]);
_driveHandle = CreateFileA(drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (_driveHandle == INVALID_HANDLE_VALUE) {
warning("Failed to open drive %c:\\, error %d", drives[drive], (int)GetLastError());
return false;
}
if (!loadTOC()) {
close();
return false;
}
return true;
}
bool Win32AudioCDManager::openCD(const Common::String &drive) {
// Just some bounds checking
if (drive.empty() || drive.size() > 3)
return false;
if (!Common::isAlpha(drive[0]) || drive[1] != ':')
return false;
if (drive[2] != 0 && drive[2] != '\\')
return false;
DriveList drives;
if (!tryAddDrive(toupper(drive[0]), drives))
return false;
// Construct the drive path and try to open it
Common::String drivePath = Common::String::format("\\\\.\\%c:", drives[0]);
_driveHandle = CreateFileA(drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (_driveHandle == INVALID_HANDLE_VALUE) {
warning("Failed to open drive %c:\\, error %d", drives[0], (int)GetLastError());
return false;
}
if (!loadTOC()) {
close();
return false;
}
return true;
}
void Win32AudioCDManager::close() {
DefaultAudioCDManager::close();
if (_driveHandle != INVALID_HANDLE_VALUE) {
CloseHandle(_driveHandle);
_driveHandle = INVALID_HANDLE_VALUE;
}
_firstTrack = _lastTrack = 0;
_tocEntries.clear();
}
bool Win32AudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
// Prefer emulation
if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
return true;
// If we're set to only emulate, or have no CD drive, return here
if (onlyEmulate || _driveHandle == INVALID_HANDLE_VALUE)
return false;
// HACK: For now, just assume that track number is right
// That only works because ScummVM uses the wrong track number anyway
if (track >= (int)_tocEntries.size() - 1) {
warning("No such track %d", track);
return false;
}
// Bail if the track isn't an audio track
if ((_tocEntries[track].Control & 0x04) != 0) {
warning("Track %d is not audio", track);
return false;
}
// Create the AudioStream and play it
debug(1, "Playing CD track %d", track);
Audio::SeekableAudioStream *audioStream = new Win32AudioCDStream(_driveHandle, _tocEntries[track], _tocEntries[track + 1]);
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
Audio::Timestamp end = (duration == 0) ? audioStream->getLength() : Audio::Timestamp(0, startFrame + duration, 75);
// Fake emulation since we're really playing an AudioStream
_emulating = true;
_mixer->playStream(
Audio::Mixer::kMusicSoundType,
&_handle,
Audio::makeLoopingAudioStream(audioStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops),
-1,
_cd.volume,
_cd.balance,
DisposeAfterUse::YES,
true);
return true;
}
bool Win32AudioCDManager::loadTOC() {
CDROM_READ_TOC_EX tocRequest;
memset(&tocRequest, 0, sizeof(tocRequest));
tocRequest.Format = CDROM_READ_TOC_EX_FORMAT_TOC;
tocRequest.Msf = 1;
tocRequest.SessionTrack = 0;
DWORD bytesReturned;
CDROM_TOC tocData;
bool result = DeviceIoControl(
_driveHandle,
IOCTL_CDROM_READ_TOC_EX,
&tocRequest,
sizeof(tocRequest),
&tocData,
sizeof(tocData),
&bytesReturned,
NULL);
if (!result) {
debug("Failed to query the CD TOC: %d", (int)GetLastError());
return false;
}
_firstTrack = tocData.FirstTrack;
_lastTrack = tocData.LastTrack;
#if 0
debug("First Track: %d", tocData.FirstTrack);
debug("Last Track: %d", tocData.LastTrack);
#endif
for (uint32 i = 0; i < (bytesReturned - 4) / sizeof(TRACK_DATA); i++)
_tocEntries.push_back(tocData.TrackData[i]);
#if 0
for (uint32 i = 0; i < _tocEntries.size(); i++) {
const TRACK_DATA &entry = _tocEntries[i];
debug("Entry:");
debug("\tTrack: %d", entry.TrackNumber);
debug("\tAdr: %d", entry.Adr);
debug("\tCtrl: %d", entry.Control);
debug("\tMSF: %d:%d:%d\n", entry.Address[1], entry.Address[2], entry.Address[3]);
}
#endif
return true;
}
Win32AudioCDManager::DriveList Win32AudioCDManager::detectDrives() {
DriveList drives;
// Try to get the game path's drive
char gameDrive = 0;
if (ConfMan.hasKey("path")) {
Common::String gamePath = ConfMan.get("path");
char fullPath[MAX_PATH];
DWORD result = GetFullPathNameA(gamePath.c_str(), sizeof(fullPath), fullPath, 0);
if (result > 0 && result < sizeof(fullPath) && Common::isAlpha(fullPath[0]) && fullPath[1] == ':' && tryAddDrive(toupper(fullPath[0]), drives))
gameDrive = drives[0];
}
// Try adding the rest of the drives
for (char drive = 'A'; drive <= 'Z'; drive++)
if (drive != gameDrive)
tryAddDrive(drive, drives);
return drives;
}
bool Win32AudioCDManager::tryAddDrive(char drive, DriveList &drives) {
Common::String drivePath = Common::String::format("%c:\\", drive);
// Ensure it's an actual CD drive
if (GetDriveTypeA(drivePath.c_str()) != DRIVE_CDROM)
return false;
debug(2, "Detected drive %c:\\ as a CD drive", drive);
drives.push_back(drive);
return true;
}
AudioCDManager *createWin32AudioCDManager() {
return new Win32AudioCDManager();
}
#endif // WIN32

View file

@ -0,0 +1,60 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Original license header:
*
* Cabal - Legacy Game Implementations
*
* Cabal is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_AUDIOCD_WIN32_H
#define BACKENDS_AUDIOCD_WIN32_H
#ifdef WIN32
class AudioCDManager;
/**
* Create an AudioCDManager using the Win32 API
*/
AudioCDManager *createWin32AudioCDManager();
#endif
#endif

View file

@ -121,7 +121,7 @@ int SdlEventSource::mapKey(SDLKey sdlKey, SDLMod mod, Uint16 unicode) {
Common::KeyCode key = SDLToOSystemKeycode(sdlKey); Common::KeyCode key = SDLToOSystemKeycode(sdlKey);
if (key >= Common::KEYCODE_F1 && key <= Common::KEYCODE_F9) { if (key >= Common::KEYCODE_F1 && key <= Common::KEYCODE_F9) {
return key - SDLK_F1 + Common::ASCII_F1; return key - Common::KEYCODE_F1 + Common::ASCII_F1;
} else if (key >= Common::KEYCODE_KP0 && key <= Common::KEYCODE_KP9) { } else if (key >= Common::KEYCODE_KP0 && key <= Common::KEYCODE_KP9) {
return key - Common::KEYCODE_KP0 + '0'; return key - Common::KEYCODE_KP0 + '0';
} else if (key >= Common::KEYCODE_UP && key <= Common::KEYCODE_PAGEDOWN) { } else if (key >= Common::KEYCODE_UP && key <= Common::KEYCODE_PAGEDOWN) {
@ -531,15 +531,17 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
SDLModToOSystemKeyFlags(SDL_GetModState(), event); SDLModToOSystemKeyFlags(SDL_GetModState(), event);
SDLKey sdlKeycode = obtainKeycode(ev.key.keysym);
// Handle scroll lock as a key modifier // Handle scroll lock as a key modifier
if (ev.key.keysym.sym == SDLK_SCROLLOCK) if (sdlKeycode == SDLK_SCROLLOCK)
_scrollLock = !_scrollLock; _scrollLock = !_scrollLock;
if (_scrollLock) if (_scrollLock)
event.kbd.flags |= Common::KBD_SCRL; event.kbd.flags |= Common::KBD_SCRL;
// Ctrl-m toggles mouse capture // Ctrl-m toggles mouse capture
if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') { if (event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'm') {
if (_graphicsManager) { if (_graphicsManager) {
_graphicsManager->getWindow()->toggleMouseGrab(); _graphicsManager->getWindow()->toggleMouseGrab();
} }
@ -548,26 +550,26 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
#if defined(MACOSX) #if defined(MACOSX)
// On Macintosh, Cmd-Q quits // On Macintosh, Cmd-Q quits
if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') { if ((ev.key.keysym.mod & KMOD_META) && sdlKeycode == 'q') {
event.type = Common::EVENT_QUIT; event.type = Common::EVENT_QUIT;
return true; return true;
} }
#elif defined(POSIX) #elif defined(POSIX)
// On other *nix systems, Control-Q quits // On other *nix systems, Control-Q quits
if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') { if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'q') {
event.type = Common::EVENT_QUIT; event.type = Common::EVENT_QUIT;
return true; return true;
} }
#else #else
// Ctrl-z and Alt-X quit // Ctrl-z quits
if ((event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'z') || (event.kbd.hasFlags(Common::KBD_ALT) && ev.key.keysym.sym == 'x')) { if ((event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'z')) {
event.type = Common::EVENT_QUIT; event.type = Common::EVENT_QUIT;
return true; return true;
} }
#ifdef WIN32 #ifdef WIN32
// On Windows, also use the default Alt-F4 quit combination // On Windows, also use the default Alt-F4 quit combination
if ((ev.key.keysym.mod & KMOD_ALT) && ev.key.keysym.sym == SDLK_F4) { if ((ev.key.keysym.mod & KMOD_ALT) && sdlKeycode == SDLK_F4) {
event.type = Common::EVENT_QUIT; event.type = Common::EVENT_QUIT;
return true; return true;
} }
@ -575,7 +577,7 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
#endif #endif
// Ctrl-u toggles mute // Ctrl-u toggles mute
if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') { if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'u') {
event.type = Common::EVENT_MUTE; event.type = Common::EVENT_MUTE;
return true; return true;
} }
@ -584,8 +586,8 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
return true; return true;
event.type = Common::EVENT_KEYDOWN; event.type = Common::EVENT_KEYDOWN;
event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym); event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode);
event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym)); event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym));
return true; return true;
} }
@ -594,6 +596,7 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
if (remapKey(ev, event)) if (remapKey(ev, event))
return true; return true;
SDLKey sdlKeycode = obtainKeycode(ev.key.keysym);
SDLMod mod = SDL_GetModState(); SDLMod mod = SDL_GetModState();
// Check if this is an event handled by handleKeyDown(), and stop if it is // Check if this is an event handled by handleKeyDown(), and stop if it is
@ -601,35 +604,30 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
// Check if the Ctrl key is down, so that we can trap cases where the // Check if the Ctrl key is down, so that we can trap cases where the
// user has the Ctrl key down, and has just released a special key // user has the Ctrl key down, and has just released a special key
if (mod & KMOD_CTRL) { if (mod & KMOD_CTRL) {
if (ev.key.keysym.sym == 'm' || // Ctrl-m toggles mouse capture if (sdlKeycode == 'm' || // Ctrl-m toggles mouse capture
#if defined(MACOSX) #if defined(MACOSX)
// Meta - Q, handled below // Meta - Q, handled below
#elif defined(POSIX) #elif defined(POSIX)
ev.key.keysym.sym == 'q' || // On other *nix systems, Control-Q quits sdlKeycode == 'q' || // On other *nix systems, Control-Q quits
#else #else
ev.key.keysym.sym == 'z' || // Ctrl-z quit sdlKeycode == 'z' || // Ctrl-z quit
#endif #endif
ev.key.keysym.sym == 'u') // Ctrl-u toggles mute sdlKeycode == 'u') // Ctrl-u toggles mute
return false; return false;
} }
// Same for other keys (Meta and Alt) // Same for other keys (Meta and Alt)
#if defined(MACOSX) #if defined(MACOSX)
if ((mod & KMOD_META) && ev.key.keysym.sym == 'q') if ((mod & KMOD_META) && sdlKeycode == 'q')
return false; // On Macintosh, Cmd-Q quits return false; // On Macintosh, Cmd-Q quits
#elif defined(POSIX)
// Control Q has already been handled above
#else
if ((mod & KMOD_ALT) && ev.key.keysym.sym == 'x')
return false; // Alt-x quit
#endif #endif
// If we reached here, this isn't an event handled by handleKeyDown(), thus // If we reached here, this isn't an event handled by handleKeyDown(), thus
// continue normally // continue normally
event.type = Common::EVENT_KEYUP; event.type = Common::EVENT_KEYUP;
event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym); event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode);
event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, 0); event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, 0);
// Ctrl-Alt-<key> will change the GFX mode // Ctrl-Alt-<key> will change the GFX mode
SDLModToOSystemKeyFlags(mod, event); SDLModToOSystemKeyFlags(mod, event);
@ -887,10 +885,63 @@ bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) {
return false; return false;
} }
SDLKey SdlEventSource::obtainKeycode(const SDL_keysym keySym) {
#if !SDL_VERSION_ATLEAST(2, 0, 0) && defined(WIN32) && !defined(_WIN32_WCE)
// WORKAROUND: SDL 1.2 on Windows does not use the user configured keyboard layout,
// resulting in "keySym.sym" values to always be those expected for an US keyboard.
// For example, SDL returns SDLK_Q when pressing the 'A' key on an AZERTY keyboard.
// This defeats the purpose of keycodes which is to be able to refer to a key without
// knowing where it is physically located.
// We work around this issue by querying the currently active Windows keyboard layout
// using the scancode provided by SDL.
if (keySym.sym >= SDLK_0 && keySym.sym <= SDLK_9) {
// The keycode returned by SDL is kept for the number keys.
// Querying the keyboard layout for those would return the base key values
// for AZERTY keyboards, which are not numbers. For example, SDLK_1 would
// map to SDLK_AMPERSAND. This is theoretically correct but practically unhelpful,
// because it makes it impossible to handle key combinations such as "ctrl-1".
return keySym.sym;
}
int vk = MapVirtualKey(keySym.scancode, MAPVK_VSC_TO_VK);
if (vk) {
int ch = (MapVirtualKey(vk, MAPVK_VK_TO_CHAR) & 0x7FFF);
// The top bit of the result of MapVirtualKey with MAPVK_VSC_TO_VK signals
// a dead key was pressed. In that case we keep the value of the accent alone.
if (ch) {
if (ch >= 'A' && ch <= 'Z') {
// Windows returns uppercase ASCII whereas SDL expects lowercase
return (SDLKey)(SDLK_a + (ch - 'A'));
} else {
return (SDLKey)ch;
}
}
}
#endif
return keySym.sym;
}
uint32 SdlEventSource::obtainUnicode(const SDL_keysym keySym) { uint32 SdlEventSource::obtainUnicode(const SDL_keysym keySym) {
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Event events[2]; SDL_Event events[2];
// Update the event queue here to give SDL a chance to insert TEXTINPUT
// events for KEYDOWN events. Otherwise we have a high chance that on
// Windows the TEXTINPUT event is not in the event queue at this point.
// In this case we will get two events with ascii values due to mapKey
// and dispatchSDLEvent. This results in nasty double input of characters
// in the GUI.
//
// FIXME: This is all a bit fragile because in mapKey we derive the ascii
// value from the key code if no unicode value is given. This is legacy
// behavior and should be removed anyway. If that is removed, we might not
// even need to do this peeking here but instead can rely on the
// SDL_TEXTINPUT case in dispatchSDLEvent to introduce keydown/keyup with
// proper ASCII values (but with KEYCODE_INVALID as keycode).
SDL_PumpEvents();
// In SDL2, the unicode field has been removed from the keysym struct. // In SDL2, the unicode field has been removed from the keysym struct.
// Instead a SDL_TEXTINPUT event is generated on key combinations that // Instead a SDL_TEXTINPUT event is generated on key combinations that
// generates unicode. // generates unicode.

View file

@ -150,6 +150,11 @@ protected:
*/ */
uint32 obtainUnicode(const SDL_keysym keySym); uint32 obtainUnicode(const SDL_keysym keySym);
/**
* Extracts the keycode for the specified key sym.
*/
SDLKey obtainKeycode(const SDL_keysym keySym);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
/** /**
* Whether _fakeKeyUp contains an event we need to send. * Whether _fakeKeyUp contains an event we need to send.

View file

@ -38,6 +38,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <dirent.h> #include <dirent.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#ifdef __OS2__ #ifdef __OS2__
#define INCL_DOS #define INCL_DOS
@ -251,4 +252,67 @@ Common::WriteStream *POSIXFilesystemNode::createWriteStream() {
return StdioStream::makeFromPath(getPath(), true); return StdioStream::makeFromPath(getPath(), true);
} }
namespace Posix {
bool assureDirectoryExists(const Common::String &dir, const char *prefix) {
struct stat sb;
// Check whether the prefix exists if one is supplied.
if (prefix) {
if (stat(prefix, &sb) != 0) {
return false;
} else if (!S_ISDIR(sb.st_mode)) {
return false;
}
}
// Obtain absolute path.
Common::String path;
if (prefix) {
path = prefix;
path += '/';
path += dir;
} else {
path = dir;
}
path = Common::normalizePath(path, '/');
const Common::String::iterator end = path.end();
Common::String::iterator cur = path.begin();
if (*cur == '/')
++cur;
do {
if (cur + 1 != end) {
if (*cur != '/') {
continue;
}
// It is kind of ugly and against the purpose of Common::String to
// insert 0s inside, but this is just for a local string and
// simplifies the code a lot.
*cur = '\0';
}
if (mkdir(path.c_str(), 0755) != 0) {
if (errno == EEXIST) {
if (stat(path.c_str(), &sb) != 0) {
return false;
} else if (!S_ISDIR(sb.st_mode)) {
return false;
}
} else {
return false;
}
}
*cur = '/';
} while (cur++ != end);
return true;
}
} // End of namespace Posix
#endif //#if defined(POSIX) #endif //#if defined(POSIX)

View file

@ -81,4 +81,18 @@ private:
virtual void setFlags(); virtual void setFlags();
}; };
namespace Posix {
/**
* Assure that a directory path exists.
*
* @param dir The path which is required to exist.
* @param prefix An (optional) prefix which should not be created if non existent.
* prefix is prepended to dir if supplied.
* @return true in case the directoy exists (or was created), false otherwise.
*/
bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr);
} // End of namespace Posix
#endif #endif

View file

@ -185,6 +185,9 @@ MusicDevices WindowsMusicPlugin::getDevices() const {
deviceNames.push_back(tmp.szPname); deviceNames.push_back(tmp.szPname);
} }
// Limit us to the number of actually retrieved devices.
numDevs = deviceNames.size();
// Check for non-unique device names. This may happen if someone has devices with identical // Check for non-unique device names. This may happen if someone has devices with identical
// names (e. g. more than one USB device of the exact same hardware type). It seems that this // names (e. g. more than one USB device of the exact same hardware type). It seems that this
// does happen in reality sometimes. We generate index numbers for these devices. // does happen in reality sometimes. We generate index numbers for these devices.

View file

@ -3,6 +3,7 @@ MODULE := backends
MODULE_OBJS := \ MODULE_OBJS := \
base-backend.o \ base-backend.o \
modular-backend.o \ modular-backend.o \
audiocd/audiocd-stream.o \
audiocd/default/default-audiocd.o \ audiocd/default/default-audiocd.o \
events/default/default-events.o \ events/default/default-events.o \
fs/abstract-fs.o \ fs/abstract-fs.o \
@ -90,6 +91,7 @@ endif
ifdef MACOSX ifdef MACOSX
MODULE_OBJS += \ MODULE_OBJS += \
audiocd/macosx/macosx-audiocd.o \
midi/coreaudio.o \ midi/coreaudio.o \
midi/coremidi.o \ midi/coremidi.o \
updates/macosx/macosx-updates.o \ updates/macosx/macosx-updates.o \
@ -98,11 +100,13 @@ endif
ifdef WIN32 ifdef WIN32
MODULE_OBJS += \ MODULE_OBJS += \
audiocd/win32/win32-audiocd.o \
fs/windows/windows-fs.o \ fs/windows/windows-fs.o \
fs/windows/windows-fs-factory.o \ fs/windows/windows-fs-factory.o \
midi/windows.o \ midi/windows.o \
plugins/win32/win32-provider.o \ plugins/win32/win32-provider.o \
saves/windows/windows-saves.o \ saves/windows/windows-saves.o \
updates/win32/win32-updates.o \
taskbar/win32/win32-taskbar.o taskbar/win32/win32-taskbar.o
endif endif
@ -121,6 +125,11 @@ MODULE_OBJS += \
events/ps3sdl/ps3sdl-events.o events/ps3sdl/ps3sdl-events.o
endif endif
ifdef USE_LINUXCD
MODULE_OBJS += \
audiocd/linux/linux-audiocd.o
endif
ifeq ($(BACKEND),tizen) ifeq ($(BACKEND),tizen)
MODULE_OBJS += \ MODULE_OBJS += \
timer/tizen/timer.o timer/tizen/timer.o

View file

@ -24,13 +24,44 @@
#if defined(__amigaos4__) #if defined(__amigaos4__)
#include "backends/fs/amigaos4/amigaos4-fs.h"
#include "backends/platform/sdl/amigaos/amigaos.h" #include "backends/platform/sdl/amigaos/amigaos.h"
#include "backends/plugins/sdl/sdl-provider.h" #include "backends/plugins/sdl/sdl-provider.h"
#include "base/main.h" #include "base/main.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Set up a stack cookie to avoid crashes due to too few stack set by users // The following will gather the application name and add the install path
// to a variable in AmigaOS4's ENV(ARC) system. It will be placed in AppPaths
// so that ScummVM can become AmiUpdate aware
const char *const appname = "ResidualVM";
BPTR lock;
APTR oldwin;
// Obtain a lock to the home directory
if ((lock = IDOS->GetProgramDir())) {
TEXT progpath[2048];
TEXT apppath[1024] = "AppPaths";
if (IDOS->DevNameFromLock(lock,
progpath,
sizeof(progpath),
DN_FULLPATH)) {
// Stop any "Insert volume..." type requesters
oldwin = IDOS->SetProcWindow((APTR)-1);
// Finally, set the variable to the path the executable was run from
IDOS->AddPart( apppath, appname, 1024);
IDOS->SetVar( apppath, progpath, -1, GVF_GLOBAL_ONLY|GVF_SAVE_VAR );
// Turn system requesters back on
IDOS->SetProcWindow( oldwin );
}
}
// Set up a stack cookie to avoid crashes from a stack set too low
static const char *stack_cookie __attribute__((used)) = "$STACK: 600000"; static const char *stack_cookie __attribute__((used)) = "$STACK: 600000";
// Create our OSystem instance // Create our OSystem instance
@ -44,7 +75,7 @@ int main(int argc, char *argv[]) {
PluginManager::instance().addPluginProvider(new SDLPluginProvider()); PluginManager::instance().addPluginProvider(new SDLPluginProvider());
#endif #endif
// Invoke the actual ScummVM main entry point: // Invoke the actual ScummVM main entry point
int res = scummvm_main(argc, argv); int res = scummvm_main(argc, argv);
// Free OSystem // Free OSystem

View file

@ -10,6 +10,17 @@ amigaosdist: $(EXECUTABLE)
ifdef DIST_FILES_ENGINEDATA ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/ cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/
endif endif
cat ${srcdir}/README | sed -f ${srcdir}/dists/amiga/convertRM.sed > README.conv
# AmigaOS's shell is not happy with indented comments, thus don't do it.
# AREXX seems to have problems when ${srcdir} is '.'. It will break with a
# "Program not found" error. Therefore we copy the script to the cwd and
# remove it again, once it has finished.
cp ${srcdir}/dists/amiga/RM2AG.rx .
rx RM2AG.rx README.conv
cp README.guide $(AMIGAOSPATH)
rm RM2AG.rx
rm README.conv
rm README.guide
cp $(DIST_FILES_DOCS) $(AMIGAOSPATH) cp $(DIST_FILES_DOCS) $(AMIGAOSPATH)
# Special target to cross create an AmigaOS snapshot installation # Special target to cross create an AmigaOS snapshot installation

View file

@ -27,9 +27,10 @@
#ifdef MACOSX #ifdef MACOSX
#include "backends/platform/sdl/macosx/macosx.h" #include "backends/audiocd/macosx/macosx-audiocd.h"
#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h" #include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
#include "backends/platform/sdl/macosx/appmenu_osx.h" #include "backends/platform/sdl/macosx/appmenu_osx.h"
#include "backends/platform/sdl/macosx/macosx.h"
#include "backends/updates/macosx/macosx-updates.h" #include "backends/updates/macosx/macosx-updates.h"
#include "backends/taskbar/macosx/macosx-taskbar.h" #include "backends/taskbar/macosx/macosx-taskbar.h"
@ -170,4 +171,8 @@ Common::String OSystem_MacOSX::getSystemLanguage() const {
#endif // USE_DETECTLANG #endif // USE_DETECTLANG
} }
AudioCDManager *OSystem_MacOSX::createAudioCDManager() {
return createMacOSXAudioCDManager();
}
#endif #endif

View file

@ -38,6 +38,11 @@ public:
virtual void init(); virtual void init();
virtual void initBackend(); virtual void initBackend();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
protected:
// Override createAudioCDManager() to get our Mac-specific
// version.
virtual AudioCDManager *createAudioCDManager();
}; };
#endif #endif

View file

@ -22,7 +22,7 @@
#include "common/scummsys.h" #include "common/scummsys.h"
#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) #if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(ANDROIDSDL)
#include "backends/platform/sdl/posix/posix.h" #include "backends/platform/sdl/posix/posix.h"
#include "backends/plugins/sdl/sdl-provider.h" #include "backends/plugins/sdl/sdl-provider.h"

View file

@ -33,14 +33,18 @@
#include "backends/platform/sdl/posix/posix.h" #include "backends/platform/sdl/posix/posix.h"
#include "backends/saves/posix/posix-saves.h" #include "backends/saves/posix/posix-saves.h"
#include "backends/fs/posix/posix-fs-factory.h" #include "backends/fs/posix/posix-fs-factory.h"
#include "backends/fs/posix/posix-fs.h"
#include "backends/taskbar/unity/unity-taskbar.h" #include "backends/taskbar/unity/unity-taskbar.h"
#ifdef USE_LINUXCD
#include "backends/audiocd/linux/linux-audiocd.h"
#endif
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName) OSystem_POSIX::OSystem_POSIX(Common::String baseConfigName)
: :
_baseConfigName(baseConfigName) { _baseConfigName(baseConfigName) {
@ -82,11 +86,54 @@ bool OSystem_POSIX::hasFeature(Feature f) {
Common::String OSystem_POSIX::getDefaultConfigFileName() { Common::String OSystem_POSIX::getDefaultConfigFileName() {
Common::String configFile; Common::String configFile;
// On POSIX type systems, by default we store the config file inside Common::String prefix;
// to the HOME directory of the user. #ifdef MACOSX
const char *home = getenv("HOME"); prefix = getenv("HOME");
if (home != NULL && (strlen(home) + 1 + _baseConfigName.size()) < MAXPATHLEN) { #elif !defined(SAMSUNGTV)
configFile = Common::String::format("%s/%s", home, _baseConfigName.c_str()); const char *envVar;
// Our old configuration file path for POSIX systems was ~/.residualvmrc.
// If that file exists, we still use it.
envVar = getenv("HOME");
if (envVar && *envVar) {
configFile = envVar;
configFile += '/';
configFile += ".residualvmrc";
if (configFile.size() < MAXPATHLEN) {
struct stat sb;
if (stat(configFile.c_str(), &sb) == 0) {
return configFile;
}
}
}
// On POSIX systems we follow the XDG Base Directory Specification for
// where to store files. The version we based our code upon can be found
// over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
envVar = getenv("XDG_CONFIG_HOME");
if (!envVar || !*envVar) {
envVar = getenv("HOME");
if (!envVar) {
return 0;
}
if (Posix::assureDirectoryExists(".config", envVar)) {
prefix = envVar;
prefix += "/.config";
}
} else {
prefix = envVar;
}
if (!prefix.empty() && Posix::assureDirectoryExists("residualvm", prefix.c_str())) {
prefix += "/residualvm";
}
#endif
if (!prefix.empty() && (prefix.size() + 1 + _baseConfigName.size()) < MAXPATHLEN) {
configFile = prefix;
configFile += '/';
configFile += _baseConfigName;
} else { } else {
configFile = _baseConfigName; configFile = _baseConfigName;
} }
@ -99,58 +146,43 @@ Common::WriteStream *OSystem_POSIX::createLogFile() {
// of a failure, we know that no log file is open. // of a failure, we know that no log file is open.
_logFilePath.clear(); _logFilePath.clear();
const char *home = getenv("HOME"); const char *prefix = nullptr;
if (home == NULL) Common::String logFile;
return 0;
Common::String logFile(home);
#ifdef MACOSX #ifdef MACOSX
logFile += "/Library"; prefix = getenv("HOME");
#else if (prefix == nullptr) {
logFile += "/.residualvm";
#endif
#ifdef SAMSUNGTV
logFile = "/mtd_ram";
#endif
struct stat sb;
// Check whether the dir exists
if (stat(logFile.c_str(), &sb) == -1) {
// The dir does not exist, or stat failed for some other reason.
if (errno != ENOENT)
return 0;
// If the problem was that the path pointed to nothing, try
// to create the dir.
if (mkdir(logFile.c_str(), 0755) != 0)
return 0;
} else if (!S_ISDIR(sb.st_mode)) {
// Path is no directory. Oops
return 0; return 0;
} }
#ifdef MACOSX logFile = "Library/Logs";
logFile += "/Logs"; #elif SAMSUNGTV
prefix = nullptr;
logFile = "/mtd_ram";
#else #else
logFile += "/logs"; // On POSIX systems we follow the XDG Base Directory Specification for
// where to store files. The version we based our code upon can be found
// over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
prefix = getenv("XDG_CACHE_HOME");
if (prefix == nullptr || !*prefix) {
prefix = getenv("HOME");
if (prefix == nullptr) {
return 0;
}
logFile = ".cache/";
}
logFile += "residualvm/logs";
#endif #endif
// Check whether the dir exists if (!Posix::assureDirectoryExists(logFile, prefix)) {
if (stat(logFile.c_str(), &sb) == -1) {
// The dir does not exist, or stat failed for some other reason.
if (errno != ENOENT)
return 0;
// If the problem was that the path pointed to nothing, try
// to create the dir.
if (mkdir(logFile.c_str(), 0755) != 0)
return 0;
} else if (!S_ISDIR(sb.st_mode)) {
// Path is no directory. Oops
return 0; return 0;
} }
if (prefix) {
logFile = Common::String::format("%s/%s", prefix, logFile.c_str());
}
logFile += "/residualvm.log"; logFile += "/residualvm.log";
Common::FSNode file(logFile); Common::FSNode file(logFile);
@ -212,4 +244,12 @@ bool OSystem_POSIX::displayLogFile() {
} }
AudioCDManager *OSystem_POSIX::createAudioCDManager() {
#ifdef USE_LINUXCD
return createLinuxAudioCDManager();
#else
return OSystem_SDL::createAudioCDManager();
#endif
}
#endif #endif

View file

@ -28,7 +28,7 @@
class OSystem_POSIX : public OSystem_SDL { class OSystem_POSIX : public OSystem_SDL {
public: public:
// Let the subclasses be able to change _baseConfigName in the constructor // Let the subclasses be able to change _baseConfigName in the constructor
OSystem_POSIX(Common::String baseConfigName = ".residualvmrc"); OSystem_POSIX(Common::String baseConfigName = "residualvm.ini");
virtual ~OSystem_POSIX() {} virtual ~OSystem_POSIX() {}
virtual bool hasFeature(Feature f); virtual bool hasFeature(Feature f);
@ -59,6 +59,8 @@ protected:
virtual Common::String getDefaultConfigFileName(); virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile(); virtual Common::WriteStream *createLogFile();
virtual AudioCDManager *createAudioCDManager();
}; };
#endif #endif

View file

@ -52,6 +52,21 @@ typedef struct { int FAKE; } FAKE_FILE;
#define strncasecmp FAKE_strncasecmp #define strncasecmp FAKE_strncasecmp
#endif #endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit)
#undef exit
#define exit FAKE_exit
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort)
#undef abort
#define abort FAKE_abort
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system)
#undef system
#define system FAKE_system
#endif
// HACK: SDL might include windows.h which defines its own ARRAYSIZE. // HACK: SDL might include windows.h which defines its own ARRAYSIZE.
// However, we want to use the version from common/util.h. Thus, we make sure // However, we want to use the version from common/util.h. Thus, we make sure
// that we actually have this definition after including the SDL headers. // that we actually have this definition after including the SDL headers.
@ -129,7 +144,7 @@ typedef struct { int FAKE; } FAKE_FILE;
#endif #endif
// In a moment of brilliance Xlib.h included by SDL_syswm.h #defines the // In a moment of brilliance Xlib.h included by SDL_syswm.h #defines the
// following names. In a moment of mental breakdown, which occured upon // following names. In a moment of mental breakdown, which occurred upon
// gazing at Xlib.h, LordHoto decided to undefine them to prevent havoc. // gazing at Xlib.h, LordHoto decided to undefine them to prevent havoc.
#ifdef Status #ifdef Status
#undef Status #undef Status
@ -163,6 +178,21 @@ typedef struct { int FAKE; } FAKE_FILE;
#define strncasecmp FORBIDDEN_SYMBOL_REPLACEMENT #define strncasecmp FORBIDDEN_SYMBOL_REPLACEMENT
#endif #endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit)
#undef exit
#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort)
#undef abort
#define abort() FORBIDDEN_SYMBOL_REPLACEMENT
#endif
#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system)
#undef system
#define system(a) FORBIDDEN_SYMBOL_REPLACEMENT
#endif
// SDL 2 has major API changes. We redefine constants which got renamed to // SDL 2 has major API changes. We redefine constants which got renamed to
// ease the transition. This is sometimes dangerous because the values changed // ease the transition. This is sometimes dangerous because the values changed
// too! // too!

View file

@ -49,9 +49,10 @@
#include "backends/timer/sdl/sdl-timer.h" #include "backends/timer/sdl/sdl-timer.h"
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h" #include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
#ifdef USE_OPENGL #ifdef USE_OPENGL
#include "backends/graphics/openglsdl/openglsdl-graphics.h" #include "backends/graphics/openglsdl/openglsdl-graphics.h"
#include "graphics/opengl/context.h" //#include "graphics/cursorman.h" // ResidualVM
#include "graphics/opengl/context.h" // ResidualVM specific
#endif #endif
#include <time.h> // for getTimeAndDate() #include <time.h> // for getTimeAndDate()
@ -169,10 +170,12 @@ void OSystem_SDL::initBackend() {
// is not active by this point. // is not active by this point.
debug(1, "Using SDL Video Driver \"%s\"", sdlDriverName); debug(1, "Using SDL Video Driver \"%s\"", sdlDriverName);
// ResidualVM specific code start
detectDesktopResolution(); detectDesktopResolution();
#ifdef USE_OPENGL #ifdef USE_OPENGL
detectFramebufferSupport(); detectFramebufferSupport();
#endif #endif
// ResidualVM specific code end
// Create the default event source, in case a custom backend // Create the default event source, in case a custom backend
// manager didn't provide one yet. // manager didn't provide one yet.
@ -203,15 +206,7 @@ void OSystem_SDL::initBackend() {
_timerManager = new SdlTimerManager(); _timerManager = new SdlTimerManager();
#endif #endif
if (_audiocdManager == 0) { _audiocdManager = createAudioCDManager();
// Audio CD support was removed with SDL 2.0
#if SDL_VERSION_ATLEAST(2, 0, 0)
_audiocdManager = new DefaultAudioCDManager();
#else
_audiocdManager = new SdlAudioCDManager();
#endif
}
// Setup a custom program icon. // Setup a custom program icon.
_window->setupIcon(); _window->setupIcon();
@ -345,6 +340,7 @@ void OSystem_SDL::setWindowCaption(const char *caption) {
_window->setWindowCaption(cap); _window->setWindowCaption(cap);
} }
// ResidualVM specific code
void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) { void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) {
#ifdef USE_OPENGL #ifdef USE_OPENGL
bool switchedManager = false; bool switchedManager = false;
@ -374,6 +370,7 @@ void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool
void OSystem_SDL::launcherInitSize(uint w, uint h) { void OSystem_SDL::launcherInitSize(uint w, uint h) {
setupScreen(w, h, false, false); setupScreen(w, h, false, false);
} }
// End of ResidualVM specific code
void OSystem_SDL::quit() { void OSystem_SDL::quit() {
delete this; delete this;
@ -531,6 +528,15 @@ Common::TimerManager *OSystem_SDL::getTimerManager() {
#endif #endif
} }
AudioCDManager *OSystem_SDL::createAudioCDManager() {
// Audio CD support was removed with SDL 2.0
#if SDL_VERSION_ATLEAST(2, 0, 0)
return new DefaultAudioCDManager();
#else
return new SdlAudioCDManager();
#endif
}
// ResidualVM specific code // ResidualVM specific code
bool OSystem_SDL::hasFeature(Feature f) { bool OSystem_SDL::hasFeature(Feature f) {
if (f == kFeatureSideTextures) if (f == kFeatureSideTextures)

View file

@ -83,6 +83,7 @@ public:
// ResidualVM specific code // ResidualVM specific code
virtual void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) override; virtual void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) override;
// ResidualVM specific code
virtual void launcherInitSize(uint w, uint h) override; virtual void launcherInitSize(uint w, uint h) override;
protected: protected:
@ -119,6 +120,11 @@ protected:
*/ */
virtual void initSDL(); virtual void initSDL();
/**
* Create the audio CD manager
*/
virtual AudioCDManager *createAudioCDManager();
// Logging // Logging
virtual Common::WriteStream *createLogFile() { return 0; } virtual Common::WriteStream *createLogFile() { return 0; }
Backends::Log::Log *_logger; Backends::Log::Log *_logger;

View file

@ -44,7 +44,12 @@ int __stdcall WinMain(HINSTANCE /*hInst*/, HINSTANCE /*hPrevInst*/, LPSTR /*lpC
SDL_SetModuleHandle(GetModuleHandle(NULL)); SDL_SetModuleHandle(GetModuleHandle(NULL));
#endif #endif
// HACK: __argc, __argv are broken and return zero when using mingwrt 4.0+ on MinGW // HACK: __argc, __argv are broken and return zero when using mingwrt 4.0+ on MinGW
#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64__) // HACK: MinGW-w64 based toolchains neither feature _argc nor _argv. The 32 bit
// incarnation only defines __MINGW32__. This leads to build breakage due to
// missing declarations. Luckily MinGW-w64 based toolchains define
// __MINGW64_VERSION_foo macros inside _mingw.h, which is included from all
// system headers. Thus we abuse that to detect them.
#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
return main(_argc, _argv); return main(_argc, _argv);
#else #else
return main(__argc, __argv); return main(__argc, __argv);

View file

@ -35,11 +35,13 @@
#include "common/error.h" #include "common/error.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "backends/audiocd/win32/win32-audiocd.h"
#include "backends/platform/sdl/win32/win32.h" #include "backends/platform/sdl/win32/win32.h"
#include "backends/platform/sdl/win32/win32-window.h" #include "backends/platform/sdl/win32/win32-window.h"
#include "backends/saves/windows/windows-saves.h" #include "backends/saves/windows/windows-saves.h"
#include "backends/fs/windows/windows-fs-factory.h" #include "backends/fs/windows/windows-fs-factory.h"
#include "backends/taskbar/win32/win32-taskbar.h" #include "backends/taskbar/win32/win32-taskbar.h"
#include "backends/updates/win32/win32-updates.h"
#include "common/memstream.h" #include "common/memstream.h"
@ -81,6 +83,11 @@ void OSystem_Win32::initBackend() {
if (_savefileManager == 0) if (_savefileManager == 0)
_savefileManager = new WindowsSaveFileManager(); _savefileManager = new WindowsSaveFileManager();
#if defined(USE_SPARKLE)
// Initialize updates manager
_updateManager = new Win32UpdateManager();
#endif
// Invoke parent implementation of this method // Invoke parent implementation of this method
OSystem_SDL::initBackend(); OSystem_SDL::initBackend();
} }
@ -318,4 +325,8 @@ void OSystem_Win32::addSysArchivesToSearchSet(Common::SearchSet &s, int priority
OSystem_SDL::addSysArchivesToSearchSet(s, priority); OSystem_SDL::addSysArchivesToSearchSet(s, priority);
} }
AudioCDManager *OSystem_Win32::createAudioCDManager() {
return createWin32AudioCDManager();
}
#endif #endif

View file

@ -49,6 +49,10 @@ protected:
virtual Common::String getDefaultConfigFileName(); virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile(); virtual Common::WriteStream *createLogFile();
// Override createAudioCDManager() to get our Mac-specific
// version.
virtual AudioCDManager *createAudioCDManager();
}; };
#endif #endif

View file

@ -77,7 +77,7 @@ public:
debug("Failed loading plugin '%s' (error code %d)", _filename.c_str(), (int32) GetLastError()); debug("Failed loading plugin '%s' (error code %d)", _filename.c_str(), (int32) GetLastError());
return false; return false;
} else { } else {
debug(1, "Success loading plugin '%s', handle %08X", _filename.c_str(), (uint32) _dlHandle); debug(1, "Success loading plugin '%s', handle %p", _filename.c_str(), _dlHandle);
} }
return DynamicPlugin::loadPlugin(); return DynamicPlugin::loadPlugin();

View file

@ -60,22 +60,15 @@ void DefaultSaveFileManager::checkPath(const Common::FSNode &dir) {
} }
Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &pattern) { Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &pattern) {
Common::String savePathName = getSavePath(); // Assure the savefile name cache is up-to-date.
checkPath(Common::FSNode(savePathName)); assureCached(getSavePath());
if (getError().getCode() != Common::kNoError) if (getError().getCode() != Common::kNoError)
return Common::StringArray(); return Common::StringArray();
// recreate FSNode since checkPath may have changed/created the directory
Common::FSNode savePath(savePathName);
Common::FSDirectory dir(savePath);
Common::ArchiveMemberList savefiles;
Common::StringArray results; Common::StringArray results;
Common::String search(pattern); for (SaveFileCache::const_iterator file = _saveFileCache.begin(), end = _saveFileCache.end(); file != end; ++file) {
if (file->_key.matchString(pattern, true)) {
if (dir.listMatchingMembers(savefiles, search) > 0) { results.push_back(file->_key);
for (Common::ArchiveMemberList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) {
results.push_back((*file)->getName());
} }
} }
@ -83,68 +76,81 @@ Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &
} }
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) { Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) {
// Ensure that the savepath is valid. If not, generate an appropriate error. // Assure the savefile name cache is up-to-date.
Common::String savePathName = getSavePath(); assureCached(getSavePath());
checkPath(Common::FSNode(savePathName));
if (getError().getCode() != Common::kNoError) if (getError().getCode() != Common::kNoError)
return 0; return nullptr;
// recreate FSNode since checkPath may have changed/created the directory SaveFileCache::const_iterator file = _saveFileCache.find(filename);
Common::FSNode savePath(savePathName); if (file == _saveFileCache.end()) {
return nullptr;
Common::FSNode file = savePath.getChild(filename); } else {
if (!file.exists()) // Open the file for loading.
return 0; Common::SeekableReadStream *sf = file->_value.createReadStream();
return Common::wrapCompressedReadStream(sf);
// Open the file for reading }
Common::SeekableReadStream *sf = file.createReadStream();
return Common::wrapCompressedReadStream(sf);
} }
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename, bool compress) { Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename, bool compress) {
// Ensure that the savepath is valid. If not, generate an appropriate error. // Assure the savefile name cache is up-to-date.
Common::String savePathName = getSavePath(); const Common::String savePathName = getSavePath();
checkPath(Common::FSNode(savePathName)); assureCached(savePathName);
if (getError().getCode() != Common::kNoError) if (getError().getCode() != Common::kNoError)
return 0; return nullptr;
// recreate FSNode since checkPath may have changed/created the directory // Obtain node.
Common::FSNode savePath(savePathName); SaveFileCache::const_iterator file = _saveFileCache.find(filename);
Common::FSNode fileNode;
Common::FSNode file = savePath.getChild(filename); // If the file did not exist before, we add it to the cache.
if (file == _saveFileCache.end()) {
const Common::FSNode savePath(savePathName);
fileNode = savePath.getChild(filename);
} else {
fileNode = file->_value;
}
// Open the file for saving // Open the file for saving.
Common::WriteStream *sf = file.createWriteStream(); Common::WriteStream *const sf = fileNode.createWriteStream();
Common::OutSaveFile *const result = compress ? Common::wrapCompressedWriteStream(sf) : sf;
return compress ? Common::wrapCompressedWriteStream(sf) : sf; // Add file to cache now that it exists.
_saveFileCache[filename] = Common::FSNode(fileNode.getPath());
return result;
} }
bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) { bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
Common::String savePathName = getSavePath(); // Assure the savefile name cache is up-to-date.
checkPath(Common::FSNode(savePathName)); assureCached(getSavePath());
if (getError().getCode() != Common::kNoError) if (getError().getCode() != Common::kNoError)
return false; return false;
// recreate FSNode since checkPath may have changed/created the directory // Obtain node if exists.
Common::FSNode savePath(savePathName); SaveFileCache::const_iterator file = _saveFileCache.find(filename);
if (file == _saveFileCache.end()) {
Common::FSNode file = savePath.getChild(filename);
// FIXME: remove does not exist on all systems. If your port fails to
// compile because of this, please let us know (scummvm-devel or Fingolfin).
// There is a nicely portable workaround, too: Make this method overloadable.
if (remove(file.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
if (errno == EACCES)
setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
if (errno == ENOENT)
setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
#endif
return false; return false;
} else { } else {
return true; const Common::FSNode fileNode = file->_value;
// Remove from cache, this invalidates the 'file' iterator.
_saveFileCache.erase(file);
file = _saveFileCache.end();
// FIXME: remove does not exist on all systems. If your port fails to
// compile because of this, please let us know (scummvm-devel).
// There is a nicely portable workaround, too: Make this method overloadable.
if (remove(fileNode.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
if (errno == EACCES)
setError(Common::kWritePermissionDenied, "Search or write permission denied: "+fileNode.getName());
if (errno == ENOENT)
setError(Common::kPathDoesNotExist, "removeSavefile: '"+fileNode.getName()+"' does not exist or path is invalid");
#endif
return false;
} else {
return true;
}
} }
} }
@ -171,4 +177,43 @@ Common::String DefaultSaveFileManager::getSavePath() const {
return dir; return dir;
} }
void DefaultSaveFileManager::assureCached(const Common::String &savePathName) {
// Check that path exists and is usable.
checkPath(Common::FSNode(savePathName));
if (_cachedDirectory == savePathName) {
return;
}
_saveFileCache.clear();
_cachedDirectory.clear();
if (getError().getCode() != Common::kNoError) {
warning("DefaultSaveFileManager::assureCached: Can not cache path '%s': '%s'", savePathName.c_str(), getErrorDesc().c_str());
return;
}
// FSNode can cache its members, thus create it after checkPath to reflect
// actual file system state.
const Common::FSNode savePath(savePathName);
Common::FSList children;
if (!savePath.getChildren(children, Common::FSNode::kListFilesOnly)) {
return;
}
// Build the savefile name cache.
for (Common::FSList::const_iterator file = children.begin(), end = children.end(); file != end; ++file) {
if (_saveFileCache.contains(file->getName())) {
warning("DefaultSaveFileManager::assureCached: Name clash when building cache, ignoring file '%s'", file->getName().c_str());
} else {
_saveFileCache[file->getName()] = *file;
}
}
// Only now store that we cached 'savePathName' to indicate we successfully
// cached the directory.
_cachedDirectory = savePathName;
}
#endif // !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) #endif // !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)

View file

@ -27,6 +27,7 @@
#include "common/savefile.h" #include "common/savefile.h"
#include "common/str.h" #include "common/str.h"
#include "common/fs.h" #include "common/fs.h"
#include "common/hashmap.h"
/** /**
* Provides a default savefile manager implementation for common platforms. * Provides a default savefile manager implementation for common platforms.
@ -54,6 +55,30 @@ protected:
* Sets the internal error and error message accordingly. * Sets the internal error and error message accordingly.
*/ */
virtual void checkPath(const Common::FSNode &dir); virtual void checkPath(const Common::FSNode &dir);
/**
* Assure that the given save path is cached.
*
* @param savePathName String representation of save path to cache.
*/
void assureCached(const Common::String &savePathName);
typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SaveFileCache;
/**
* Cache of all the save files in the currently cached directory.
*
* Modify with caution because we only re-cache when the save path changed!
* This needs to be updated inside at least openForSaving and
* removeSavefile.
*/
SaveFileCache _saveFileCache;
private:
/**
* The currently cached directory.
*/
Common::String _cachedDirectory;
}; };
#endif #endif

View file

@ -21,16 +21,19 @@
*/ */
// Enable getenv, mkdir and time.h stuff // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv // Also with clock() in sys/time.h in some Mac OS X SDKs.
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h //On IRIX, sys/stat.h includes sys/time.h #define FORBIDDEN_SYMBOL_EXCEPTION_time_h //On IRIX, sys/stat.h includes sys/time.h
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
#include "common/scummsys.h" #include "common/scummsys.h"
#if defined(POSIX) && !defined(DISABLE_DEFAULT_SAVEFILEMANAGER) #if defined(POSIX) && !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)
#include "backends/saves/posix/posix-saves.h" #include "backends/saves/posix/posix-saves.h"
#include "backends/fs/posix/posix-fs.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/savefile.h" #include "common/savefile.h"
@ -41,26 +44,70 @@
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef MACOSX
#define DEFAULT_SAVE_PATH "Documents/ResidualVM Savegames"
#else
#define DEFAULT_SAVE_PATH ".residualvm"
#endif
POSIXSaveFileManager::POSIXSaveFileManager() { POSIXSaveFileManager::POSIXSaveFileManager() {
// Register default savepath based on HOME // Register default savepath.
#if defined(SAMSUNGTV) #if defined(SAMSUNGTV)
ConfMan.registerDefault("savepath", "/mtd_wiselink/residualvm savegames"); ConfMan.registerDefault("savepath", "/mtd_wiselink/residualvm savegames");
#else #else
Common::String savePath; Common::String savePath;
#if defined(MACOSX)
const char *home = getenv("HOME"); const char *home = getenv("HOME");
if (home && *home && strlen(home) < MAXPATHLEN) { if (home && *home && strlen(home) < MAXPATHLEN) {
savePath = home; savePath = home;
savePath += "/" DEFAULT_SAVE_PATH; savePath += "/Documents/ResidualVM Savegames";
ConfMan.registerDefault("savepath", savePath); ConfMan.registerDefault("savepath", savePath);
} }
#else
const char *envVar;
// Previously we placed our default savepath in HOME. If the directory
// still exists, we will use it for backwards compatability.
envVar = getenv("HOME");
if (envVar && *envVar) {
savePath = envVar;
savePath += "/.residualvm";
struct stat sb;
if (stat(savePath.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
savePath.clear();
}
}
if (savePath.empty()) {
Common::String prefix;
// On POSIX systems we follow the XDG Base Directory Specification for
// where to store files. The version we based our code upon can be found
// over here: http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
envVar = getenv("XDG_DATA_HOME");
if (!envVar || !*envVar) {
envVar = getenv("HOME");
if (envVar && *envVar) {
prefix = envVar;
savePath = ".local/share/";
}
} else {
prefix = envVar;
}
// Our default save path is '$XDG_DATA_HOME/residualvm/saves'
savePath += "residualvm/saves";
if (!Posix::assureDirectoryExists(savePath, prefix.c_str())) {
savePath.clear();
} else {
savePath = prefix + '/' + savePath;
}
}
if (!savePath.empty() && savePath.size() < MAXPATHLEN) {
ConfMan.registerDefault("savepath", savePath);
}
#endif
// The user can override the savepath with the SCUMMVM_SAVEPATH // The user can override the savepath with the SCUMMVM_SAVEPATH
// environment variable. This is weaker than a --savepath on the // environment variable. This is weaker than a --savepath on the
// command line, but overrides the default savepath. // command line, but overrides the default savepath.

View file

@ -0,0 +1,125 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <Cocoa/Cocoa.h>
@interface ScummVMDockTilePlugIn : NSObject <NSDockTilePlugIn> {
NSMenu *recentGamesMenu;
}
@end
@interface StartGameMenuItem : NSMenuItem {
NSString *game;
}
- (IBAction) startGame;
- (NSMenuItem*)initWithGame:(NSString *)gameId description:(NSString*)desc icon:(NSString*)iconFile;
@end
@implementation ScummVMDockTilePlugIn
- (id)init {
self = [super init];
if (self) {
recentGamesMenu = nil;
}
return self;
}
- (void)dealloc {
[recentGamesMenu release];
[super dealloc];
}
- (void)setDockTile:(NSDockTile *)dockTile {
}
- (NSMenu*)dockMenu {
// Get the list or recent games
CFPreferencesAppSynchronize(CFSTR("org.residualvm.residaulvm"));
NSArray *array = CFPreferencesCopyAppValue(CFSTR("recentGames"), CFSTR("org.residualvm.residualvm"));
if (array == nil)
return nil;
// Create the menu
if (recentGamesMenu == nil)
recentGamesMenu = [[NSMenu alloc] init];
else
[recentGamesMenu removeAllItems];
NSEnumerator *enumerator = [array objectEnumerator];
NSDictionary *recentGame;
while (recentGame = [enumerator nextObject]) {
NSString *gameId = [recentGame valueForKey:@"game"];
NSString *desc = [recentGame valueForKey:@"description"];
NSString *iconFile = [recentGame valueForKey:@"icon"];
StartGameMenuItem *menuItem = [[StartGameMenuItem alloc] initWithGame:gameId description:desc icon:iconFile];
[recentGamesMenu addItem:menuItem];
[menuItem release];
}
return recentGamesMenu;
}
@end
@implementation StartGameMenuItem
- (NSMenuItem*)initWithGame:(NSString *)gameId description:(NSString*)desc icon:(NSString*)iconFile {
self = [super initWithTitle:(desc == nil ? gameId : desc) action:@selector(startGame) keyEquivalent:@""];
[self setTarget:self];
if (iconFile != nil) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:iconFile];
[self setImage:image];
[image release];
}
game = gameId;
[game retain];
return self;
}
- (void)dealloc {
[game release];
[super dealloc];
}
- (IBAction) startGame {
NSLog(@"Starting Game %@...", game);
NSString *scummVMPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:@"org.residualvm.residualvm"];
if (scummVMPath == nil) {
NSLog(@"Cannot find ResidualVM.app!");
return;
}
// Start ScummVM.app with the game ID as argument
NSURL *url = [NSURL fileURLWithPath:scummVMPath];
NSMutableDictionary *args = [[NSMutableDictionary alloc] init];
[args setObject:[NSArray arrayWithObject:game] forKey:NSWorkspaceLaunchConfigurationArguments];
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:url options:NSWorkspaceLaunchDefault configuration:args error:nil];
[args release];
}
@end

View file

@ -37,6 +37,7 @@ public:
virtual void setProgressValue(int completed, int total); virtual void setProgressValue(int completed, int total);
virtual void setProgressState(TaskbarProgressState state); virtual void setProgressState(TaskbarProgressState state);
virtual void setCount(int count); virtual void setCount(int count);
virtual void addRecent(const Common::String &name, const Common::String &description);
virtual void notifyError(); virtual void notifyError();
virtual void clearError(); virtual void clearError();

View file

@ -29,9 +29,6 @@
// NSDockTile was introduced with Mac OS X 10.5. // NSDockTile was introduced with Mac OS X 10.5.
// Try provide backward compatibility by avoiding NSDockTile symbols. // Try provide backward compatibility by avoiding NSDockTile symbols.
// TODO: Implement recent list, maybe as a custom menu on dock tile when app is not running
// See Dock Tile plug-in at https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/CreatingaDockTilePlug-in/CreatingaDockTilePlug-in.html
#include "backends/taskbar/macosx/macosx-taskbar.h" #include "backends/taskbar/macosx/macosx-taskbar.h"
#include "common/config-manager.h" #include "common/config-manager.h"
#include "common/file.h" #include "common/file.h"
@ -39,6 +36,9 @@
#include <AppKit/NSApplication.h> #include <AppKit/NSApplication.h>
#include <AppKit/NSImage.h> #include <AppKit/NSImage.h>
#include <Foundation/NSString.h> #include <Foundation/NSString.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSUserDefaults.h>
#include <AppKit/NSImageView.h> #include <AppKit/NSImageView.h>
#include <AppKit/NSColor.h> #include <AppKit/NSColor.h>
#include <AppKit/NSBezierPath.h> #include <AppKit/NSBezierPath.h>
@ -120,7 +120,7 @@ void MacOSXTaskbarManager::setOverlayIcon(const Common::String &name, const Comm
initOverlayIconView(); initOverlayIconView();
CFStringRef imageFile = CFStringCreateWithCString(0, path.c_str(), kCFStringEncodingASCII); CFStringRef imageFile = CFStringCreateWithCString(0, path.c_str(), kCFStringEncodingASCII);
NSImage* image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile]; NSImage *image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile];
[_overlayIconView setImage:image]; [_overlayIconView setImage:image];
[image release]; [image release];
CFRelease(imageFile); CFRelease(imageFile);
@ -234,5 +234,64 @@ return (path); \
return ""; return "";
} }
void MacOSXTaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
//warning("[MacOSXTaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
if (_dockTile == nil)
return;
// Store the game, description and icon in user preferences.
// The NSDockTilePlugin will retrieve them there to list them in the dock tile menu.
CFStringRef gameName = CFStringCreateWithCString(0, name.c_str(), kCFStringEncodingASCII);
CFStringRef desc = CFStringCreateWithCString(0, description.c_str(), kCFStringEncodingASCII);
// First build the dictionary for this game.
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:(NSString *)gameName forKey:@"game"];
[dict setObject:(NSString *)desc forKey:@"description"];
// Icon
Common::String iconPath = getIconPath(name);
if (!iconPath.empty()) {
CFStringRef icon = CFStringCreateWithCString(0, iconPath.c_str(), kCFStringEncodingASCII);
[dict setObject:(NSString *)icon forKey:@"icon"];
CFRelease(icon);
}
// Retrieve the current list of recent items and update it.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *oldArray = [defaults arrayForKey:@"recentGames"];
if (oldArray == nil) {
[defaults setObject:[NSArray arrayWithObject:dict] forKey:@"recentGames"];
} else {
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray];
// Insert the new game at the start
[newArray insertObject:dict atIndex:0];
// If the game was already present in the array, remove it
for (unsigned int i = 1 ; i < [newArray count] ; ++i) {
NSDictionary *oldDict = [newArray objectAtIndex:i];
if (oldDict == nil)
continue;
NSString *oldGame = [oldDict valueForKey:@"game"];
if (oldGame != nil && [oldGame isEqualToString:(NSString*)gameName]) {
[newArray removeObjectAtIndex:i];
break;
}
}
// And make sure we limit the size of the array to 5 games
if ([newArray count] > 5)
[newArray removeLastObject];
[defaults setObject:newArray forKey:@"recentGames"];
[newArray release];
}
// Finally release the dictionary
[dict release];
CFRelease(gameName);
CFRelease(desc);
}
#endif #endif

View file

@ -28,8 +28,22 @@
#if defined(WIN32) && defined(USE_TASKBAR) #if defined(WIN32) && defined(USE_TASKBAR)
// HACK: To get __MINGW64_VERSION_foo defines we need to manually include
// _mingw.h in this file because we do not include any system headers at this
// point on purpose. The defines are required to detect whether this is a
// classic MinGW toolchain or a MinGW-w64 based one.
#if defined(__MINGW32__)
#include <_mingw.h>
#endif
// Needed for taskbar functions // Needed for taskbar functions
#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64__) // HACK: MinGW-w64 based toolchains include the symbols we require in their
// headers. The 32 bit incarnation only defines __MINGW32__. This leads to
// build breakage due to clashes with our compat header. Luckily MinGW-w64
// based toolchains define __MINGW64_VERSION_foo macros inside _mingw.h,
// which is included from all system headers. Thus we abuse that to detect
// them.
#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#include "backends/taskbar/win32/mingw-compat.h" #include "backends/taskbar/win32/mingw-compat.h"
#else #else
// We use functionality introduced with Win7 in this file. // We use functionality introduced with Win7 in this file.
@ -71,7 +85,7 @@ const PROPERTYKEY PKEY_Title = { /* fmtid = */ { 0xF29F85E0, 0x4FF9, 0x1068, { 0
Win32TaskbarManager::Win32TaskbarManager(SdlWindow *window) : _window(window), _taskbar(NULL), _count(0), _icon(NULL) { Win32TaskbarManager::Win32TaskbarManager(SdlWindow *window) : _window(window), _taskbar(NULL), _count(0), _icon(NULL) {
// Do nothing if not running on Windows 7 or later // Do nothing if not running on Windows 7 or later
if (!isWin7OrLater()) if (!confirmWindowsVersion(10, 0) && !confirmWindowsVersion(6, 1))
return; return;
CoInitialize(NULL); CoInitialize(NULL);
@ -386,14 +400,14 @@ BOOL VerifyVersionInfoFunc(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwType
return verifyVersionInfo(lpVersionInformation, dwTypeMask, dwlConditionMask); return verifyVersionInfo(lpVersionInformation, dwTypeMask, dwlConditionMask);
} }
bool Win32TaskbarManager::isWin7OrLater() { bool Win32TaskbarManager::confirmWindowsVersion(uint majorVersion, uint minorVersion) {
OSVERSIONINFOEX versionInfo; OSVERSIONINFOEX versionInfo;
DWORDLONG conditionMask = 0; DWORDLONG conditionMask = 0;
ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX)); ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
versionInfo.dwMajorVersion = 6; versionInfo.dwMajorVersion = majorVersion;
versionInfo.dwMinorVersion = 1; versionInfo.dwMinorVersion = minorVersion;
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);

View file

@ -64,7 +64,7 @@ private:
Common::String getIconPath(Common::String target); Common::String getIconPath(Common::String target);
// Helper functions // Helper functions
bool isWin7OrLater(); bool confirmWindowsVersion(uint majorVersion, uint minorVersion);
LPWSTR ansiToUnicode(const char *s); LPWSTR ansiToUnicode(const char *s);
HWND getHwnd(); HWND getHwnd();
}; };

View file

@ -39,8 +39,10 @@ public:
virtual void setAutomaticallyChecksForUpdates(UpdateState state); virtual void setAutomaticallyChecksForUpdates(UpdateState state);
virtual UpdateState getAutomaticallyChecksForUpdates(); virtual UpdateState getAutomaticallyChecksForUpdates();
virtual void setUpdateCheckInterval(UpdateInterval interval); virtual void setUpdateCheckInterval(int interval);
virtual UpdateInterval getUpdateCheckInterval(); virtual int getUpdateCheckInterval();
virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t);
}; };
#endif #endif

View file

@ -23,14 +23,18 @@
// Disable symbol overrides so that we can use system headers. // Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL #define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/system.h"
#include "backends/updates/macosx/macosx-updates.h" #include "backends/updates/macosx/macosx-updates.h"
#ifdef USE_SPARKLE #ifdef USE_SPARKLE
#include "common/translation.h" #include "common/translation.h"
#include "common/config-manager.h"
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h> #include <Sparkle/Sparkle.h>
#include <AvailabilityMacros.h>
SUUpdater *sparkleUpdater; SUUpdater *sparkleUpdater;
/** /**
@ -45,14 +49,22 @@ SUUpdater *sparkleUpdater;
* *
*/ */
MacOSXUpdateManager::MacOSXUpdateManager() { MacOSXUpdateManager::MacOSXUpdateManager() {
NSBundle* mainBundle = [NSBundle mainBundle];
NSString *version = [mainBundle objectForInfoDictionaryKey:(__bridge NSString *)kCFBundleVersionKey];
if (!version || [version isEqualToString:@""]) {
warning("Running not in bundle, skipping Sparkle initialization");
sparkleUpdater = nullptr;
return;
}
NSMenuItem *menuItem = [[NSApp mainMenu] itemAtIndex:0]; NSMenuItem *menuItem = [[NSApp mainMenu] itemAtIndex:0];
NSMenu *applicationMenu = [menuItem submenu]; NSMenu *applicationMenu = [menuItem submenu];
// Init Sparkle // Init Sparkle
sparkleUpdater = [SUUpdater sharedUpdater]; sparkleUpdater = [SUUpdater sharedUpdater];
NSBundle* mainBundle = [NSBundle mainBundle];
NSString* feedbackURL = [mainBundle objectForInfoDictionaryKey:@"SUFeedURL"]; NSString* feedbackURL = [mainBundle objectForInfoDictionaryKey:@"SUFeedURL"];
// Set appcast URL // Set appcast URL
@ -74,11 +86,13 @@ MacOSXUpdateManager::MacOSXUpdateManager() {
// Finally give up our references to the objects // Finally give up our references to the objects
[menuItem release]; [menuItem release];
// Enable automatic update checking once a day (alternatively use if (!ConfMan.hasKey("updates_check")
// checkForUpdates() here to check for updates on every startup) || ConfMan.getInt("updates_check") == Common::UpdateManager::kUpdateIntervalNotSupported) {
// TODO: Should be removed when an update settings gui is implemented setAutomaticallyChecksForUpdates(kUpdateStateDisabled);
setAutomaticallyChecksForUpdates(kUpdateStateEnabled); } else {
setUpdateCheckInterval(kUpdateIntervalOneDay); setAutomaticallyChecksForUpdates(kUpdateStateEnabled);
setUpdateCheckInterval(normalizeInterval(ConfMan.getInt("updates_check")));
}
} }
MacOSXUpdateManager::~MacOSXUpdateManager() { MacOSXUpdateManager::~MacOSXUpdateManager() {
@ -86,6 +100,9 @@ MacOSXUpdateManager::~MacOSXUpdateManager() {
} }
void MacOSXUpdateManager::checkForUpdates() { void MacOSXUpdateManager::checkForUpdates() {
if (sparkleUpdater == nullptr)
return;
[sparkleUpdater checkForUpdatesInBackground]; [sparkleUpdater checkForUpdatesInBackground];
} }
@ -93,24 +110,38 @@ void MacOSXUpdateManager::setAutomaticallyChecksForUpdates(UpdateManager::Update
if (state == kUpdateStateNotSupported) if (state == kUpdateStateNotSupported)
return; return;
if (sparkleUpdater == nullptr)
return;
[sparkleUpdater setAutomaticallyChecksForUpdates:(state == kUpdateStateEnabled ? YES : NO)]; [sparkleUpdater setAutomaticallyChecksForUpdates:(state == kUpdateStateEnabled ? YES : NO)];
} }
Common::UpdateManager::UpdateState MacOSXUpdateManager::getAutomaticallyChecksForUpdates() { Common::UpdateManager::UpdateState MacOSXUpdateManager::getAutomaticallyChecksForUpdates() {
if (sparkleUpdater == nullptr)
return kUpdateStateDisabled;
if ([sparkleUpdater automaticallyChecksForUpdates]) if ([sparkleUpdater automaticallyChecksForUpdates])
return kUpdateStateEnabled; return kUpdateStateEnabled;
else else
return kUpdateStateDisabled; return kUpdateStateDisabled;
} }
void MacOSXUpdateManager::setUpdateCheckInterval(UpdateInterval interval) { void MacOSXUpdateManager::setUpdateCheckInterval(int interval) {
if (sparkleUpdater == nullptr)
return;
if (interval == kUpdateIntervalNotSupported) if (interval == kUpdateIntervalNotSupported)
return; return;
interval = normalizeInterval(interval);
[sparkleUpdater setUpdateCheckInterval:(NSTimeInterval)interval]; [sparkleUpdater setUpdateCheckInterval:(NSTimeInterval)interval];
} }
Common::UpdateManager::UpdateInterval MacOSXUpdateManager::getUpdateCheckInterval() { int MacOSXUpdateManager::getUpdateCheckInterval() {
if (sparkleUpdater == nullptr)
return kUpdateIntervalOneDay;
// This is kind of a hack but necessary, as the value stored by Sparkle // This is kind of a hack but necessary, as the value stored by Sparkle
// might have been changed outside of ScummVM (in which case we return the // might have been changed outside of ScummVM (in which case we return the
// default interval of one day) // default interval of one day)
@ -128,4 +159,30 @@ Common::UpdateManager::UpdateInterval MacOSXUpdateManager::getUpdateCheckInterva
} }
} }
bool MacOSXUpdateManager::getLastUpdateCheckTimeAndDate(TimeDate &t) {
if (sparkleUpdater == nullptr)
return false;
NSDate *date = [sparkleUpdater lastUpdateCheckDate];
#ifdef MAC_OS_X_VERSION_10_10
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorian components:(NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:date];
#else
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date];
#endif
t.tm_wday = [components weekday];
t.tm_year = [components year];
t.tm_mon = [components month];
t.tm_mday = [components day];
t.tm_hour = [components hour];
t.tm_min = [components minute];
t.tm_sec = [components second];
[gregorian release];
return true;
}
#endif #endif

View file

@ -0,0 +1,132 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "common/system.h"
#include "backends/updates/win32/win32-updates.h"
#ifdef USE_SPARKLE
#include "common/translation.h"
#include "common/config-manager.h"
#include <time.h>
#include <winsparkle.h>
/**
* Sparkle is a software update framework for Mac OS X which uses appcasts for
* release information. Appcasts are RSS-like XML feeds which contain information
* about the most current version at the time. If a new version is available, the
* user is presented the release-notes/changes/fixes and is asked if he wants to
* update, and if yes the Sparkle framework downloads a signed update package
* from the server and automatically installs and restarts the software.
* More detailed information is available at the following address:
* http://sparkle.andymatuschak.org/
*
* WinSparkle is a heavily (to the point of being its almost-port) inspired by the
* Sparkle framework originally by Andy Matuschak that became the de facto standard
* for software updates on OS X.
* More detailed information is available at the following address:
* https://winsparkle.org/
*
*/
Win32UpdateManager::Win32UpdateManager() {
const char *appcastUrl = "https://www.residualvm.org/appcasts/macosx/release.xml";
win_sparkle_set_appcast_url(appcastUrl);
win_sparkle_init();
if (!ConfMan.hasKey("updates_check")
|| ConfMan.getInt("updates_check") == Common::UpdateManager::kUpdateIntervalNotSupported) {
setAutomaticallyChecksForUpdates(kUpdateStateDisabled);
} else {
setAutomaticallyChecksForUpdates(kUpdateStateEnabled);
setUpdateCheckInterval(normalizeInterval(ConfMan.getInt("updates_check")));
}
}
Win32UpdateManager::~Win32UpdateManager() {
win_sparkle_cleanup();
}
void Win32UpdateManager::checkForUpdates() {
win_sparkle_check_update_with_ui();
}
void Win32UpdateManager::setAutomaticallyChecksForUpdates(UpdateManager::UpdateState state) {
if (state == kUpdateStateNotSupported)
return;
win_sparkle_set_automatic_check_for_updates(state == kUpdateStateEnabled ? 1 : 0);
}
Common::UpdateManager::UpdateState Win32UpdateManager::getAutomaticallyChecksForUpdates() {
if (win_sparkle_get_automatic_check_for_updates() == 1)
return kUpdateStateEnabled;
else
return kUpdateStateDisabled;
}
void Win32UpdateManager::setUpdateCheckInterval(int interval) {
if (interval == kUpdateIntervalNotSupported)
return;
interval = normalizeInterval(interval);
win_sparkle_set_update_check_interval(interval);
}
int Win32UpdateManager::getUpdateCheckInterval() {
// This is kind of a hack but necessary, as the value stored by Sparkle
// might have been changed outside of ScummVM (in which case we return the
// default interval of one day)
int updateInterval = win_sparkle_get_update_check_interval();
switch (updateInterval) {
case kUpdateIntervalOneDay:
case kUpdateIntervalOneWeek:
case kUpdateIntervalOneMonth:
return updateInterval;
default:
// Return the default value (one day)
return kUpdateIntervalOneDay;
}
}
bool Win32UpdateManager::getLastUpdateCheckTimeAndDate(TimeDate &t) {
time_t updateTime = win_sparkle_get_last_check_time();
tm *ut = localtime(&updateTime);
t.tm_wday = ut->tm_wday;
t.tm_year = ut->tm_year;
t.tm_mon = ut->tm_mon;
t.tm_mday = ut->tm_mday;
t.tm_hour = ut->tm_hour;
t.tm_min = ut->tm_min;
t.tm_sec = ut->tm_sec;
return true;
}
#endif

View file

@ -0,0 +1,50 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_UPDATES_WIN32_H
#define BACKENDS_UPDATES_WIN32_H
#include "common/scummsys.h"
#if defined(WIN32) && defined(USE_SPARKLE)
#include "common/updates.h"
class Win32UpdateManager : public Common::UpdateManager {
public:
Win32UpdateManager();
virtual ~Win32UpdateManager();
virtual void checkForUpdates();
virtual void setAutomaticallyChecksForUpdates(UpdateState state);
virtual UpdateState getAutomaticallyChecksForUpdates();
virtual void setUpdateCheckInterval(int interval);
virtual int getUpdateCheckInterval();
virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t);
};
#endif
#endif // BACKENDS_UPDATES_WIN32_H

View file

@ -42,7 +42,7 @@
#include "audio/musicplugin.h" #include "audio/musicplugin.h"
#include "graphics/renderer.h" #include "graphics/renderer.h" // ResidualVM
#define DETECTOR_TESTING_HACK #define DETECTOR_TESTING_HACK
#define UPGRADE_ALL_TARGETS_HACK #define UPGRADE_ALL_TARGETS_HACK
@ -59,7 +59,7 @@ static const char USAGE_STRING[] =
; ;
// DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :) // DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :)
#if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__) #if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__) || defined(__3DS__)
static const char HELP_STRING[] = "NoUsageString"; // save more data segment space static const char HELP_STRING[] = "NoUsageString"; // save more data segment space
#else #else
static const char HELP_STRING[] = static const char HELP_STRING[] =
@ -99,8 +99,9 @@ static const char HELP_STRING[] =
" -u, --dump-scripts Enable script dumping if a directory called 'dumps'\n" " -u, --dump-scripts Enable script dumping if a directory called 'dumps'\n"
" exists in the current directory\n" " exists in the current directory\n"
"\n" "\n"
" --cdrom=NUM CD drive to play CD audio from (default: 0 = first\n" " --cdrom=DRIVE CD drive to play CD audio from; can either be a\n"
" drive)\n" " drive, path, or numeric index (default: 0 = best\n"
" choice drive)\n"
" --joystick[=NUM] Enable joystick input (default: 0 = first joystick)\n" " --joystick[=NUM] Enable joystick input (default: 0 = first joystick)\n"
" --platform=WORD Specify platform of game (allowed values: 2gs, 3do,\n" " --platform=WORD Specify platform of game (allowed values: 2gs, 3do,\n"
" acorn, amiga, atari, c64, fmtowns, nes, mac, pc, pc98,\n" " acorn, amiga, atari, c64, fmtowns, nes, mac, pc, pc98,\n"
@ -339,6 +340,12 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
// We defer checking whether this is a valid target to a later point. // We defer checking whether this is a valid target to a later point.
return s; return s;
} else { } else {
// On MacOS X prior to 10.9 the OS is sometimes adding a -psn_X_XXXXXX argument (where X are digits)
// to pass the process serial number. We need to ignore it to avoid an error.
#ifdef MACOSX
if (strncmp(s, "-psn_", 5) == 0)
continue;
#endif
bool isLongCmd = (s[0] == '-' && s[1] == '-'); bool isLongCmd = (s[0] == '-' && s[1] == '-');
@ -489,7 +496,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
DO_LONG_OPTION("gamma") DO_LONG_OPTION("gamma")
END_OPTION END_OPTION
// ResidualVM specific start
DO_LONG_OPTION("renderer") DO_LONG_OPTION("renderer")
Graphics::RendererType renderer = Graphics::parseRendererTypeCode(option); Graphics::RendererType renderer = Graphics::parseRendererTypeCode(option);
if (renderer == Graphics::kRendererTypeDefault) if (renderer == Graphics::kRendererTypeDefault)
@ -497,6 +504,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
END_OPTION END_OPTION
DO_LONG_OPTION_BOOL("show-fps") DO_LONG_OPTION_BOOL("show-fps")
// ResidualVM specific end
END_OPTION END_OPTION
DO_LONG_OPTION("savepath") DO_LONG_OPTION("savepath")

View file

@ -75,6 +75,9 @@
#include "gui/launcher.h" #include "gui/launcher.h"
#endif #endif
#ifdef USE_UPDATES
#include "gui/updates-dialog.h"
#endif
static bool launcherDialog() { static bool launcherDialog() {
@ -134,9 +137,26 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
Common::Error err = Common::kNoError; Common::Error err = Common::kNoError;
Engine *engine = 0; Engine *engine = 0;
// Disabled in ResidualVM:
#if 0//defined(SDL_BACKEND) && defined(USE_OPENGL) && defined(USE_RGB_COLOR)
// HACK: We set up the requested graphics mode setting here to allow the
// backend to switch from Surface SDL to OpenGL if necessary. This is
// needed because otherwise the g_system->getSupportedFormats might return
// bad values.
g_system->beginGFXTransaction();
g_system->setGraphicsMode(ConfMan.get("gfx_mode").c_str());
if (g_system->endGFXTransaction() != OSystem::kTransactionSuccess) {
warning("Switching graphics mode to '%s' failed", ConfMan.get("gfx_mode").c_str());
return Common::kUnknownError;
}
#endif
// Verify that the game path refers to an actual directory // Verify that the game path refers to an actual directory
if (!(dir.exists() && dir.isDirectory())) if (!dir.exists()) {
err = Common::kPathDoesNotExist;
} else if (!dir.isDirectory()) {
err = Common::kPathNotDirectory; err = Common::kPathNotDirectory;
}
// Create the game engine // Create the game engine
if (err.getCode() == Common::kNoError) { if (err.getCode() == Common::kNoError) {
@ -370,7 +390,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
if (settings.contains("debugflags")) { if (settings.contains("debugflags")) {
specialDebug = settings["debugflags"]; specialDebug = settings["debugflags"];
settings.erase("debugflags"); settings.erase("debugflags");
} } else if (ConfMan.hasKey("debugflags"))
specialDebug = ConfMan.get("debugflags");
PluginManager::instance().init(); PluginManager::instance().init();
PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager
@ -446,6 +467,13 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// Now as the event manager is created, setup the keymapper // Now as the event manager is created, setup the keymapper
setupKeymapper(system); setupKeymapper(system);
#ifdef USE_UPDATES
if (!ConfMan.hasKey("updates_check")) {
GUI::UpdatesDialog dlg;
dlg.runModal();
}
#endif
// Unless a game was specified, show the launcher dialog // Unless a game was specified, show the launcher dialog
if (0 == ConfMan.getActiveDomain()) if (0 == ConfMan.getActiveDomain())
launcherDialog(); launcherDialog();

View file

@ -141,9 +141,6 @@ public:
#if defined(USE_TIMIDITY) #if defined(USE_TIMIDITY)
LINK_PLUGIN(TIMIDITY) LINK_PLUGIN(TIMIDITY)
#endif #endif
#if PLUGIN_ENABLED_STATIC(STARK)
LINK_PLUGIN(STARK)
#endif
return pl; return pl;
} }

View file

@ -51,7 +51,7 @@
* header file, analog to internal_version.h, maybe called svn_rev.h or so.) * header file, analog to internal_version.h, maybe called svn_rev.h or so.)
* *
* Drawback: This only works on systems which can run suitable scripts as part * Drawback: This only works on systems which can run suitable scripts as part
* of the build proces (so I guess Visual C++ would be out of the game here? * of the build process (so I guess Visual C++ would be out of the game here?
* I don't know VC enough to be sure). And of course it must be robust enough * I don't know VC enough to be sure). And of course it must be robust enough
* to properly work in exports (i.e. release tar balls etc.). * to properly work in exports (i.e. release tar balls etc.).
*/ */

View file

@ -270,5 +270,26 @@ T gcd(T a, T b) {
#pragma warning(pop) #pragma warning(pop)
#endif #endif
/**
* Replacement algorithm for iterables.
*
* Replaces all occurrences of "original" in [begin, end) with occurrences of "replaced".
*
* @param[in, out] begin: First element to be examined.
* @param[in] end: Last element in the seubsection. Not examined.
* @param[in] original: Elements to be replaced.
* @param[in] replaced: Element to replace occurrences of "original".
*
* @note Usage examples and unit tests may be found in "test/common/algorithm.h"
*/
template<class It, class Dat>
void replace(It begin, It end, const Dat &original, const Dat &replaced) {
for (; begin != end; ++begin) {
if (*begin == original) {
*begin = replaced;
}
}
}
} // End of namespace Common } // End of namespace Common
#endif #endif

View file

@ -48,7 +48,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
int matches = 0; int matches = 0;
ArchiveMemberList::const_iterator it = allNames.begin(); ArchiveMemberList::const_iterator it = allNames.begin();
for ( ; it != allNames.end(); ++it) { for (; it != allNames.end(); ++it) {
// TODO: We match case-insenstivie for now, our API does not define whether that's ok or not though... // TODO: We match case-insenstivie for now, our API does not define whether that's ok or not though...
// For our use case case-insensitive is probably what we want to have though. // For our use case case-insensitive is probably what we want to have though.
if ((*it)->getName().matchString(pattern, true, true)) { if ((*it)->getName().matchString(pattern, true, true)) {
@ -64,7 +64,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) { SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) {
ArchiveNodeList::iterator it = _list.begin(); ArchiveNodeList::iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
if (it->_name == name) if (it->_name == name)
break; break;
} }
@ -73,7 +73,7 @@ SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) {
SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) const { SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) const {
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
if (it->_name == name) if (it->_name == name)
break; break;
} }
@ -81,13 +81,13 @@ SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) c
} }
/* /*
Keep the nodes sorted according to descending priorities. Keep the nodes sorted according to descending priorities.
In case two or node nodes have the same priority, insertion In case two or node nodes have the same priority, insertion
order prevails. order prevails.
*/ */
void SearchSet::insert(const Node &node) { void SearchSet::insert(const Node &node) {
ArchiveNodeList::iterator it = _list.begin(); ArchiveNodeList::iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
if (it->_priority < node._priority) if (it->_priority < node._priority)
break; break;
} }
@ -131,8 +131,7 @@ void SearchSet::addSubDirectoriesMatching(const FSNode &directory, String origPa
++sep; ++sep;
if (sep != origPattern.end()) if (sep != origPattern.end())
nextPattern = String(sep, origPattern.end()); nextPattern = String(sep, origPattern.end());
} } else {
else {
pattern = origPattern; pattern = origPattern;
} }
@ -211,7 +210,7 @@ bool SearchSet::hasFile(const String &name) const {
return false; return false;
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
if (it->_arc->hasFile(name)) if (it->_arc->hasFile(name))
return true; return true;
} }
@ -223,7 +222,7 @@ int SearchSet::listMatchingMembers(ArchiveMemberList &list, const String &patter
int matches = 0; int matches = 0;
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) for (; it != _list.end(); ++it)
matches += it->_arc->listMatchingMembers(list, pattern); matches += it->_arc->listMatchingMembers(list, pattern);
return matches; return matches;
@ -233,7 +232,7 @@ int SearchSet::listMembers(ArchiveMemberList &list) const {
int matches = 0; int matches = 0;
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) for (; it != _list.end(); ++it)
matches += it->_arc->listMembers(list); matches += it->_arc->listMembers(list);
return matches; return matches;
@ -244,7 +243,7 @@ const ArchiveMemberPtr SearchSet::getMember(const String &name) const {
return ArchiveMemberPtr(); return ArchiveMemberPtr();
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
if (it->_arc->hasFile(name)) if (it->_arc->hasFile(name))
return it->_arc->getMember(name); return it->_arc->getMember(name);
} }
@ -257,7 +256,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con
return 0; return 0;
ArchiveNodeList::const_iterator it = _list.begin(); ArchiveNodeList::const_iterator it = _list.begin();
for ( ; it != _list.end(); ++it) { for (; it != _list.end(); ++it) {
SeekableReadStream *stream = it->_arc->createReadStreamForMember(name); SeekableReadStream *stream = it->_arc->createReadStreamForMember(name);
if (stream) if (stream)
return stream; return stream;
@ -268,7 +267,7 @@ SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) con
SearchManager::SearchManager() { SearchManager::SearchManager() {
clear(); // Force a reset clear(); // Force a reset
} }
void SearchManager::clear() { void SearchManager::clear() {

View file

@ -141,6 +141,12 @@ public:
insert_aux(_storage + idx, array.begin(), array.end()); insert_aux(_storage + idx, array.begin(), array.end());
} }
/**
* Inserts element before pos.
*/
void insert(iterator pos, const T &element) {
insert_aux(pos, &element, &element + 1);
}
T remove_at(size_type idx) { T remove_at(size_type idx) {
assert(idx < _size); assert(idx < _size);
@ -187,6 +193,14 @@ public:
_capacity = 0; _capacity = 0;
} }
iterator erase(iterator pos) {
copy(pos + 1, _storage + _size, pos);
_size--;
// We also need to destroy the last object properly here.
_storage[_size].~T();
return pos;
}
bool empty() const { bool empty() const {
return (_size == 0); return (_size == 0);
} }
@ -347,6 +361,87 @@ protected:
}; };
/**
* Double linked list with sorted nodes.
*/
template<class T>
class SortedArray : public Array<T> {
public:
typedef T *iterator;
typedef uint size_type;
SortedArray(int (*comparator)(const void *, const void *)) {
_comparator = comparator;
}
/**
* Inserts element at the sorted position.
*/
void insert(const T &element) {
if (!this->_size) {
this->insert_aux(this->_storage, &element, &element + 1);
return;
}
T *where = bsearchMin(element);
if (where > this->_storage + this->_size)
Array<T>::push_back(element);
else
Array<T>::insert(where, element);
}
T &operator[](size_type idx) {
error("Operation []= not allowed with SortedArray");
}
void insert_at(size_type idx, const T &element) {
error("Operation insert_at(idx, element) not allowed with SortedArray");
}
void insert_at(size_type idx, const Array<T> &array) {
error("Operation insert_at(idx, array) not allowed with SortedArray");
}
void insert(iterator pos, const T &element) {
error("Operation insert(pos, elemnet) not allowed with SortedArray");
}
void push_back(const T &element) {
error("Operation push_back(element) not allowed with SortedArray");
}
void push_back(const Array<T> &array) {
error("Operation push_back(array) not allowed with SortedArray");
}
private:
// Based on code Copyright (C) 2008-2009 Ksplice, Inc.
// Author: Tim Abbott <tabbott@ksplice.com>
// Licensed under GPLv2+
T *bsearchMin(void *key) {
uint start_ = 0, end_ = this->_size;
int result;
while (start_ < end_) {
uint mid = start_ + (end_ - start_) / 2;
result = this->_comparator(key, this->_storage[mid]);
if (result < 0)
end_ = mid;
else if (result > 0)
start_ = mid + 1;
else
return &this->_storage[mid];
}
return &this->_storage[start_];
}
private:
int (*_comparator)(const void *, const void *);
};
} // End of namespace Common } // End of namespace Common
#endif #endif

View file

@ -470,7 +470,7 @@ bool decompressDCL(ReadStream *src, byte *dest, uint32 packedSize, uint32 unpack
// Read source into memory // Read source into memory
src->read(sourceBufferPtr, packedSize); src->read(sourceBufferPtr, packedSize);
Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::NO); Common::MemoryReadStream *sourceStream = new MemoryReadStream(sourceBufferPtr, packedSize, DisposeAfterUse::YES);
Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize); Common::MemoryWriteStream *targetStream = new MemoryWriteStream(dest, unpackedSize);
success = dcl.unpack(sourceStream, targetStream, unpackedSize, true); success = dcl.unpack(sourceStream, targetStream, unpackedSize, true);

View file

@ -64,6 +64,7 @@ const struct GameOpt {
{ GUIO_RENDERPC9801, "pc9801" }, { GUIO_RENDERPC9801, "pc9801" },
{ GUIO_RENDERAPPLE2GS, "2gs" }, { GUIO_RENDERAPPLE2GS, "2gs" },
{ GUIO_RENDERATARIST, "atari" }, { GUIO_RENDERATARIST, "atari" },
{ GUIO_RENDERMACINTOSH, "macintosh" },
{ GUIO_GAMEOPTIONS1, "gameOption1" }, { GUIO_GAMEOPTIONS1, "gameOption1" },
{ GUIO_GAMEOPTIONS2, "gameOption2" }, { GUIO_GAMEOPTIONS2, "gameOption2" },
@ -73,6 +74,7 @@ const struct GameOpt {
{ GUIO_GAMEOPTIONS6, "gameOption6" }, { GUIO_GAMEOPTIONS6, "gameOption6" },
{ GUIO_GAMEOPTIONS7, "gameOption7" }, { GUIO_GAMEOPTIONS7, "gameOption7" },
{ GUIO_GAMEOPTIONS8, "gameOption8" }, { GUIO_GAMEOPTIONS8, "gameOption8" },
{ GUIO_GAMEOPTIONS9, "gameOption9" },
{ GUIO_NONE, 0 } { GUIO_NONE, 0 }
}; };

View file

@ -56,6 +56,7 @@
#define GUIO_RENDERPC9801 "\040" #define GUIO_RENDERPC9801 "\040"
#define GUIO_RENDERAPPLE2GS "\041" #define GUIO_RENDERAPPLE2GS "\041"
#define GUIO_RENDERATARIST "\042" #define GUIO_RENDERATARIST "\042"
#define GUIO_RENDERMACINTOSH "\043"
// Special GUIO flags for the AdvancedDetector's caching of game specific // Special GUIO flags for the AdvancedDetector's caching of game specific
// options. // options.
@ -67,6 +68,7 @@
#define GUIO_GAMEOPTIONS6 "\055" #define GUIO_GAMEOPTIONS6 "\055"
#define GUIO_GAMEOPTIONS7 "\056" #define GUIO_GAMEOPTIONS7 "\056"
#define GUIO_GAMEOPTIONS8 "\057" #define GUIO_GAMEOPTIONS8 "\057"
#define GUIO_GAMEOPTIONS9 "\058"
#define GUIO0() (GUIO_NONE) #define GUIO0() (GUIO_NONE)
#define GUIO1(a) (a) #define GUIO1(a) (a)

View file

@ -29,6 +29,7 @@
#include "common/md5.h" #include "common/md5.h"
#include "common/substream.h" #include "common/substream.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "common/archive.h"
#ifdef MACOSX #ifdef MACOSX
#include "common/config-manager.h" #include "common/config-manager.h"
@ -261,6 +262,76 @@ bool MacResManager::exists(const String &fileName) {
return false; return false;
} }
void MacResManager::listFiles(StringArray &files, const String &pattern) {
// Base names discovered so far.
typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> BaseNameSet;
BaseNameSet baseNames;
// List files itself.
ArchiveMemberList memberList;
SearchMan.listMatchingMembers(memberList, pattern);
SearchMan.listMatchingMembers(memberList, pattern + ".rsrc");
SearchMan.listMatchingMembers(memberList, pattern + ".bin");
SearchMan.listMatchingMembers(memberList, constructAppleDoubleName(pattern));
for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) {
String filename = (*i)->getName();
// For raw resource forks and MacBinary files we strip the extension
// here to obtain a valid base name.
int lastDotPos = filename.size() - 1;
for (; lastDotPos >= 0; --lastDotPos) {
if (filename[lastDotPos] == '.') {
break;
}
}
if (lastDotPos != -1) {
const char *extension = filename.c_str() + lastDotPos + 1;
bool removeExtension = false;
// TODO: Should we really keep filenames suggesting raw resource
// forks or MacBinary files but not being such around? This might
// depend on the pattern the client requests...
if (!scumm_stricmp(extension, "rsrc")) {
SeekableReadStream *stream = (*i)->createReadStream();
removeExtension = stream && isRawFork(*stream);
delete stream;
} else if (!scumm_stricmp(extension, "bin")) {
SeekableReadStream *stream = (*i)->createReadStream();
removeExtension = stream && isMacBinary(*stream);
delete stream;
}
if (removeExtension) {
filename.erase(lastDotPos);
}
}
// Strip AppleDouble '._' prefix if applicable.
bool isAppleDoubleName = false;
const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName);
if (isAppleDoubleName) {
SeekableReadStream *stream = (*i)->createReadStream();
if (stream->readUint32BE() == 0x00051607) {
filename = filenameAppleDoubleStripped;
}
// TODO: Should we really keep filenames suggesting AppleDouble
// but not being AppleDouble around? This might depend on the
// pattern the client requests...
delete stream;
}
baseNames[filename] = true;
}
// Append resulting base names to list to indicate found files.
for (BaseNameSet::const_iterator i = baseNames.begin(), end = baseNames.end(); i != end; ++i) {
files.push_back(i->_key);
}
}
bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) { bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) {
if (stream.readUint32BE() != 0x00051607) // tag if (stream.readUint32BE() != 0x00051607) // tag
return false; return false;
@ -314,6 +385,18 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {
return true; return true;
} }
bool MacResManager::isRawFork(SeekableReadStream &stream) {
// TODO: Is there a better way to detect whether this is a raw fork?
const uint32 dataOffset = stream.readUint32BE();
const uint32 mapOffset = stream.readUint32BE();
const uint32 dataLength = stream.readUint32BE();
const uint32 mapLength = stream.readUint32BE();
return !stream.eos() && !stream.err()
&& dataOffset < (uint32)stream.size() && dataOffset + dataLength <= (uint32)stream.size()
&& mapOffset < (uint32)stream.size() && mapOffset + mapLength <= (uint32)stream.size();
}
bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) { bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) {
byte infoHeader[MBI_INFOHDR]; byte infoHeader[MBI_INFOHDR];
stream.read(infoHeader, MBI_INFOHDR); stream.read(infoHeader, MBI_INFOHDR);
@ -592,4 +675,32 @@ String MacResManager::constructAppleDoubleName(String name) {
return name; return name;
} }
String MacResManager::disassembleAppleDoubleName(String name, bool *isAppleDouble) {
if (isAppleDouble) {
*isAppleDouble = false;
}
// Remove "._" before the last portion of a path name.
for (int i = name.size() - 1; i >= 0; --i) {
if (i == 0) {
if (name.size() > 2 && name[0] == '.' && name[1] == '_') {
name.erase(0, 2);
if (isAppleDouble) {
*isAppleDouble = true;
}
}
} else if (name[i] == '/') {
if ((uint)(i + 2) < name.size() && name[i + 1] == '.' && name[i + 2] == '_') {
name.erase(i + 1, 2);
if (isAppleDouble) {
*isAppleDouble = true;
}
}
break;
}
}
return name;
}
} // End of namespace Common } // End of namespace Common

View file

@ -33,6 +33,7 @@
#include "common/array.h" #include "common/array.h"
#include "common/fs.h" #include "common/fs.h"
#include "common/str.h" #include "common/str.h"
#include "common/str-array.h"
#ifndef COMMON_MACRESMAN_H #ifndef COMMON_MACRESMAN_H
#define COMMON_MACRESMAN_H #define COMMON_MACRESMAN_H
@ -81,6 +82,16 @@ public:
*/ */
static bool exists(const String &fileName); static bool exists(const String &fileName);
/**
* List all filenames matching pattern for opening with open().
*
* @param files Array containing all matching filenames discovered. Only
* adds to the list.
* @param pattern Pattern to match against. Taking String::matchPattern's
* format.
*/
static void listFiles(StringArray &files, const String &pattern);
/** /**
* Close the Mac data/resource fork pair. * Close the Mac data/resource fork pair.
*/ */
@ -176,6 +187,7 @@ private:
bool loadFromAppleDouble(SeekableReadStream &stream); bool loadFromAppleDouble(SeekableReadStream &stream);
static String constructAppleDoubleName(String name); static String constructAppleDoubleName(String name);
static String disassembleAppleDoubleName(String name, bool *isAppleDouble);
/** /**
* Check if the given stream is in the MacBinary format. * Check if the given stream is in the MacBinary format.
@ -183,6 +195,13 @@ private:
*/ */
static bool isMacBinary(SeekableReadStream &stream); static bool isMacBinary(SeekableReadStream &stream);
/**
* Do a sanity check whether the given stream is a raw resource fork.
*
* @param stream Stream object to check. Will not preserve its position.
*/
static bool isRawFork(SeekableReadStream &stream);
enum { enum {
kResForkNone = 0, kResForkNone = 0,
kResForkRaw, kResForkRaw,

View file

@ -25,6 +25,7 @@
#include "common/stream.h" #include "common/stream.h"
#include "common/types.h" #include "common/types.h"
#include "common/util.h"
namespace Common { namespace Common {
@ -156,7 +157,7 @@ public:
* that grows as it's written to. * that grows as it's written to.
*/ */
class MemoryWriteStreamDynamic : public WriteStream { class MemoryWriteStreamDynamic : public WriteStream {
private: protected:
uint32 _capacity; uint32 _capacity;
uint32 _size; uint32 _size;
byte *_ptr; byte *_ptr;
@ -170,7 +171,7 @@ private:
byte *old_data = _data; byte *old_data = _data;
_capacity = new_len + 32; _capacity = MAX(new_len + 32, _capacity * 2);
_data = (byte *)malloc(_capacity); _data = (byte *)malloc(_capacity);
_ptr = _data + _pos; _ptr = _data + _pos;

View file

@ -59,10 +59,16 @@ MODULE_OBJS += \
recorderfile.o recorderfile.o
endif endif
# ResidualVM specific
ifdef USE_ICONV ifdef USE_ICONV
MODULE_OBJS += \ MODULE_OBJS += \
iconv.o iconv.o
endif endif
ifdef USE_UPDATES
MODULE_OBJS += \
updates.o
endif
# Include common rules # Include common rules
include $(srcdir)/rules.mk include $(srcdir)/rules.mk

View file

@ -27,6 +27,7 @@ namespace Common {
const PlatformDescription g_platforms[] = { const PlatformDescription g_platforms[] = {
{ "2gs", "2gs", "2gs", "Apple IIgs", kPlatformApple2GS }, { "2gs", "2gs", "2gs", "Apple IIgs", kPlatformApple2GS },
{ "apple2", "apple2", "apple2", "Apple II", kPlatformApple2 },
{ "3do", "3do", "3do", "3DO", kPlatform3DO }, { "3do", "3do", "3do", "3DO", kPlatform3DO },
{ "acorn", "acorn", "acorn", "Acorn", kPlatformAcorn }, { "acorn", "acorn", "acorn", "Acorn", kPlatformAcorn },
{ "amiga", "ami", "amiga", "Amiga", kPlatformAmiga }, { "amiga", "ami", "amiga", "Amiga", kPlatformAmiga },

View file

@ -50,6 +50,7 @@ enum Platform {
kPlatformSegaCD, kPlatformSegaCD,
kPlatform3DO, kPlatform3DO,
kPlatformPCEngine, kPlatformPCEngine,
kPlatformApple2,
kPlatformApple2GS, kPlatformApple2GS,
kPlatformPC98, kPlatformPC98,
kPlatformWii, kPlatformWii,

View file

@ -84,6 +84,8 @@ public:
int getNumerator() const { return _num; } int getNumerator() const { return _num; }
int getDenominator() const { return _denom; } int getDenominator() const { return _denom; }
bool isOne() const { return _num == _denom; }
void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const; void debugPrint(int debuglevel = 0, const char *caption = "Rational:") const;
private: private:

View file

@ -30,6 +30,8 @@
#include "graphics/surface.h" #include "graphics/surface.h"
#include "graphics/scaler.h" #include "graphics/scaler.h"
#ifdef ENABLE_EVENTRECORDER
#define RECORD_VERSION 1 #define RECORD_VERSION 1
namespace Common { namespace Common {
@ -714,3 +716,5 @@ void PlaybackFile::checkRecordedMD5() {
} }
#endif // ENABLE_EVENTRECORDER

View file

@ -163,7 +163,8 @@ struct Rect {
* *
* @param r the rectangle to check * @param r the rectangle to check
* *
* @return true if the given rectangle is inside the rectangle, false otherwise * @return true if the given rectangle has a non-empty intersection with
* this rectangle, false otherwise
*/ */
bool intersects(const Rect &r) const { bool intersects(const Rect &r) const {
return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom); return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom);

View file

@ -43,6 +43,7 @@ const RenderModeDescription g_renderModes[] = {
{ "pc9801", _s("PC-9801 (16 Colors)"), kRenderPC9801 }, { "pc9801", _s("PC-9801 (16 Colors)"), kRenderPC9801 },
{ "2gs", "Apple IIgs", kRenderApple2GS }, { "2gs", "Apple IIgs", kRenderApple2GS },
{ "atari", "Atari ST", kRenderAtariST }, { "atari", "Atari ST", kRenderAtariST },
{ "macintosh", "Macintosh", kRenderMacintosh },
{0, 0, kRenderDefault} {0, 0, kRenderDefault}
}; };
@ -65,7 +66,8 @@ static const RenderGUIOMapping s_renderGUIOMapping[] = {
{ kRenderPC9821, GUIO_RENDERPC9821 }, { kRenderPC9821, GUIO_RENDERPC9821 },
{ kRenderPC9801, GUIO_RENDERPC9801 }, { kRenderPC9801, GUIO_RENDERPC9801 },
{ kRenderApple2GS, GUIO_RENDERAPPLE2GS }, { kRenderApple2GS, GUIO_RENDERAPPLE2GS },
{ kRenderAtariST, GUIO_RENDERATARIST } { kRenderAtariST, GUIO_RENDERATARIST },
{ kRenderMacintosh, GUIO_RENDERMACINTOSH }
}; };
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Hercules Green", "lowres") DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Hercules Green", "lowres")

View file

@ -47,7 +47,8 @@ enum RenderMode {
kRenderPC9821 = 8, kRenderPC9821 = 8,
kRenderPC9801 = 9, kRenderPC9801 = 9,
kRenderApple2GS = 10, kRenderApple2GS = 10,
kRenderAtariST = 11 kRenderAtariST = 11,
kRenderMacintosh = 12
}; };
struct RenderModeDescription { struct RenderModeDescription {

View file

@ -56,6 +56,12 @@ typedef WriteStream OutSaveFile;
* i.e. typically save states, but also configuration files and similar * i.e. typically save states, but also configuration files and similar
* things. * things.
* *
* Savefile names represent SaveFiles. These names are case insensitive, that
* means a name of "Kq1.000" represents the same savefile as "kq1.000". In
* addition, SaveFileManager does not allow for names which contain path
* separators like '/' or '\'. This is because we do not support directories
* in SaveFileManager.
*
* While not declared as a singleton, it is effectively used as such, * While not declared as a singleton, it is effectively used as such,
* with OSystem::getSavefileManager returning a pointer to the single * with OSystem::getSavefileManager returning a pointer to the single
* SaveFileManager instances to be used. * SaveFileManager instances to be used.
@ -115,49 +121,56 @@ public:
* exports from the Quest for Glory series. QfG5 is a 3D game and won't be * exports from the Quest for Glory series. QfG5 is a 3D game and won't be
* supported by ScummVM. * supported by ScummVM.
* *
* @param name the name of the savefile * @param name The name of the savefile.
* @param compress toggles whether to compress the resulting save file * @param compress Toggles whether to compress the resulting save file
* (default) or not. * (default) or not.
* @return pointer to an OutSaveFile, or NULL if an error occurred. * @return Pointer to an OutSaveFile, or NULL if an error occurred.
*/ */
virtual OutSaveFile *openForSaving(const String &name, bool compress = true) = 0; virtual OutSaveFile *openForSaving(const String &name, bool compress = true) = 0;
/** /**
* Open the file with the specified name in the given directory for loading. * Open the file with the specified name in the given directory for loading.
* @param name the name of the savefile *
* @return pointer to an InSaveFile, or NULL if an error occurred. * @param name The name of the savefile.
* @return Pointer to an InSaveFile, or NULL if an error occurred.
*/ */
virtual InSaveFile *openForLoading(const String &name) = 0; virtual InSaveFile *openForLoading(const String &name) = 0;
/** /**
* Removes the given savefile from the system. * Removes the given savefile from the system.
* @param name the name of the savefile to be removed. *
* @param name The name of the savefile to be removed.
* @return true if no error occurred, false otherwise. * @return true if no error occurred, false otherwise.
*/ */
virtual bool removeSavefile(const String &name) = 0; virtual bool removeSavefile(const String &name) = 0;
/** /**
* Renames the given savefile. * Renames the given savefile.
* @param oldName Old name. *
* @param newName New name. * @param oldName Old name.
* @param newName New name.
* @return true if no error occurred. false otherwise. * @return true if no error occurred. false otherwise.
*/ */
virtual bool renameSavefile(const String &oldName, const String &newName); virtual bool renameSavefile(const String &oldName, const String &newName);
/** /**
* Copy the given savefile. * Copy the given savefile.
* @param oldName Old name. *
* @param newName New name. * @param oldName Old name.
* @param newName New name.
* @return true if no error occurred. false otherwise. * @return true if no error occurred. false otherwise.
*/ */
virtual bool copySavefile(const String &oldName, const String &newName); virtual bool copySavefile(const String &oldName, const String &newName);
/** /**
* Request a list of available savegames with a given DOS-style pattern, * List available savegames matching a given pattern.
* also known as "glob" in the POSIX world. Refer to the Common::matchString() *
* function to learn about the precise pattern format. * Our pattern format is based on DOS paterns, also known as "glob" in the
* @param pattern Pattern to match. Wildcards like * or ? are available. * POSIX world. Please refer to the Common::matchString() function to learn
* @return list of strings for all present file names. * about the precise pattern format.
*
* @param pattern Pattern to match. Wildcards like * or ? are available.
* @return List of strings for all present file names.
* @see Common::matchString() * @see Common::matchString()
*/ */
virtual StringArray listSavefiles(const String &pattern) = 0; virtual StringArray listSavefiles(const String &pattern) = 0;

View file

@ -215,6 +215,10 @@
#include "config.h" #include "config.h"
#endif #endif
// Now we need to adjust some settings when running tests
#ifdef COMPILING_TESTS
#undef ENABLE_EVENTRECORDER
#endif
// In the following we configure various targets, in particular those // In the following we configure various targets, in particular those
// which can't use our "configure" tool and hence don't use config.h. // which can't use our "configure" tool and hence don't use config.h.
@ -251,6 +255,7 @@
#if defined(__DC__) || \ #if defined(__DC__) || \
defined(__DS__) || \ defined(__DS__) || \
defined(__3DS__) || \
defined(__GP32__) || \ defined(__GP32__) || \
defined(IPHONE) || \ defined(IPHONE) || \
defined(__PLAYSTATION2__) || \ defined(__PLAYSTATION2__) || \
@ -367,7 +372,7 @@
#endif #endif
#ifndef STRINGBUFLEN #ifndef STRINGBUFLEN
#if defined(__N64__) || defined(__DS__) #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
#define STRINGBUFLEN 256 #define STRINGBUFLEN 256
#else #else
#define STRINGBUFLEN 1024 #define STRINGBUFLEN 1024

View file

@ -75,7 +75,7 @@ void String::initWithCStr(const char *str, uint32 len) {
} }
String::String(const String &str) String::String(const String &str)
: _size(str._size) { : _size(str._size) {
if (str.isStorageIntern()) { if (str.isStorageIntern()) {
// String in internal storage: just copy it // String in internal storage: just copy it
memcpy(_storage, str._storage, _builtinCapacity); memcpy(_storage, str._storage, _builtinCapacity);
@ -91,7 +91,7 @@ String::String(const String &str)
} }
String::String(char c) String::String(char c)
: _size(0), _str(_storage) { : _size(0), _str(_storage) {
_storage[0] = c; _storage[0] = c;
_storage[1] = 0; _storage[1] = 0;
@ -132,24 +132,19 @@ void String::ensureCapacity(uint32 new_size, bool keep_old) {
if (!isShared && new_size < curCapacity) if (!isShared && new_size < curCapacity)
return; return;
if (isShared && new_size < _builtinCapacity) { // We need to allocate storage on the heap!
// We share the storage, but there is enough internal storage: Use that.
newStorage = _storage;
newCapacity = _builtinCapacity;
} else {
// We need to allocate storage on the heap!
// Compute a suitable new capacity limit // Compute a suitable new capacity limit
// If the current capacity is sufficient we use the same capacity // If the current capacity is sufficient we use the same capacity
if (new_size < curCapacity) if (new_size < curCapacity)
newCapacity = curCapacity; newCapacity = curCapacity;
else else
newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1)); newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
// Allocate new storage
newStorage = new char[newCapacity];
assert(newStorage);
// Allocate new storage
newStorage = new char[newCapacity];
assert(newStorage);
}
// Copy old data if needed, elsewise reset the new storage. // Copy old data if needed, elsewise reset the new storage.
if (keep_old) { if (keep_old) {
@ -444,6 +439,58 @@ uint String::hash() const {
return hashit(c_str()); return hashit(c_str());
} }
void String::replace(uint32 pos, uint32 count, const String &str) {
replace(pos, count, str, 0, str._size);
}
void String::replace(uint32 pos, uint32 count, const char *str) {
replace(pos, count, str, 0, strlen(str));
}
void String::replace(iterator begin_, iterator end_, const String &str) {
replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
}
void String::replace(iterator begin_, iterator end_, const char *str) {
replace(begin_ - _str, end_ - begin_, str, 0, strlen(str));
}
void String::replace(uint32 posOri, uint32 countOri, const String &str,
uint32 posDest, uint32 countDest) {
replace(posOri, countOri, str._str, posDest, countDest);
}
void String::replace(uint32 posOri, uint32 countOri, const char *str,
uint32 posDest, uint32 countDest) {
ensureCapacity(_size + countDest - countOri, true);
// Prepare string for the replaced text.
if (countOri < countDest) {
uint32 offset = countDest - countOri; ///< Offset to copy the characters
uint32 newSize = _size + offset;
_size = newSize;
// Push the old characters to the end of the string
for (uint32 i = _size; i >= posOri + countDest; i--)
_str[i] = _str[i - offset];
} else if (countOri > countDest){
uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
// Pull the remainder string back
for (uint32 i = posOri + countDest; i < _size; i++)
_str[i] = _str[i + offset];
_size -= offset;
}
// Copy the replaced part of the string
for (uint32 i = 0; i < countDest; i++)
_str[posOri + i] = str[posDest + i];
}
// static // static
String String::format(const char *fmt, ...) { String String::format(const char *fmt, ...) {
String output; String output;

View file

@ -46,6 +46,17 @@ namespace Common {
class String { class String {
public: public:
static const uint32 npos = 0xFFFFFFFF; static const uint32 npos = 0xFFFFFFFF;
typedef char value_type;
/**
* Unsigned version of the underlying type. This can be used to cast
* individual string characters to bigger integer types without sign
* extension happening.
*/
typedef unsigned char unsigned_type;
typedef char * iterator;
typedef const char * const_iterator;
protected: protected:
/** /**
* The size of the internal storage. Increasing this means less heap * The size of the internal storage. Increasing this means less heap
@ -222,6 +233,38 @@ public:
void trim(); void trim();
uint hash() const; uint hash() const;
/**@{
* Functions to replace some amount of chars with chars from some other string.
*
* @note The implementation follows that of the STL's std::string:
* http://www.cplusplus.com/reference/string/string/replace/
*
* @param pos Starting position for the replace in the original string.
* @param count Number of chars to replace from the original string.
* @param str Source of the new chars.
* @param posOri Same as pos
* @param countOri Same as count
* @param posDest Initial position to read str from.
* @param countDest Number of chars to read from str. npos by default.
*/
// Replace 'count' bytes, starting from 'pos' with str.
void replace(uint32 pos, uint32 count, const String &str);
// The same as above, but accepts a C-like array of characters.
void replace(uint32 pos, uint32 count, const char *str);
// Replace the characters in [begin, end) with str._str.
void replace(iterator begin, iterator end, const String &str);
// Replace the characters in [begin, end) with str.
void replace(iterator begin, iterator end, const char *str);
// Replace _str[posOri, posOri + countOri) with
// str._str[posDest, posDest + countDest)
void replace(uint32 posOri, uint32 countOri, const String &str,
uint32 posDest, uint32 countDest);
// Replace _str[posOri, posOri + countOri) with
// str[posDest, posDest + countDest)
void replace(uint32 posOri, uint32 countOri, const char *str,
uint32 posDest, uint32 countDest);
/**@}*/
/** /**
* Print formatted data into a String object. Similar to sprintf, * Print formatted data into a String object. Similar to sprintf,
@ -238,15 +281,6 @@ public:
static String vformat(const char *fmt, va_list args); static String vformat(const char *fmt, va_list args);
public: public:
typedef char value_type;
/**
* Unsigned version of the underlying type. This can be used to cast
* individual string characters to bigger integer types without sign
* extension happening.
*/
typedef unsigned char unsigned_type;
typedef char * iterator;
typedef const char * const_iterator;
iterator begin() { iterator begin() {
// Since the user could potentially // Since the user could potentially

View file

@ -672,6 +672,7 @@ public:
* Return a Graphics::PixelBuffer representing the framebuffer. * Return a Graphics::PixelBuffer representing the framebuffer.
* The caller can then perform arbitrary graphics transformations * The caller can then perform arbitrary graphics transformations
* on the framebuffer (blitting, scrolling, etc.). * on the framebuffer (blitting, scrolling, etc.).
* !!! ResidualVM specific method: !!!
*/ */
virtual Graphics::PixelBuffer getScreenPixelBuffer() = 0; virtual Graphics::PixelBuffer getScreenPixelBuffer() = 0;

View file

@ -123,7 +123,7 @@ public:
virtual void addRecent(const String &name, const String &description) {} virtual void addRecent(const String &name, const String &description) {}
/** /**
* Notifies the user an error occured through the taskbar icon * Notifies the user an error occurred through the taskbar icon
* *
* This will for example show the taskbar icon as red (using progress of 100% and an error state) * This will for example show the taskbar icon as red (using progress of 100% and an error state)
* on Windows, and set the launcher icon in the urgent state on Unity * on Windows, and set the launcher icon in the urgent state on Unity

View file

@ -41,7 +41,7 @@ void setErrorHandler(ErrorHandler handler) {
} }
} // End of namespace Common } // End of namespace Common
#ifndef DISABLE_TEXT_CONSOLE #ifndef DISABLE_TEXT_CONSOLE

68
common/updates.cpp Normal file
View file

@ -0,0 +1,68 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/system.h"
#include "common/updates.h"
#include "common/translation.h"
namespace Common {
static const int updateIntervals[] = {
UpdateManager::kUpdateIntervalNotSupported,
UpdateManager::kUpdateIntervalOneDay,
UpdateManager::kUpdateIntervalOneWeek,
UpdateManager::kUpdateIntervalOneMonth,
-1
};
const int *UpdateManager::getUpdateIntervals() {
return updateIntervals;
}
int UpdateManager::normalizeInterval(int interval) {
const int *val = updateIntervals;
while (*val != -1) {
if (*val >= interval)
return *val;
val++;
}
return val[-1]; // Return maximal acceptable value
}
const char *UpdateManager::updateIntervalToString(int interval) {
switch (interval) {
case kUpdateIntervalNotSupported:
return _("Never");
case kUpdateIntervalOneDay:
return _("Daily");
case kUpdateIntervalOneWeek:
return _("Weekly");
case kUpdateIntervalOneMonth:
return _("Monthly");
default:
return _("<Bad value>");
}
}
} // End of namespace Common

View file

@ -20,8 +20,8 @@
* *
*/ */
#ifndef BACKENDS_UPDATES_ABSTRACT_H #ifndef COMMON_UPDATES_H
#define BACKENDS_UPDATES_ABSTRACT_H #define COMMON_UPDATES_H
#if defined(USE_UPDATES) #if defined(USE_UPDATES)
@ -85,18 +85,50 @@ public:
* *
* @param interval The interval. * @param interval The interval.
*/ */
virtual void setUpdateCheckInterval(UpdateInterval interval) {} virtual void setUpdateCheckInterval(int interval) {}
/** /**
* Gets the update check interval. * Gets the update check interval.
* *
* @return the update check interval. * @return the update check interval.
*/ */
virtual UpdateInterval getUpdateCheckInterval() { return kUpdateIntervalNotSupported; } virtual int getUpdateCheckInterval() { return kUpdateIntervalNotSupported; }
/**
* Gets last update check time
*
* @param t TimeDate struct to fill out
* @return flag indicating success
*/
virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t) { return false; }
/**
* Returns list of supported uptate intervals.
* Ending with '-1' which is not acceptable value.
*
* @return list of integer values representing update intervals in seconds.
*/
static const int *getUpdateIntervals();
/**
* Returns string representation of a given interval.
*
* @param interval The interval.
* @return pointer to localized string of given interval.
*/
static const char *updateIntervalToString(int interval);
/**
* Rounds up the given interval to acceptable value.
*
* @param interval The interval.
* @return rounded up interval
*/
static int normalizeInterval(int interval);
}; };
} // End of namespace Common } // End of namespace Common
#endif #endif
#endif // BACKENDS_UPDATES_ABSTRACT_H #endif // COMMON_UPDATES_H

143
config.guess vendored
View file

@ -1,8 +1,8 @@
#! /bin/sh #! /bin/sh
# Attempt to guess a canonical system name. # Attempt to guess a canonical system name.
# Copyright 1992-2014 Free Software Foundation, Inc. # Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-11-04' timestamp='2016-04-02'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -27,7 +27,7 @@ timestamp='2014-11-04'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
# #
# You can get the latest version of this script from: # You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
# #
# Please send patches to <config-patches@gnu.org>. # Please send patches to <config-patches@gnu.org>.
@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp) GNU config.guess ($timestamp)
Originally written by Per Bothner. Originally written by Per Bothner.
Copyright 1992-2014 Free Software Foundation, Inc. Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor # Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown". # portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch" sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || echo unknown)` /sbin/$sysctl 2>/dev/null || \
/usr/sbin/$sysctl 2>/dev/null || \
echo unknown)`
case "${UNAME_MACHINE_ARCH}" in case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;; armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;; arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;; sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;; sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;; sh5el) machine=sh5le-unknown ;;
earmv*)
arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
machine=${arch}${endian}-unknown
;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac esac
# The Operating System including object format, if it has switched # The Operating System including object format, if it has switched
# to ELF recently, or will in the future. # to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in case "${UNAME_MACHINE_ARCH}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax) arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__ | grep -q __ELF__
@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd os=netbsd
;; ;;
esac esac
# Determine ABI tags.
case "${UNAME_MACHINE_ARCH}" in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
;;
esac
# The OS release # The OS release
# Debian GNU/NetBSD machines have a different userland, and # Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need # thus, need a distinct triplet. However, they do not need
@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu' release='-gnu'
;; ;;
*) *)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;; ;;
esac esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form: # contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}" echo "${machine}-${os}${release}${abi}"
exit ;; exit ;;
*:Bitrig:*:*) *:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@ -223,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;; exit ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
exit ;;
*:ekkoBSD:*:*) *:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;; exit ;;
@ -235,6 +253,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*) *:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;; exit ;;
*:Sortix:*:*)
echo ${UNAME_MACHINE}-unknown-sortix
exit ;;
alpha:OSF1:*:*) alpha:OSF1:*:*)
case $UNAME_RELEASE in case $UNAME_RELEASE in
*4.0) *4.0)
@ -251,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in case "$ALPHA_CPU_TYPE" in
"EV4 (21064)") "EV4 (21064)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"EV4.5 (21064)") "EV4.5 (21064)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"LCA4 (21066/21068)") "LCA4 (21066/21068)")
UNAME_MACHINE="alpha" ;; UNAME_MACHINE=alpha ;;
"EV5 (21164)") "EV5 (21164)")
UNAME_MACHINE="alphaev5" ;; UNAME_MACHINE=alphaev5 ;;
"EV5.6 (21164A)") "EV5.6 (21164A)")
UNAME_MACHINE="alphaev56" ;; UNAME_MACHINE=alphaev56 ;;
"EV5.6 (21164PC)") "EV5.6 (21164PC)")
UNAME_MACHINE="alphapca56" ;; UNAME_MACHINE=alphapca56 ;;
"EV5.7 (21164PC)") "EV5.7 (21164PC)")
UNAME_MACHINE="alphapca57" ;; UNAME_MACHINE=alphapca57 ;;
"EV6 (21264)") "EV6 (21264)")
UNAME_MACHINE="alphaev6" ;; UNAME_MACHINE=alphaev6 ;;
"EV6.7 (21264A)") "EV6.7 (21264A)")
UNAME_MACHINE="alphaev67" ;; UNAME_MACHINE=alphaev67 ;;
"EV6.8CB (21264C)") "EV6.8CB (21264C)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.8AL (21264B)") "EV6.8AL (21264B)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.8CX (21264D)") "EV6.8CX (21264D)")
UNAME_MACHINE="alphaev68" ;; UNAME_MACHINE=alphaev68 ;;
"EV6.9A (21264/EV69A)") "EV6.9A (21264/EV69A)")
UNAME_MACHINE="alphaev69" ;; UNAME_MACHINE=alphaev69 ;;
"EV7 (21364)") "EV7 (21364)")
UNAME_MACHINE="alphaev7" ;; UNAME_MACHINE=alphaev7 ;;
"EV7.9 (21364A)") "EV7.9 (21364A)")
UNAME_MACHINE="alphaev79" ;; UNAME_MACHINE=alphaev79 ;;
esac esac
# A Pn.n version is a patched version. # A Pn.n version is a patched version.
# A Vn.n version is a released version. # A Vn.n version is a released version.
# A Tn.n version is a released field test version. # A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel. # A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r. # 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code. # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$? exitcode=$?
trap '' 0 trap '' 0
@ -359,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;; exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build eval $set_cc_for_build
SUN_ARCH="i386" SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects. # If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers. # This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null grep IS_64BIT_ARCH >/dev/null
then then
SUN_ARCH="x86_64" SUN_ARCH=x86_64
fi fi
fi fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@ -393,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;; exit ;;
sun*:*:4.2BSD:*) sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
case "`/bin/arch`" in case "`/bin/arch`" in
sun3) sun3)
echo m68k-sun-sunos${UNAME_RELEASE} echo m68k-sun-sunos${UNAME_RELEASE}
@ -618,13 +639,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in case "${sc_cpu_version}" in
523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0 532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in case "${sc_kernel_bits}" in
32) HP_ARCH="hppa2.0n" ;; 32) HP_ARCH=hppa2.0n ;;
64) HP_ARCH="hppa2.0w" ;; 64) HP_ARCH=hppa2.0w ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;; esac ;;
esac esac
fi fi
@ -663,11 +684,11 @@ EOF
exit (0); exit (0);
} }
EOF EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;; fi ;;
esac esac
if [ ${HP_ARCH} = "hppa2.0w" ] if [ ${HP_ARCH} = hppa2.0w ]
then then
eval $set_cc_for_build eval $set_cc_for_build
@ -680,12 +701,12 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23 # => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__ grep -q __LP64__
then then
HP_ARCH="hppa2.0w" HP_ARCH=hppa2.0w
else else
HP_ARCH="hppa64" HP_ARCH=hppa64
fi fi
fi fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV} echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@ -790,14 +811,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;; exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;; exit ;;
5000:UNIX_System_V:4.*:*) 5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;; exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@ -879,7 +900,7 @@ EOF
exit ;; exit ;;
*:GNU/*:*:*) *:GNU/*:*:*)
# other systems with GNU libc and userland # other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;; exit ;;
i*86:Minix:*:*) i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix echo ${UNAME_MACHINE}-pc-minix
@ -902,7 +923,7 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;; EV68*) UNAME_MACHINE=alphaev68 ;;
esac esac
objdump --private-headers /bin/sh | grep -q ld.so.1 objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="gnulibc1" ; fi if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
arc:Linux:*:* | arceb:Linux:*:*) arc:Linux:*:* | arceb:Linux:*:*)
@ -933,6 +954,9 @@ EOF
crisv32:Linux:*:*) crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC} echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;; exit ;;
e2k:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
frv:Linux:*:*) frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
@ -945,6 +969,9 @@ EOF
ia64:Linux:*:*) ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
k1om:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
m32r*:Linux:*:*) m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;; exit ;;
@ -1021,7 +1048,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC} echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;; exit ;;
x86_64:Linux:*:*) x86_64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;; exit ;;
xtensa*:Linux:*:*) xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC} echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@ -1100,7 +1127,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about # uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586. # the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub # Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that # prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build. # this is a cross-build.
echo i586-pc-msdosdjgpp echo i586-pc-msdosdjgpp
exit ;; exit ;;
@ -1249,6 +1276,9 @@ EOF
SX-8R:SUPER-UX:*:*) SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE} echo sx8r-nec-superux${UNAME_RELEASE}
exit ;; exit ;;
SX-ACE:SUPER-UX:*:*)
echo sxace-nec-superux${UNAME_RELEASE}
exit ;;
Power*:Rhapsody:*:*) Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE} echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;; exit ;;
@ -1262,9 +1292,9 @@ EOF
UNAME_PROCESSOR=powerpc UNAME_PROCESSOR=powerpc
fi fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null grep IS_64BIT_ARCH >/dev/null
then then
case $UNAME_PROCESSOR in case $UNAME_PROCESSOR in
@ -1286,7 +1316,7 @@ EOF
exit ;; exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*) *:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p` UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = "x86"; then if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386 UNAME_PROCESSOR=i386
UNAME_MACHINE=pc UNAME_MACHINE=pc
fi fi
@ -1317,7 +1347,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386 # "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86 # is converted to i386 for consistency with other x86
# operating systems. # operating systems.
if test "$cputype" = "386"; then if test "$cputype" = 386; then
UNAME_MACHINE=i386 UNAME_MACHINE=i386
else else
UNAME_MACHINE="$cputype" UNAME_MACHINE="$cputype"
@ -1359,7 +1389,7 @@ EOF
echo i386-pc-xenix echo i386-pc-xenix
exit ;; exit ;;
i*86:skyos:*:*) i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
exit ;; exit ;;
i*86:rdos:*:*) i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos echo ${UNAME_MACHINE}-pc-rdos
@ -1370,6 +1400,9 @@ EOF
x86_64:VMkernel:*:*) x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx echo ${UNAME_MACHINE}-unknown-esx
exit ;; exit ;;
amd64:Isilon\ OneFS:*:*)
echo x86_64-unknown-onefs
exit ;;
esac esac
cat >&2 <<EOF cat >&2 <<EOF
@ -1379,9 +1412,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you the operating system you are using. It is advised that you
download the most up to date version of the config scripts from download the most up to date version of the config scripts from
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and and
http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If the version you run ($0) is already up to date, please If the version you run ($0) is already up to date, please
send the following data and any information you think might be send the following data and any information you think might be

38
config.sub vendored
View file

@ -1,8 +1,8 @@
#! /bin/sh #! /bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright 1992-2014 Free Software Foundation, Inc. # Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2014-12-03' timestamp='2016-03-30'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -33,7 +33,7 @@ timestamp='2014-12-03'
# Otherwise, we print the canonical config type on stdout and succeed. # Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from: # You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages # This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases # and recognize all the CPU types, system types and aliases
@ -53,8 +53,7 @@ timestamp='2014-12-03'
me=`echo "$0" | sed -e 's,.*/,,'` me=`echo "$0" | sed -e 's,.*/,,'`
usage="\ usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
$0 [OPTION] ALIAS
Canonicalize a configuration name. Canonicalize a configuration name.
@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\ version="\
GNU config.sub ($timestamp) GNU config.sub ($timestamp)
Copyright 1992-2014 Free Software Foundation, Inc. Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -117,7 +116,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | \ kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*) storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os os=-$maybe_os
@ -255,12 +254,13 @@ case $basic_machine in
| arc | arceb \ | arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \ | avr | avr32 \
| ba \
| be32 | be64 \ | be32 | be64 \
| bfin \ | bfin \
| c4x | c8051 | clipper \ | c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \ | d10v | d30v | dlx | dsp16xx \
| epiphany \ | e2k | epiphany \
| fido | fr30 | frv \ | fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \ | hexagon \
| i370 | i860 | i960 | ia64 \ | i370 | i860 | i960 | ia64 \
@ -305,7 +305,7 @@ case $basic_machine in
| riscv32 | riscv64 \ | riscv32 | riscv64 \
| rl78 | rx \ | rl78 | rx \
| score \ | score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \ | sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@ -376,12 +376,13 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \ | avr-* | avr32-* \
| ba-* \
| be32-* | be64-* \ | be32-* | be64-* \
| bfin-* | bs2000-* \ | bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \ | c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \ | d10v-* | d30v-* | dlx-* \
| elxsi-* \ | e2k-* | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \ | h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@ -428,12 +429,13 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \ | pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \ | rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \ | sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \ | tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \ | tile*-* \
@ -518,6 +520,9 @@ case $basic_machine in
basic_machine=i386-pc basic_machine=i386-pc
os=-aros os=-aros
;; ;;
asmjs)
basic_machine=asmjs-unknown
;;
aux) aux)
basic_machine=m68k-apple basic_machine=m68k-apple
os=-aux os=-aux
@ -1373,11 +1378,11 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \ | -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \ | -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
@ -1393,7 +1398,8 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-qnx*) -qnx*)
@ -1525,6 +1531,8 @@ case $os in
;; ;;
-nacl*) -nacl*)
;; ;;
-ios)
;;
-none) -none)
;; ;;
*) *)

538
configure vendored
View file

@ -132,6 +132,7 @@ _timidity=no
_zlib=auto _zlib=auto
_mpeg2=auto _mpeg2=auto
_sparkle=auto _sparkle=auto
_osxdockplugin=auto
_jpeg=auto _jpeg=auto
_png=auto _png=auto
_theoradec=auto _theoradec=auto
@ -165,10 +166,12 @@ _bink=yes
_vkeybd=no _vkeybd=no
_keymapper=no _keymapper=no
_eventrec=no _eventrec=no
# GUI translation options
_translation=yes _translation=yes
# Default platform settings # Default platform settings
_backend=sdl _backend=sdl
_16bit=auto _16bit=auto
_highres=auto
_savegame_timestamp=auto _savegame_timestamp=auto
_dynamic_modules=no _dynamic_modules=no
_elf_loader=no _elf_loader=no
@ -188,6 +191,8 @@ _stagingpath="staging"
_win32path="C:/residualvm" _win32path="C:/residualvm"
_amigaospath="Games:ResidualVM" _amigaospath="Games:ResidualVM"
_staticlibpath= _staticlibpath=
_xcodetoolspath=
_sparklepath=
_sdlconfig=sdl-config _sdlconfig=sdl-config
_freetypeconfig=freetype-config _freetypeconfig=freetype-config
_sdlpath="$PATH" _sdlpath="$PATH"
@ -208,6 +213,7 @@ add_feature 16bit "16bit color" "_16bit"
add_feature faad "libfaad" "_faad" add_feature faad "libfaad" "_faad"
add_feature flac "FLAC" "_flac" add_feature flac "FLAC" "_flac"
add_feature freetype2 "FreeType2" "_freetype2" add_feature freetype2 "FreeType2" "_freetype2"
add_feature highres "high resolution" "_highres"
add_feature mad "MAD" "_mad" add_feature mad "MAD" "_mad"
add_feature jpeg "JPEG" "_jpeg" add_feature jpeg "JPEG" "_jpeg"
add_feature png "PNG" "_png" add_feature png "PNG" "_png"
@ -443,7 +449,7 @@ get_system_exe_extension() {
arm-riscos) arm-riscos)
_exeext=",ff8" _exeext=",ff8"
;; ;;
dreamcast | ds | gamecube | n64 | ps2 | psp | wii) 3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
_exeext=".elf" _exeext=".elf"
;; ;;
gph-linux) gph-linux)
@ -600,7 +606,7 @@ engine_enable() {
parent=`get_subengine_parent ${engine}` parent=`get_subengine_parent ${engine}`
if test `get_engine_build ${parent}` = "no" ; then if test `get_engine_build ${parent}` = "no" ; then
set_var _engine_${parent}_build "yes" set_var _engine_${parent}_build "yes"
fi fi
fi fi
if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then if test "$opt" = "static" -o "$opt" = "dynamic" -o "$opt" = "yes" ; then
@ -811,12 +817,6 @@ get_subengines_build_string() {
echo "$subengine_string" echo "$subengine_string"
} }
#
# Greet user
#
echo "Running ResidualVM configure..."
echo "Configure run on" `date` > $TMPLOG
# #
# Check any parameters we received # Check any parameters we received
# #
@ -877,7 +877,7 @@ Game engines:
--disable-all-engines disable all engines --disable-all-engines disable all engines
--enable-engine=<engine name>[,<engine name>...] enable engine(s) listed --enable-engine=<engine name>[,<engine name>...] enable engine(s) listed
--disable-engine=<engine name>[,<engine name>...] disable engine(s) listed --disable-engine=<engine name>[,<engine name>...] disable engine(s) listed
--enable-engine-static=<engine name>[,<engine name>...] --enable-engine-static=<engine name>[,<engine name>...]
enable engine(s) listed as static builtin (when plugins are enabled) enable engine(s) listed as static builtin (when plugins are enabled)
--enable-engine-dynamic=<engine name>[,<engine name>...] --enable-engine-dynamic=<engine name>[,<engine name>...]
enable engine(s) listed as dynamic plugin (when plugins are enabled) enable engine(s) listed as dynamic plugin (when plugins are enabled)
@ -953,8 +953,10 @@ Optional Libraries:
installed (optional) installed (optional)
--disable-fluidsynth disable fluidsynth MIDI driver [autodetect] --disable-fluidsynth disable fluidsynth MIDI driver [autodetect]
--with-sparkle-prefix=DIR Prefix where sparkle is installed (Mac OS X only - optional) --with-sparkle-prefix=DIR Prefix where sparkle is installed (OS X/Windows only - optional)
--disable-sparkle disable sparkle automatic update support [Mac OS X only - autodetect] --disable-sparkle disable sparkle automatic update support [OS X/Windows only - autodetect]
--disable-osx-dock-plugin disable the NSDockTilePlugin support [Mac OS X only - autodetect]
--with-sdl-prefix=DIR Prefix where the sdl-config script is --with-sdl-prefix=DIR Prefix where the sdl-config script is
installed (optional) installed (optional)
@ -993,9 +995,25 @@ EOF
fi fi
done # for parm in ... done # for parm in ...
#
# If we're not showing help, greet the user and start the log file
#
echo "Running ResidualVM configure..."
echo "Configure run on" `date` > $TMPLOG
cat >> $TMPLOG <<EOF
Invocation command line was:
$0 $@
Saved environment variables:
LDFLAGS="$SAVED_LDFLAGS" CXX="$SAVED_CXX" CXXFLAGS="$SAVED_CXXFLAGS" CPPFLAGS="$SAVED_CPPFLAGS" ASFLAGS="$SAVED_ASFLAGS" WINDRESFLAGS="$SAVED_WINDRESFLAGS" SDL_CONFIG="$SAVED_SDL_CONFIG"
EOF
for ac_option in $@; do for ac_option in $@; do
case "$ac_option" in case "$ac_option" in
# --disable-16bit) _16bit=no ;; #ResidualVM: not supported # --disable-16bit) _16bit=no ;; #ResidualVM: not supported
# --enable-highres) _highres=yes ;; #ResidualVM: not supported
# --disable-highres) _highres=no ;; #ResidualVM: not supported
--disable-savegame-timestamp) _savegame_timestamp=no ;; --disable-savegame-timestamp) _savegame_timestamp=no ;;
# --disable-scalers) _build_scalers=no ;; #ResidualVM: not supported # --disable-scalers) _build_scalers=no ;; #ResidualVM: not supported
# --disable-hq-scalers) _build_hq_scalers=no ;; #ResidualVM: not supported # --disable-hq-scalers) _build_hq_scalers=no ;; #ResidualVM: not supported
@ -1019,6 +1037,8 @@ for ac_option in $@; do
--disable-zlib) _zlib=no ;; --disable-zlib) _zlib=no ;;
--enable-sparkle) _sparkle=yes ;; --enable-sparkle) _sparkle=yes ;;
--disable-sparkle) _sparkle=no ;; --disable-sparkle) _sparkle=no ;;
--enable-osx-dock-plugin) _osxdockplugin=yes;;
--disable-osx-dock-plugin) _osxdockplugin=no;;
--enable-nasm) _nasm=yes ;; --enable-nasm) _nasm=yes ;;
--disable-nasm) _nasm=no ;; --disable-nasm) _nasm=no ;;
--enable-mpeg2) _mpeg2=yes ;; --enable-mpeg2) _mpeg2=yes ;;
@ -1141,8 +1161,7 @@ for ac_option in $@; do
;; ;;
--with-sparkle-prefix=*) --with-sparkle-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2` arg=`echo $ac_option | cut -d '=' -f 2`
SPARKLE_CFLAGS="-F$arg" _sparklepath=$arg
SPARKLE_LIBS="-F$arg"
;; ;;
--with-readline-prefix=*) --with-readline-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2` arg=`echo $ac_option | cut -d '=' -f 2`
@ -1225,6 +1244,9 @@ for ac_option in $@; do
--with-staticlib-prefix=*) --with-staticlib-prefix=*)
_staticlibpath=`echo $ac_option | cut -d '=' -f 2` _staticlibpath=`echo $ac_option | cut -d '=' -f 2`
;; ;;
--with-xcodetools-path=*)
_xcodetoolspath=`echo $ac_option | cut -d '=' -f 2`
;;
--host=*) --host=*)
_host=`echo $ac_option | cut -d '=' -f 2` _host=`echo $ac_option | cut -d '=' -f 2`
;; ;;
@ -1289,6 +1311,11 @@ get_system_exe_extension $guessed_host
NATIVEEXEEXT=$_exeext NATIVEEXEEXT=$_exeext
case $_host in case $_host in
3ds)
_host_os=3ds
_host_cpu=arm
_host_alias=arm-none-eabi
;;
android | android-arm | android-v7a | android-arm-v7a | ouya) android | android-arm | android-v7a | android-arm-v7a | ouya)
_host_os=android _host_os=android
_host_cpu=arm _host_cpu=arm
@ -1304,6 +1331,26 @@ android-x86)
_host_cpu=i686 _host_cpu=i686
_host_alias=i686-linux-android _host_alias=i686-linux-android
;; ;;
androidsdl-armeabi | androidsdl-armeabi-v7a)
_host_os=androidsdl
_host_cpu=arm
_host_alias=arm-linux-androideabi
;;
androidsdl-arm64-v8a)
_host_os=androidsdl
_host_cpu=aarch64
_host_alias=aarch64-linux-android
;;
androidsdl-mips)
_host_os=androidsdl
_host_cpu=mipsel
_host_alias=mipsel-linux-android
;;
androidsdl-x86)
_host_os=androidsdl
_host_cpu=i686
_host_alias=i686-linux-android
;;
arm-riscos) arm-riscos)
_host_os=riscos _host_os=riscos
_host_cpu=arm _host_cpu=arm
@ -1313,7 +1360,7 @@ raspberrypi)
_host_cpu=arm _host_cpu=arm
# This tuple is the one used by the official Rpi toolchain. # This tuple is the one used by the official Rpi toolchain.
# It may change in the future. # It may change in the future.
_host_alias=bcm2708hardfp _host_alias=arm-linux-gnueabihf
;; ;;
caanoo) caanoo)
_host_os=gph-linux _host_os=gph-linux
@ -1570,7 +1617,7 @@ android)
exit 1 exit 1
fi fi
;; ;;
ds | gamecube | wii) 3ds | ds | gamecube | wii)
if test -z "$DEVKITPRO"; then if test -z "$DEVKITPRO"; then
echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>" echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
exit 1 exit 1
@ -1826,7 +1873,7 @@ if test "$have_gcc" = yes ; then
case $_host_os in case $_host_os in
# newlib-based system include files suppress non-C89 function # newlib-based system include files suppress non-C89 function
# declarations under __STRICT_ANSI__ # declarations under __STRICT_ANSI__
amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince ) 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
;; ;;
*) *)
append_var CXXFLAGS "-ansi" append_var CXXFLAGS "-ansi"
@ -1862,7 +1909,7 @@ echo $_use_cxx11
# However, some platforms use GNU extensions in system header files, so # However, some platforms use GNU extensions in system header files, so
# for these we must not use -pedantic. # for these we must not use -pedantic.
case $_host_os in case $_host_os in
android | gamecube | psp | tizen | wii | webos) android | androidsdl | gamecube | psp | tizen | wii | webos)
;; ;;
*) *)
# ICC does not support pedantic, while GCC and clang do. # ICC does not support pedantic, while GCC and clang do.
@ -2126,6 +2173,27 @@ esac
echo_n "Checking hosttype... " echo_n "Checking hosttype... "
echo $_host_os echo $_host_os
case $_host_os in case $_host_os in
3ds)
_optimization_level=-O2
append_var DEFINES "-D__3DS__"
append_var DEFINES "-DARM"
append_var DEFINES "-DARM11"
append_var CXXFLAGS "-march=armv6k"
append_var CXXFLAGS "-mtune=mpcore"
append_var CXXFLAGS "-mword-relocations"
append_var CXXFLAGS "-mfloat-abi=hard"
append_var CXXFLAGS "-ffunction-sections"
append_var CXXFLAGS "-fomit-frame-pointer"
append_var CXXFLAGS "-I$DEVKITPRO/libctru/include"
append_var CXXFLAGS "-I$DEVKITPRO/portlibs/3ds/include"
if test "$_dynamic_modules" = no ; then
append_var LDFLAGS "-Wl,--gc-sections"
else
append_var LDFLAGS "-Wl,--no-gc-sections"
fi
append_var LDFLAGS "-L$DEVKITPRO/portlibs/3ds/lib"
append_var LIBS "-lcitro3d -lctru"
;;
amigaos*) amigaos*)
append_var LDFLAGS "-Wl,--export-dynamic" append_var LDFLAGS "-Wl,--export-dynamic"
append_var LDFLAGS "-L/sdk/local/newlib/lib" append_var LDFLAGS "-L/sdk/local/newlib/lib"
@ -2280,7 +2348,7 @@ case $_host_os in
LDFLAGS="-L${macport_prefix}/lib $LDFLAGS" LDFLAGS="-L${macport_prefix}/lib $LDFLAGS"
CXXFLAGS="-I${macport_prefix}/include $CXXFLAGS" CXXFLAGS="-I${macport_prefix}/include $CXXFLAGS"
if test -z "$_staticlibpath"; then if test -z "$_staticlibpath"; then
_staticlibpath=${macport_prefix} _staticlibpath=${macport_prefix}
echo "Set staticlib-prefix to ${_staticlibpath}" echo "Set staticlib-prefix to ${_staticlibpath}"
@ -2342,6 +2410,17 @@ case $_host_os in
echo "Could not determine prefix for static libraries" echo "Could not determine prefix for static libraries"
fi fi
fi fi
# If _xcodetoolspath is not set yet use xcode-select to get the path
if test -z "$_xcodetoolspath"; then
_xcodetoolspath=`xcode-select -print-path`/Tools
if test -d "$_xcodetoolspath"; then
echo "Set xcodetools-path to ${_xcodetoolspath}"
else
_xcodetoolspath=
echo "Could not determine path for Xcode Tools"
fi
fi
;; ;;
dreamcast) dreamcast)
append_var DEFINES "-D__DC__" append_var DEFINES "-D__DC__"
@ -2435,6 +2514,10 @@ case $_host_os in
mint*) mint*)
append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE" append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
;; ;;
msys)
echo ERROR: Using the MSYS shell in msys mode is not supported. Please use the MSYS shell in mingw mode instead.
exit 1
;;
n64) n64)
append_var DEFINES "-D__N64__" append_var DEFINES "-D__N64__"
append_var DEFINES "-DLIMIT_FPS" append_var DEFINES "-DLIMIT_FPS"
@ -2550,6 +2633,18 @@ if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed # Cross-compiling mode - add your target here if needed
echo "Cross-compiling to $_host" echo "Cross-compiling to $_host"
case "$_host" in case "$_host" in
3ds)
append_var DEFINES "-DDISABLE_FANCY_THEMES"
append_var DEFINES "-DDISABLE_SID"
append_var DEFINES "-DDISABLE_NES_APU"
_backend="3ds"
_build_scalers=no
_vkeybd=yes
_mt32emu=no
# Should use Tremor instead of Vorbis
_vorbis=no
_port_mk="backends/platform/3ds/3ds.mk"
;;
android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya) android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya)
# we link a .so as default # we link a .so as default
append_var LDFLAGS "-shared" append_var LDFLAGS "-shared"
@ -2563,6 +2658,15 @@ if test -n "$_host"; then
_mt32emu=no _mt32emu=no
_timidity=no _timidity=no
;; ;;
androidsdl | androidsdl-armeabi | androidsdl-armeabi-v7a | androidsdl-mips | androidsdl-x86 | androidsdl-arm64-v8a)
DEFINES="$DEFINES -DANDROIDSDL"
_unix=yes
_seq_midi=no
_mt32emu=no
_timidity=no
_backend="androidsdl"
_port_mk="backends/platform/androidsdl/androidsdl.mk"
;;
arm-linux|arm*-linux-gnueabi|arm-*-linux) arm-linux|arm*-linux-gnueabi|arm-*-linux)
;; ;;
arm-riscos|linupy) arm-riscos|linupy)
@ -2601,7 +2705,7 @@ if test -n "$_host"; then
_mt32emu=no _mt32emu=no
_optimization_level=-O3 _optimization_level=-O3
# Disable alsa midi to get the port build on OpenDingux toolchain # Disable alsa midi to get the port build on OpenDingux toolchain
_alsa=no _alsa=no
_vkeybd=yes _vkeybd=yes
_build_hq_scalers=no _build_hq_scalers=no
_keymapper=no _keymapper=no
@ -2628,14 +2732,15 @@ if test -n "$_host"; then
_eventrec=no _eventrec=no
_build_scalers=no _build_scalers=no
_build_hq_scalers=no _build_hq_scalers=no
# We prefer SDL2 on the Raspberry Pi: acceleration now depends on it # We prefer SDL2 on the Raspberry Pi: acceleration now depends on it
# since SDL2 manages dispmanx/GLES2 very well internally. # since SDL2 manages dispmanx/GLES2 very well internally.
# SDL1 is bit-rotten on this platform. # SDL1 is bit-rotten on this platform.
_sdlconfig=sdl2-config _sdlconfig=sdl2-config
# OpenGL(ES) support is mature enough as to be the best option on # OpenGL ES support is mature enough as to be the best option on
# the Raspberry Pi, so it's enabled by default. # the Raspberry Pi, so it's enabled by default.
_opengl=yes # The Raspberry Pi always supports OpenGL ES 2.0 contexts, thus we
_opengles=yes # take advantage of those.
_opengl_mode=gles2
;; ;;
dreamcast) dreamcast)
append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER" append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER"
@ -2656,7 +2761,11 @@ if test -n "$_host"; then
_build_scalers=no _build_scalers=no
_mad=yes _mad=yes
_zlib=yes _zlib=yes
add_line_to_config_mk 'ronindir = /usr/local/ronin' if test -z "$RONINDIR"; then
add_line_to_config_mk "ronindir := /usr/local/ronin"
else
add_line_to_config_mk "ronindir := $RONINDIR"
fi
_port_mk="backends/platform/dc/dreamcast.mk" _port_mk="backends/platform/dc/dreamcast.mk"
;; ;;
ds) ds)
@ -2689,22 +2798,22 @@ if test -n "$_host"; then
add_line_to_config_h "/* #define DEBUG_WII_GDB */" add_line_to_config_h "/* #define DEBUG_WII_GDB */"
add_line_to_config_h "#define USE_WII_DI" add_line_to_config_h "#define USE_WII_DI"
;; ;;
gcw0) gcw0)
append_var DEFINES "-DDINGUX -DGCW0" _sysroot=`$CXX --print-sysroot`
_sdlpath=$_sysroot/usr/bin
append_var DEFINES "-DDINGUX -DGCW0 -DGUI_ONLY_FULLSCREEN"
append_var DEFINES "-DREDUCE_MEMORY_USAGE" append_var DEFINES "-DREDUCE_MEMORY_USAGE"
append_var CXXFLAGS "-mips32" append_var CXXFLAGS "-mips32"
_backend="dingux" _backend="dingux"
_mt32emu=no
_optimization_level=-O3
# Disable alsa midi to get the port build on OpenDingux toolchain
_alsa=no _alsa=no
_vkeybd=yes _mt32emu=no
_build_hq_scalers=no
_keymapper=yes
# Force disable vorbis on dingux, it has terrible performance compared to tremor
_vorbis=no
# Force disable seq on dingux, no way to use it and it would get enabled by default with configure
_seq_midi=no _seq_midi=no
_timidity=no
_build_scalers=no
_optimization_level=-O3
_vkeybd=yes
_keymapper=yes
_vorbis=no
_port_mk="backends/platform/dingux/dingux.mk" _port_mk="backends/platform/dingux/dingux.mk"
;; ;;
gp2x) gp2x)
@ -2746,11 +2855,8 @@ if test -n "$_host"; then
;; ;;
ios7) ios7)
append_var DEFINES "-DIPHONE" append_var DEFINES "-DIPHONE"
append_var CFLAGS "-Wno-shift-count-overflow"
append_var CXXFLAGS "-Wno-shift-count-overflow"
_backend="ios7" _backend="ios7"
_build_scalers=no _build_scalers=no
_mt32emu=no
_seq_midi=no _seq_midi=no
_timidity=no _timidity=no
;; ;;
@ -2767,7 +2873,7 @@ if test -n "$_host"; then
append_var INCLUDES "-I/usr/X11R6/include" append_var INCLUDES "-I/usr/X11R6/include"
append_var LIBS "-lX11" append_var LIBS "-lX11"
append_var LIBS "-L/usr/lib" append_var LIBS "-L/usr/lib"
_backend="maemo" _backend="maemo"
_vkeybd=yes _vkeybd=yes
_keymapper=yes _keymapper=yes
@ -2960,6 +3066,8 @@ if test -n "$_host"; then
_mt32emu=no _mt32emu=no
_timidity=no _timidity=no
_vkeybd=yes _vkeybd=yes
# Tizen relies on the OpenGL ES output thus we always enable it.
_opengl_mode=gles
;; ;;
webos) webos)
_backend="webos" _backend="webos"
@ -3005,12 +3113,16 @@ fi
# Backend related stuff # Backend related stuff
# #
case $_backend in case $_backend in
3ds)
;;
android) android)
append_var DEFINES "-DREDUCE_MEMORY_USAGE" append_var DEFINES "-DREDUCE_MEMORY_USAGE"
append_var CXXFLAGS "-Wa,--noexecstack" append_var CXXFLAGS "-Wa,--noexecstack"
append_var LDFLAGS "-Wl,-z,noexecstack" append_var LDFLAGS "-Wl,-z,noexecstack"
append_var INCLUDES "-I$ANDROID_NDK/sources/cxx-stl/system/include" append_var INCLUDES "-I$ANDROID_NDK/sources/cxx-stl/system/include"
;; ;;
androidsdl)
;;
dc) dc)
append_var INCLUDES '-I$(srcdir)/backends/platform/dc' append_var INCLUDES '-I$(srcdir)/backends/platform/dc'
append_var INCLUDES '-isystem $(ronindir)/include' append_var INCLUDES '-isystem $(ronindir)/include'
@ -3107,6 +3219,8 @@ case $_backend in
append_var LDFLAGS "-shared" append_var LDFLAGS "-shared"
append_var LDFLAGS "-fpic" append_var LDFLAGS "-fpic"
;; ;;
sdl)
;;
tizen) tizen)
# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included # dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT" append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
@ -3155,8 +3269,6 @@ case $_backend in
append_var DEFINES "-DSDL_BACKEND" append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1" add_line_to_config_mk "SDL_BACKEND = 1"
;; ;;
sdl)
;;
*) *)
echo "support for $_backend backend not implemented in configure script yet" echo "support for $_backend backend not implemented in configure script yet"
exit 1 exit 1
@ -3168,7 +3280,7 @@ append_var MODULES "backends/platform/$_backend"
# Setup SDL specifics for SDL based backends # Setup SDL specifics for SDL based backends
# #
case $_backend in case $_backend in
dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl) androidsdl | dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl)
find_sdlconfig find_sdlconfig
append_var INCLUDES "`$_sdlconfig --prefix="$_sdlpath" --cflags`" append_var INCLUDES "`$_sdlconfig --prefix="$_sdlpath" --cflags`"
append_var LIBS "`$_sdlconfig --prefix="$_sdlpath" --libs`" append_var LIBS "`$_sdlconfig --prefix="$_sdlpath" --libs`"
@ -3191,7 +3303,7 @@ esac
# Enable 16bit support only for backends which support it # Enable 16bit support only for backends which support it
# #
case $_backend in case $_backend in
android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii) 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
if test "$_16bit" = auto ; then if test "$_16bit" = auto ; then
_16bit=yes _16bit=yes
else else
@ -3203,6 +3315,26 @@ case $_backend in
;; ;;
esac esac
#
# Enable High resolution engines (>320x240) support only for backends which support it
#
case $_host in
gcw0)
if test "$_highres" = yes ; then
_highres=yes
else
_highres=no
fi
;;
*)
if test "$_highres" = no ; then
_highres=no
else
_highres=yes
fi
;;
esac
# #
# Enable Event Recorder only for backends that support it # Enable Event Recorder only for backends that support it
# #
@ -3250,7 +3382,7 @@ case $_host_os in
amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince) amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince)
_posix=no _posix=no
;; ;;
android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos) 3ds | android | androidsdl | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos)
_posix=yes _posix=yes
;; ;;
os2-emx*) os2-emx*)
@ -3515,6 +3647,11 @@ define_in_config_if_yes "$_mt32emu" 'USE_MT32EMU'
# #
define_in_config_if_yes "$_16bit" 'USE_RGB_COLOR' define_in_config_if_yes "$_16bit" 'USE_RGB_COLOR'
#
# Check whether High resolution graphics support is requested
#
define_in_config_if_yes "$_highres" 'USE_HIGHRES'
# #
# Check whether save games use the current time as default description # Check whether save games use the current time as default description
# #
@ -3873,39 +4010,100 @@ echo "$_mpeg2"
# #
# Check for Sparkle if updates support is enabled # Check for Sparkle if updates support is enabled
# #
echocheck "Sparkle" #
if test "$_updates" = no; then # Check is NSDockTilePlugIn protocol is supported
_sparkle=no #
else case $_host_os in
if test "$_sparkle" = auto ; then darwin*)
_sparkle=no echocheck "Sparkle"
cat > $TMPC << EOF if test "$_updates" = no; then
_sparkle=no
else
if test ! -z $_sparklepath ; then
SPARKLE_CFLAGS="-F$_sparklepath"
SPARKLE_LIBS="-F$_sparklepath"
fi
if test "$_sparkle" = auto ; then
_sparkle=no
cat > $TMPC << EOF
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h> #include <Sparkle/Sparkle.h>
int main(void) { SUUpdater *updater = [SUUpdater sharedUpdater]; return 0; } int main(void) { SUUpdater *updater = [SUUpdater sharedUpdater]; return 0; }
EOF EOF
cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -framework Sparkle -ObjC++ -lobjc && _sparkle=yes cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -framework Sparkle -ObjC++ -lobjc && _sparkle=yes
fi fi
if test "$_sparkle" = yes ; then if test "$_sparkle" = yes ; then
append_var LIBS "$SPARKLE_LIBS -framework Sparkle" append_var LIBS "$SPARKLE_LIBS -framework Sparkle"
append_var INCLUDES "$SPARKLE_CFLAGS" append_var INCLUDES "$SPARKLE_CFLAGS"
fi fi
define_in_config_if_yes "$_sparkle" 'USE_SPARKLE' define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
fi fi
echo "$_sparkle" echo "$_sparkle"
;;
mingw*)
echocheck "Sparkle"
if test "$_updates" = no; then
_sparkle=no
else
if test ! -z $_sparklepath ; then
SPARKLE_CFLAGS="-I$_sparklepath/include"
SPARKLE_LIBS="-L$_sparklepath/Release -L$_sparklepath/x64/Release"
fi
if test "$_sparkle" = auto ; then
_sparkle=no
cat > $TMPC << EOF
#include <winsparkle.h>
int main(void) { win_sparkle_get_update_check_interval(); return 0; }
EOF
cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -lWinSparkle && _sparkle=yes
fi
if test "$_sparkle" = yes ; then
append_var LIBS "$SPARKLE_LIBS -lWinSparkle"
append_var INCLUDES "$SPARKLE_CFLAGS"
fi
define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
fi
echo "$_sparkle"
;;
*)
_sparkle=no
;;
esac
# #
# Check for FluidSynth # Check is NSDockTilePlugIn protocol is supported
#
case $_host_os in
darwin*)
# NSDockTilePlugIn was added in OS X 10.6, so will not be available when compiling on older OS X versions.
echocheck "DockTilePlugin"
if test "$_osxdockplugin" = auto ; then
_osxdockplugin=no
cat > $TMPC << EOF
#include <Cocoa/Cocoa.h>
@interface ScummVMDockTilePlugIn : NSObject <NSDockTilePlugIn> {
}
@end
EOF
cc_check -c -ObjC++ && _osxdockplugin=yes
fi
define_in_config_if_yes "$_osxdockplugin" 'USE_DOCKTILEPLUGIN'
echo "$_osxdockplugin"
;;
*)
_osxdockplugin=no
;;
esac
#
# Check for FluidSynth
# #
echocheck "FluidSynth" echocheck "FluidSynth"
append_var FLUIDSYNTH_LIBS "-lfluidsynth" append_var FLUIDSYNTH_LIBS "-lfluidsynth"
case $_host_os in case $_host_os in
mingw*) mingw*)
# NOTE: Windows builds use an older FluidSynth version (1.0.9) FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -lglib-2.0 -lintl -liconv -lws2_32 -lole32 -lshlwapi -lpcre -ldsound -lwinmm"
# which doesn't require glib, to avoid bundling the complete glib
# libraries with Windows builds.
FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -ldsound -lwinmm"
;; ;;
darwin*) darwin*)
@ -4138,87 +4336,7 @@ EOF
fi fi
define_in_config_if_yes "$_glew" "USE_GLEW" define_in_config_if_yes "$_glew" "USE_GLEW"
# ResidualVM specific end <-
#
# Check for iconv
#
echo_n "Checking whether iconv.h is present... "
if test "$_iconv" = auto ; then
_iconv=no
cat > $TMPC << EOF
#include <iconv.h>
int main(int, char **) {
return 0;
}
EOF
cc_check $ICONV_CFLAGS $ICONV_LIBS && _iconv=yes
fi
create_iconv_test() {
cat > $TMPC << EOF
#include <iconv.h>
int main(int, char **) {
iconv_t iconv = iconv_open("UTF-32", "SJIS");
iconv_close(iconv);
return 0;
}
EOF
}
echo "$_iconv"
if test "$_iconv" = yes ; then
echo_n "Checking whether iconv needs linking against libiconv... "
needs_iconvlib='auto'
create_iconv_test
cc_check $ICONV_CFLAGS $ICONV_LIBS -liconv && needs_iconvlib='yes'
# We do check linking without -liconv here too, just in case
# it would fail otherwise too
create_iconv_test
cc_check $ICONV_CFLAGS $ICONV_LIBS && needs_iconvlib='no'
if test "$needs_iconvlib" = auto ; then
_iconv=no
echo "does not link at all"
else
if test "$needs_iconvlib" = yes ; then
append_var ICONV_LIBS "-liconv"
fi
echo "$needs_iconvlib"
echo_n "Checking signature of iconv... "
uses_const=no
cat > $TMPC << EOF
#include <iconv.h>
int main(int argc, char **argv) {
iconv_t iconvP;
const char **inbuf = 0;
iconv(iconvP, inbuf, 0, 0, 0);
return 0;
}
EOF
cc_check $ICONV_CFLAGS $ICONV_LIBS && uses_const=yes
if test "$uses_const" = yes ; then
echo "iconv_t, const char **, size_t *, char **, size_t *"
else
echo "iconv_t, char **, size_t *, char **, size_t *"
fi
define_in_config_if_yes "$uses_const" 'ICONV_USES_CONST'
fi
fi
if test "$_iconv" = yes ; then
append_var LIBS "$ICONV_LIBS"
append_var INCLUDES "$ICONV_CFLAGS"
fi
echocheck "iconv"
define_in_config_if_yes "$_iconv" 'USE_ICONV'
echo "$_iconv"
# #
# Check for OpenGL (ES) # Check for OpenGL (ES)
@ -4239,7 +4357,6 @@ case $_backend in
;; ;;
esac esac
# ResidualVM specific start ->
if test "$_opengl" = auto ; then if test "$_opengl" = auto ; then
_opengl=no _opengl=no
if test "$_backend" = "sdl" || test "$_backend" = "android"; then if test "$_backend" = "sdl" || test "$_backend" = "android"; then
@ -4340,19 +4457,10 @@ EOF
fi fi
cc_check_clean cc_check_clean
fi fi
# ResidualVM specific end <-
case $_host_os in
tizen)
# components live in non-standard locations so just assume sane SDK
_opengl=yes
_opengles=yes
;;
esac
if test "$_opengles" = "yes" ; then if test "$_opengles" = "yes" ; then
echo "yes (OpenGL ES)" echo "yes (OpenGL ES)"
# ResidualVM specific start here ->
elif test "$_opengles2" = "yes" ; then elif test "$_opengles2" = "yes" ; then
echo "yes (OpenGL ES2)" echo "yes (OpenGL ES2)"
else else
@ -4369,8 +4477,112 @@ define_in_config_if_yes "$_opengl" "USE_OPENGL"
define_in_config_if_yes "$_opengles" "USE_GLES" define_in_config_if_yes "$_opengles" "USE_GLES"
define_in_config_if_yes "$_opengles2" "USE_GLES2" define_in_config_if_yes "$_opengles2" "USE_GLES2"
define_in_config_if_yes "$_opengl_shaders" "USE_OPENGL_SHADERS" define_in_config_if_yes "$_opengl_shaders" "USE_OPENGL_SHADERS"
#
# Check for iconv
#
echo_n "Checking whether iconv.h is present... "
if test "$_iconv" = auto ; then
_iconv=no
cat > $TMPC << EOF
#include <iconv.h>
int main(int, char **) {
return 0;
}
EOF
cc_check $ICONV_CFLAGS $ICONV_LIBS && _iconv=yes
fi
create_iconv_test() {
cat > $TMPC << EOF
#include <iconv.h>
int main(int, char **) {
iconv_t iconv = iconv_open("UTF-32", "SJIS");
iconv_close(iconv);
return 0;
}
EOF
}
echo "$_iconv"
if test "$_iconv" = yes ; then
echo_n "Checking whether iconv needs linking against libiconv... "
needs_iconvlib='auto'
create_iconv_test
cc_check $ICONV_CFLAGS $ICONV_LIBS -liconv && needs_iconvlib='yes'
# We do check linking without -liconv here too, just in case
# it would fail otherwise too
create_iconv_test
cc_check $ICONV_CFLAGS $ICONV_LIBS && needs_iconvlib='no'
if test "$needs_iconvlib" = auto ; then
_iconv=no
echo "does not link at all"
else
if test "$needs_iconvlib" = yes ; then
append_var ICONV_LIBS "-liconv"
fi
echo "$needs_iconvlib"
echo_n "Checking signature of iconv... "
uses_const=no
cat > $TMPC << EOF
#include <iconv.h>
int main(int argc, char **argv) {
iconv_t iconvP;
const char **inbuf = 0;
iconv(iconvP, inbuf, 0, 0, 0);
return 0;
}
EOF
cc_check $ICONV_CFLAGS $ICONV_LIBS && uses_const=yes
if test "$uses_const" = yes ; then
echo "iconv_t, const char **, size_t *, char **, size_t *"
else
echo "iconv_t, char **, size_t *, char **, size_t *"
fi
define_in_config_if_yes "$uses_const" 'ICONV_USES_CONST'
fi
fi
if test "$_iconv" = yes ; then
append_var LIBS "$ICONV_LIBS"
append_var INCLUDES "$ICONV_CFLAGS"
fi
echocheck "iconv"
define_in_config_if_yes "$_iconv" 'USE_ICONV'
echo "$_iconv"
# ResidualVM specific ends here <- # ResidualVM specific ends here <-
#
# Check for Linux CD-ROM support
#
case $_host_os in
*linux*)
echocheck "Linux CD-ROM"
linuxcd=no
cat > $TMPC << EOF
#include <linux/cdrom.h>
#include <sys/types.h>
int main(void) {
int x = CDROMREADAUDIO;
dev_t dev;
return major(dev) + x;
}
EOF
cc_check && linuxcd=yes
define_in_config_if_yes "$linuxcd" 'USE_LINUXCD'
echo "$linuxcd"
;;
esac
# #
# Check for nasm # Check for nasm
# #
@ -4605,6 +4817,10 @@ if test "$_16bit" = yes ; then
: # residualvm not use it : # residualvm not use it
fi fi
if test "$_highres" = yes ; then
: # residualvm not use it
fi
if test "$_savegame_timestamp" = yes ; then if test "$_savegame_timestamp" = yes ; then
echo_n ", savegame timestamp" echo_n ", savegame timestamp"
fi fi
@ -4618,7 +4834,7 @@ if test "$_build_scalers" = yes ; then
fi fi
if test "$_mt32emu" = yes ; then if test "$_mt32emu" = yes ; then
echo_n ", MT-32 emu" echo_n ", MT-32 emulator"
fi fi
if test "$_text_console" = yes ; then if test "$_text_console" = yes ; then
@ -4644,6 +4860,14 @@ fi
# after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup # after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup
# #
case $_backend in case $_backend in
3ds)
if test "$_freetype2" = yes -a "$_png" = yes; then
append_var LIBS "-lpng"
fi
if test "$_tremor" = yes -o "$_flac" = yes; then
append_var LIBS "-logg"
fi
;;
android) android)
# ssp at this point so the cxxtests link # ssp at this point so the cxxtests link
if test "$_debug_build" = yes; then if test "$_debug_build" = yes; then
@ -4875,6 +5099,8 @@ STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path WIN32PATH=$_win32path
AMIGAOSPATH=$_amigaospath AMIGAOSPATH=$_amigaospath
STATICLIBPATH=$_staticlibpath STATICLIBPATH=$_staticlibpath
XCODETOOLSPATH=$_xcodetoolspath
SPARKLEPATH=$_sparklepath
SDLCONFIG=$_sdlconfig SDLCONFIG=$_sdlconfig
ABI := $ABI ABI := $ABI

View file

@ -0,0 +1,324 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "cmake.h"
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iterator>
namespace CreateProjectTool {
CMakeProvider::CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
: ProjectProvider(global_warnings, project_warnings, version) {
}
const CMakeProvider::Library *CMakeProvider::getLibraryFromFeature(const char *feature) const {
static const Library s_libraries[] = {
{ "sdl", "FindSDL", "SDL", "SDL_INCLUDE_DIR", "SDL_LIBRARY", 0 },
{ "sdl2", 0, "SDL2", "SDL2_INCLUDE_DIRS", "SDL2_LIBRARIES", 0 },
{ "freetype", "FindFreetype", "Freetype", "FREETYPE_INCLUDE_DIRS", "FREETYPE_LIBRARIES", 0 },
{ "libz", "FindZLIB", "ZLIB", "ZLIB_INCLUDE_DIRS", "ZLIB_LIBRARIES", 0 },
{ "png", "FindPNG", "PNG", "PNG_INCLUDE_DIRS", "PNG_LIBRARIES", 0 },
{ "jpeg", "FindJPEG", "JPEG", "JPEG_INCLUDE_DIRS", "JPEG_LIBRARIES", 0 },
{ "mpeg2", "FindMPEG2", "MPEG2", "MPEG2_INCLUDE_DIRS", "MPEG2_mpeg2_LIBRARY", 0 },
{ "flac", 0, 0, 0, 0, "FLAC" },
{ "mad", 0, 0, 0, 0, "mad" },
{ "vorbis", 0, 0, 0, 0, "vorbisfile vorbis ogg" },
{ "theora", 0, 0, 0, 0, "theoradec" },
{ "fluidsynth",0, 0, 0, 0, "fluidsynth" },
{ "faad", 0, 0, 0, 0, "faad" }
};
for (unsigned int i = 0; i < sizeof(s_libraries) / sizeof(s_libraries[0]); i++) {
if (std::strcmp(feature, s_libraries[i].feature) == 0) {
return &s_libraries[i];
}
}
return 0;
}
void CMakeProvider::createWorkspace(const BuildSetup &setup) {
std::string filename = setup.outputDir + "/CMakeLists.txt";
std::ofstream workspace(filename.c_str());
if (!workspace)
error("Could not open \"" + filename + "\" for writing");
workspace << "cmake_minimum_required(VERSION 3.2)\n"
"project(" << setup.projectDescription << ")\n\n";
workspace << "# Define the engines and subengines\n";
writeEngines(setup, workspace);
writeSubEngines(setup, workspace);
workspace << "# Generate options for the engines\n";
writeEngineOptions(workspace);
workspace << "include_directories(${" << setup.projectDescription << "_SOURCE_DIR} ${" << setup.projectDescription << "_SOURCE_DIR}/engines\n"
"$ENV{"<<LIBS_DEFINE<<"}/include)\n\n";
workspace << "# Libraries and features\n";
writeFeatureLibSearch(workspace, setup.useSDL2 ? "sdl2" : "sdl");
for (FeatureList::const_iterator i = setup.features.begin(), end = setup.features.end(); i != end; ++i) {
if (!i->enable || featureExcluded(i->name)) continue;
writeFeatureLibSearch(workspace, i->name);
workspace << "add_definitions(-D" << i->define << ")\n";
}
workspace << "\n";
writeWarnings(workspace);
writeDefines(setup, workspace);
workspace << "# Generate definitions for the engines\n";
writeEngineDefinitions(workspace);
workspace << "# Generate \"engines/plugins_table.h\"\n";
writeGeneratePluginsTable(workspace);
}
void CMakeProvider::writeFeatureLibSearch(std::ofstream &workspace, const char *feature) const {
const Library *library = getLibraryFromFeature(feature);
if (library) {
if (library->module) {
workspace << "Include(" << library->module << ")\n";
}
if (library->package) {
workspace << "Find_Package(" << library->package << " REQUIRED)\n";
}
if (library->includesVar) {
workspace << "include_directories(${" << library->includesVar << "})\n";
}
}
}
void CMakeProvider::writeEngines(const BuildSetup &setup, std::ofstream &workspace) const {
workspace << "set(ENGINES";
for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
// We ignore all sub engines here because they require special handling.
if (!i->enable || isSubEngine(i->name, setup.engines)) {
continue;
}
std::string engineName;
std::transform(i->name.begin(), i->name.end(), std::back_inserter(engineName), toupper);
workspace << " " << engineName;
}
workspace << ")\n";
}
void CMakeProvider::writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const {
for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
// We ignore all sub engines here because they are handled in the inner loop
if (!i->enable || isSubEngine(i->name, setup.engines) || i->subEngines.empty()) {
continue;
}
std::string engineName;
std::transform(i->name.begin(), i->name.end(), std::back_inserter(engineName), toupper);
workspace << "set(SUB_ENGINES_" << engineName;
for (StringList::const_iterator j = i->subEngines.begin(), subEnd = i->subEngines.end(); j != subEnd; ++j) {
const EngineDesc &subEngine = findEngineDesc(*j, setup.engines);
if (!subEngine.enable) continue;
std::string subEngineName;
std::transform(j->begin(), j->end(), std::back_inserter(subEngineName), toupper);
workspace << " " << subEngineName;
}
workspace << ")\n";
}
workspace << "\n";
}
void CMakeProvider::createProjectFile(const std::string &name, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList) {
const std::string projectFile = setup.outputDir + "/CMakeLists.txt";
std::ofstream project(projectFile.c_str(), std::ofstream::out | std::ofstream::app);
if (!project)
error("Could not open \"" + projectFile + "\" for writing");
if (name == setup.projectName) {
project << "add_executable(" << name << "\n";
} else {
std::string engineName;
std::transform(name.begin(), name.end(), std::back_inserter(engineName), toupper);
project << "if (ENABLE_" << engineName << ")\n";
project << "add_library(" << name << "\n";
}
std::string modulePath;
if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
modulePath = moduleDir.substr(setup.srcDir.size());
if (!modulePath.empty() && modulePath.at(0) == '/')
modulePath.erase(0, 1);
}
if (modulePath.size())
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
else
addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
project << ")\n";
if (name != setup.projectName) {
project << "endif()\n";
}
project << "# Libraries\n";
if (name == setup.projectName) {
const Library *sdlLibrary = getLibraryFromFeature(setup.useSDL2 ? "sdl2" : "sdl");
project << "target_link_libraries(" << name << " ${" << sdlLibrary->librariesVar << "})\n";
for (FeatureList::const_iterator i = setup.features.begin(), end = setup.features.end(); i != end; ++i) {
if (!i->enable || featureExcluded(i->name)) continue;
const Library *library = getLibraryFromFeature(i->name);
if (!library) continue;
if (library->librariesVar) {
project << "target_link_libraries(" << name << " ${" << library->librariesVar << "})\n";
} else {
project << "target_link_libraries(" << name << " " << library->libraries << ")\n";
}
}
project << "if (WIN32)\n";
project << " target_sources(" << name << " PUBLIC dists/" << name << ".rc)\n";
project << " target_link_libraries(" << name << " winmm)\n";
project << "endif()\n";
project << "\n";
project << "# Engines libraries handling\n";
writeEnginesLibrariesHandling(setup, project);
project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD 11)\n";
project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD_REQUIRED ON)\n";
}
}
void CMakeProvider::writeWarnings(std::ofstream &output) const {
output << "SET (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}";
for (StringList::const_iterator i = _globalWarnings.begin(); i != _globalWarnings.end(); ++i) {
output << " " << *i;
}
output << "\")\n";
}
void CMakeProvider::writeDefines(const BuildSetup &setup, std::ofstream &output) const {
output << "if (WIN32)\n";
output << " add_definitions(-DWIN32)\n";
output << "else()\n";
output << " add_definitions(-DPOSIX)\n";
output << "endif()\n";
output << "if (CMAKE_SIZEOF_VOID_P MATCHES 8)\n";
output << " add_definitions(-DSCUMM_64BITS)\n";
output << "endif()\n";
output << "add_definitions(-DSDL_BACKEND)\n\n";
}
void CMakeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) {
for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
const FileNode *node = *i;
if (!node->children.empty()) {
writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
} else {
std::string name, ext;
splitFilename(node->name, name, ext);
projectFile << "\t" << filePrefix + node->name << "\n";
}
}
}
const char *CMakeProvider::getProjectExtension() {
return ".txt";
}
void CMakeProvider::writeEngineOptions(std::ofstream &workspace) const {
workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
workspace << " OPTION(ENABLE_${ENGINE} \"Enable ${ENGINE}\" ON)\n";
workspace << "endforeach(ENGINE)\n\n";
}
void CMakeProvider::writeGeneratePluginsTable(std::ofstream &workspace) const {
workspace << "file(REMOVE \"engines/plugins_table.h\")\n";
workspace << "file(APPEND \"engines/plugins_table.h\" \"/* This file is automatically generated by CMake */\\n\")\n";
workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
workspace << " if (ENABLE_${ENGINE})\n";
workspace << " file(APPEND \"engines/plugins_table.h\" \"#if PLUGIN_ENABLED_STATIC(${ENGINE})\\n\")\n";
workspace << " file(APPEND \"engines/plugins_table.h\" \"LINK_PLUGIN(${ENGINE})\\n\")\n";
workspace << " file(APPEND \"engines/plugins_table.h\" \"#endif\\n\")\n";
workspace << " endif()\n";
workspace << "endforeach()\n\n";
}
void CMakeProvider::writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const {
workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
workspace << " if (ENABLE_${ENGINE})\n";
workspace << " string(TOLOWER ${ENGINE} ENGINE_LIB)\n\n";
workspace << " # Enable C++11\n";
workspace << " set_property(TARGET ${ENGINE_LIB} PROPERTY CXX_STANDARD 11)\n";
workspace << " set_property(TARGET ${ENGINE_LIB} PROPERTY CXX_STANDARD_REQUIRED ON)\n\n";
workspace << " # Link against the engine\n";
workspace << " target_link_libraries("<< setup.projectName <<" ${ENGINE_LIB})\n";
workspace << " endif()\n";
workspace << "endforeach()\n\n";
}
void CMakeProvider::writeEngineDefinitions(std::ofstream &workspace) const {
workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
workspace << " if (ENABLE_${ENGINE})\n";
workspace << " add_definitions(-DENABLE_${ENGINE})\n";
workspace << " foreach(SUB_ENGINE IN LISTS SUB_ENGINES_${ENGINE})\n";
workspace << " add_definitions(-DENABLE_${SUB_ENGINE})\n";;
workspace << " endforeach(SUB_ENGINE)\n";
workspace << " endif()\n";
workspace << "endforeach()\n\n";
}
bool CMakeProvider::featureExcluded(const char *name) const {
return std::strcmp(name, "nasm") == 0 ||
std::strcmp(name, "updates") == 0 ; // NASM is not supported for now
}
const EngineDesc &CMakeProvider::findEngineDesc(const std::string &name, const EngineDescList &engines) const {
for (EngineDescList::const_iterator i = engines.begin(), end = engines.end(); i != end; ++i) {
if (i->name == name) {
return *i;
}
}
error("Unable to find requested engine");
}
} // End of CreateProjectTool namespace

View file

@ -0,0 +1,85 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef TOOLS_CREATE_PROJECT_CMAKE_H
#define TOOLS_CREATE_PROJECT_CMAKE_H
#include "create_project.h"
namespace CreateProjectTool {
/**
* A ProjectProvider used to generate CMake project descriptions
*
* Generated CMake projects are minimal, and will only work with GCC.
*/
class CMakeProvider : public ProjectProvider {
public:
CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0);
protected:
void createWorkspace(const BuildSetup &setup);
void createOtherBuildFiles(const BuildSetup &) {}
void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {}
void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
const StringList &includeList, const StringList &excludeList);
void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
const char *getProjectExtension();
private:
/**
* CMake properties for a library required by a feature
*/
struct Library {
const char *feature;
const char *module;
const char *package;
const char *includesVar;
const char *librariesVar;
const char *libraries;
};
const Library *getLibraryFromFeature(const char *feature) const;
void writeWarnings(std::ofstream &output) const;
void writeDefines(const BuildSetup &setup, std::ofstream &output) const;
void writeEngines(const BuildSetup &setup, std::ofstream &workspace) const;
void writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const;
void writeEngineOptions(std::ofstream &workspace) const;
void writeGeneratePluginsTable(std::ofstream &workspace) const;
void writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const;
void writeEngineDefinitions(std::ofstream &workspace) const;
void writeFeatureLibSearch(std::ofstream &workspace, const char *feature) const;
bool featureExcluded(const char *name) const;
const EngineDesc &findEngineDesc(const std::string &name, const EngineDescList &engines) const;
};
} // End of CreateProjectTool namespace
#endif // TOOLS_CREATE_PROJECT_CMAKE_H

View file

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.2)
project(create_project)
set(SOURCE_FILES
../cmake.cpp
../cmake.h
../codeblocks.cpp
../codeblocks.h
../create_project.cpp
../create_project.h
../msbuild.cpp
../msbuild.h
../msvc.cpp
../msvc.h
../visualstudio.cpp
../visualstudio.h
../xcode.cpp
../xcode.h
)
add_executable(create_project ${SOURCE_FILES})

View file

@ -31,6 +31,7 @@
#include "config.h" #include "config.h"
#include "create_project.h" #include "create_project.h"
#include "cmake.h"
#include "codeblocks.h" #include "codeblocks.h"
#include "msvc.h" #include "msvc.h"
#include "visualstudio.h" #include "visualstudio.h"
@ -53,7 +54,7 @@
#define USE_WIN32_API #define USE_WIN32_API
#endif #endif
#ifdef USE_WIN32_API #if (defined(_WIN32) || defined(WIN32))
#include <windows.h> #include <windows.h>
#else #else
#include <sstream> #include <sstream>
@ -83,10 +84,18 @@ std::string unifyPath(const std::string &path);
* @param exe Name of the executable. * @param exe Name of the executable.
*/ */
void displayHelp(const char *exe); void displayHelp(const char *exe);
/**
* Build a list of options to enable or disable GCC warnings
*
* @param globalWarnings Resulting list of warnings
*/
void addGCCWarnings(StringList &globalWarnings);
} // End of anonymous namespace } // End of anonymous namespace
enum ProjectType { enum ProjectType {
kProjectNone, kProjectNone,
kProjectCMake,
kProjectCodeBlocks, kProjectCodeBlocks,
kProjectMSVC, kProjectMSVC,
kProjectXcode kProjectXcode
@ -125,7 +134,6 @@ int main(int argc, char *argv[]) {
ProjectType projectType = kProjectNone; ProjectType projectType = kProjectNone;
int msvcVersion = 12; int msvcVersion = 12;
bool useSDL2 = false;
// Parse command line arguments // Parse command line arguments
using std::cout; using std::cout;
@ -142,6 +150,14 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} else if (!std::strcmp(argv[i], "--cmake")) {
if (projectType != kProjectNone) {
std::cerr << "ERROR: You cannot pass more than one project type!\n";
return -1;
}
projectType = kProjectCMake;
} else if (!std::strcmp(argv[i], "--codeblocks")) { } else if (!std::strcmp(argv[i], "--codeblocks")) {
if (projectType != kProjectNone) { if (projectType != kProjectNone) {
std::cerr << "ERROR: You cannot pass more than one project type!\n"; std::cerr << "ERROR: You cannot pass more than one project type!\n";
@ -269,7 +285,7 @@ int main(int argc, char *argv[]) {
} else if (!std::strcmp(argv[i], "--tests")) { } else if (!std::strcmp(argv[i], "--tests")) {
setup.tests = true; setup.tests = true;
} else if (!std::strcmp(argv[i], "--sdl2")) { } else if (!std::strcmp(argv[i], "--sdl2")) {
useSDL2 = true; setup.useSDL2 = true;
} else { } else {
std::cerr << "ERROR: Unknown parameter \"" << argv[i] << "\"\n"; std::cerr << "ERROR: Unknown parameter \"" << argv[i] << "\"\n";
return -1; return -1;
@ -335,10 +351,7 @@ int main(int argc, char *argv[]) {
StringList featureDefines = getFeatureDefines(setup.features); StringList featureDefines = getFeatureDefines(setup.features);
setup.defines.splice(setup.defines.begin(), featureDefines); setup.defines.splice(setup.defines.begin(), featureDefines);
// Windows only has support for the SDL backend, so we hardcode it here (along with winmm) if (projectType == kProjectXcode) {
if (projectType != kProjectXcode) {
setup.defines.push_back("WIN32");
} else {
setup.defines.push_back("POSIX"); setup.defines.push_back("POSIX");
// Define both MACOSX, and IPHONE, but only one of them will be associated to the // Define both MACOSX, and IPHONE, but only one of them will be associated to the
// correct target by the Xcode project provider. // correct target by the Xcode project provider.
@ -347,13 +360,42 @@ int main(int argc, char *argv[]) {
// the files, according to the target. // the files, according to the target.
setup.defines.push_back("MACOSX"); setup.defines.push_back("MACOSX");
setup.defines.push_back("IPHONE"); setup.defines.push_back("IPHONE");
} else if (projectType == kProjectMSVC || projectType == kProjectCodeBlocks) {
// Windows only has support for the SDL backend, so we hardcode it here (along with winmm)
setup.defines.push_back("WIN32");
} else {
// As a last resort, select the backend files to build based on the platform used to build create_project.
// This is broken when cross compiling.
#if defined(_WIN32) || defined(WIN32)
setup.defines.push_back("WIN32");
#else
setup.defines.push_back("POSIX");
#endif
} }
bool updatesEnabled = false;
for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) {
if (i->enable && !strcmp(i->name, "updates"))
updatesEnabled = true;
}
if (updatesEnabled) {
setup.defines.push_back("USE_SPARKLE");
if (projectType != kProjectXcode)
setup.libraries.push_back("winsparkle");
else
setup.libraries.push_back("sparkle");
}
setup.defines.push_back("SDL_BACKEND"); setup.defines.push_back("SDL_BACKEND");
if (!useSDL2) { if (!setup.useSDL2) {
cout << "\nLinking to SDL 1.2\n\n"; cout << "\nBuilding against SDL 1.2\n\n";
setup.libraries.push_back("sdl"); setup.libraries.push_back("sdl");
} else { } else {
cout << "\nLinking to SDL 2.0\n\n"; cout << "\nBuilding against SDL 2.0\n\n";
// TODO: This also defines USE_SDL2 in the preprocessor, we don't do
// this in our configure/make based build system. Adapt create_project
// to replicate this behavior.
setup.defines.push_back("USE_SDL2");
setup.libraries.push_back("sdl2"); setup.libraries.push_back("sdl2");
} }
setup.libraries.push_back("winmm"); setup.libraries.push_back("winmm");
@ -380,49 +422,25 @@ int main(int argc, char *argv[]) {
std::cerr << "ERROR: No project type has been specified!\n"; std::cerr << "ERROR: No project type has been specified!\n";
return -1; return -1;
case kProjectCMake:
if (setup.devTools || setup.tests) {
std::cerr << "ERROR: Building tools or tests is not supported for the CMake project type!\n";
return -1;
}
addGCCWarnings(globalWarnings);
provider = new CreateProjectTool::CMakeProvider(globalWarnings, projectWarnings);
break;
case kProjectCodeBlocks: case kProjectCodeBlocks:
if (setup.devTools || setup.tests) { if (setup.devTools || setup.tests) {
std::cerr << "ERROR: Building tools or tests is not supported for the CodeBlocks project type!\n"; std::cerr << "ERROR: Building tools or tests is not supported for the CodeBlocks project type!\n";
return -1; return -1;
} }
//////////////////////////////////////////////////////////////////////////// addGCCWarnings(globalWarnings);
// Code::Blocks is using GCC behind the scenes, so we need to pass a list
// of options to enable or disable warnings
////////////////////////////////////////////////////////////////////////////
//
// -Wall
// enable all warnings
//
// -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
// disable annoying and not-so-useful warnings
//
// -Wpointer-arith -Wcast-qual -Wcast-align
// -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
// enable even more warnings...
//
// -fno-rtti -fno-exceptions -fcheck-new
// disable RTTI and exceptions, and enable checking of pointers returned
// by "new"
//
////////////////////////////////////////////////////////////////////////////
globalWarnings.push_back("-Wall");
globalWarnings.push_back("-Wno-long-long");
globalWarnings.push_back("-Wno-multichar");
globalWarnings.push_back("-Wno-unknown-pragmas");
globalWarnings.push_back("-Wno-reorder");
globalWarnings.push_back("-Wpointer-arith");
globalWarnings.push_back("-Wcast-qual");
globalWarnings.push_back("-Wcast-align");
globalWarnings.push_back("-Wshadow");
globalWarnings.push_back("-Wimplicit");
globalWarnings.push_back("-Wnon-virtual-dtor");
globalWarnings.push_back("-Wwrite-strings");
// The following are not warnings at all... We should consider adding them to
// a different list of parameters.
globalWarnings.push_back("-fno-exceptions");
globalWarnings.push_back("-fcheck-new");
provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings); provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings);
@ -636,6 +654,7 @@ void displayHelp(const char *exe) {
" Additionally there are the following switches for changing various settings:\n" " Additionally there are the following switches for changing various settings:\n"
"\n" "\n"
"Project specific settings:\n" "Project specific settings:\n"
" --cmake build CMake project files\n"
" --codeblocks build Code::Blocks project files\n" " --codeblocks build Code::Blocks project files\n"
" --msvc build Visual Studio project files\n" " --msvc build Visual Studio project files\n"
" --xcode build XCode project files\n" " --xcode build XCode project files\n"
@ -690,6 +709,41 @@ void displayHelp(const char *exe) {
cout.setf(std::ios_base::right, std::ios_base::adjustfield); cout.setf(std::ios_base::right, std::ios_base::adjustfield);
} }
void addGCCWarnings(StringList &globalWarnings) {
////////////////////////////////////////////////////////////////////////////
//
// -Wall
// enable all warnings
//
// -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
// disable annoying and not-so-useful warnings
//
// -Wpointer-arith -Wcast-qual -Wcast-align
// -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
// enable even more warnings...
//
// -fno-exceptions -fcheck-new
// disable exceptions, and enable checking of pointers returned by "new"
//
////////////////////////////////////////////////////////////////////////////
globalWarnings.push_back("-Wall");
globalWarnings.push_back("-Wno-long-long");
globalWarnings.push_back("-Wno-multichar");
globalWarnings.push_back("-Wno-unknown-pragmas");
globalWarnings.push_back("-Wno-reorder");
globalWarnings.push_back("-Wpointer-arith");
globalWarnings.push_back("-Wcast-qual");
globalWarnings.push_back("-Wcast-align");
globalWarnings.push_back("-Wshadow");
globalWarnings.push_back("-Wnon-virtual-dtor");
globalWarnings.push_back("-Wwrite-strings");
// The following are not warnings at all... We should consider adding them to
// a different list of parameters.
globalWarnings.push_back("-fno-exceptions");
globalWarnings.push_back("-fcheck-new");
}
/** /**
* Parse the configure.engine file of a given engine directory and return a * Parse the configure.engine file of a given engine directory and return a
* list of all defined engines. * list of all defined engines.
@ -937,12 +991,12 @@ const Feature s_features[] = {
// Libraries // Libraries
{ "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" }, { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" },
{ "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" }, { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" },
{ "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", false, "Ogg Vorbis support" }, { "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", false, "Ogg Vorbis support" }, // ResidualVM change
{ "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", false, "FLAC support" }, { "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", false, "FLAC support" }, // ResidualVM change
{ "png", "USE_PNG", "libpng", false, "libpng support" }, { "png", "USE_PNG", "libpng", false, "libpng support" },
{ "faad", "USE_FAAD", "libfaad", false, "AAC support" }, { "faad", "USE_FAAD", "libfaad", false, "AAC support" },
{ "mpeg2", "USE_MPEG2", "libmpeg2", true, "MPEG-2 support" }, { "mpeg2", "USE_MPEG2", "libmpeg2", true, "MPEG-2 support" }, // ResidualVM change
{ "theora", "USE_THEORADEC", "libtheora_static", false, "Theora decoding support" }, { "theora", "USE_THEORADEC", "libtheora_static", false, "Theora decoding support" }, // ResidualVM change
{ "freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" }, { "freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" },
{ "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" }, { "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" },
{"fluidsynth", "USE_FLUIDSYNTH", "libfluidsynth", true, "FluidSynth support" }, {"fluidsynth", "USE_FLUIDSYNTH", "libfluidsynth", true, "FluidSynth support" },
@ -952,29 +1006,22 @@ const Feature s_features[] = {
{ "scalers", "USE_SCALERS", "", true, "Scalers" }, { "scalers", "USE_SCALERS", "", true, "Scalers" },
{ "hqscalers", "USE_HQ_SCALERS", "", true, "HQ scalers" }, { "hqscalers", "USE_HQ_SCALERS", "", true, "HQ scalers" },
{ "16bit", "USE_RGB_COLOR", "", true, "16bit color support" }, { "16bit", "USE_RGB_COLOR", "", true, "16bit color support" },
{ "mt32emu", "USE_MT32EMU", "", false, "integrated MT-32 emulator" }, { "mt32emu", "USE_MT32EMU", "", false, "integrated MT-32 emulator" }, // ResidualVM change
{ "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling. { "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling.
{ "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" }, { "opengl", "USE_OPENGL", "", true, "OpenGL support" },
{ "opengles", "USE_GLES", "", true, "forced OpenGL ES mode" },
{ "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" }, { "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" },
{ "translation", "USE_TRANSLATION", "", true, "Translation support" }, { "translation", "USE_TRANSLATION", "", true, "Translation support" },
{ "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"}, { "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"},
{ "keymapper", "ENABLE_KEYMAPPER", "", false, "Keymapper support"}, { "keymapper", "ENABLE_KEYMAPPER", "", false, "Keymapper support"},
{ "eventrecorder", "ENABLE_EVENTRECORDER", "", false, "Event recorder support"}, { "eventrecorder", "ENABLE_EVENTRECORDER", "", false, "Event recorder support"},
{ "updates", "USE_UPDATES", "", false, "Updates support"},
{ "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there { "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there
// is just no current way of properly detecting this... // is just no current way of properly detecting this...
}; };
const Tool s_tools[] = { const Tool s_tools[] = {
{ "create_drascula", true},
{ "create_hugo", true},
{ "create_kyradat", true},
{ "create_lure", true},
{ "create_neverhood", true},
{ "create_teenagent", true},
{ "create_tony", true},
{ "create_toon", true},
{ "create_translations", true}, { "create_translations", true},
{ "qtable", true}
}; };
} // End of anonymous namespace } // End of anonymous namespace
@ -1156,7 +1203,7 @@ bool compareNodes(const FileNode *l, const FileNode *r) {
FileList listDirectory(const std::string &dir) { FileList listDirectory(const std::string &dir) {
FileList result; FileList result;
#ifdef USE_WIN32_API #if defined(_WIN32) || defined(WIN32)
WIN32_FIND_DATA fileInformation; WIN32_FIND_DATA fileInformation;
HANDLE fileHandle = FindFirstFile((dir + "/*").c_str(), &fileInformation); HANDLE fileHandle = FindFirstFile((dir + "/*").c_str(), &fileInformation);
@ -1359,7 +1406,7 @@ void ProjectProvider::createProject(BuildSetup &setup) {
in.push_back(setup.srcDir + "/COPYING.FREEFONT"); in.push_back(setup.srcDir + "/COPYING.FREEFONT");
in.push_back(setup.srcDir + "/COPYRIGHT"); in.push_back(setup.srcDir + "/COPYRIGHT");
in.push_back(setup.srcDir + "/NEWS"); in.push_back(setup.srcDir + "/NEWS");
in.push_back(setup.srcDir + "/README.md"); in.push_back(setup.srcDir + "/README.md"); // ResidualVM change
in.push_back(setup.srcDir + "/TODO"); in.push_back(setup.srcDir + "/TODO");
// Create the main project file. // Create the main project file.

View file

@ -229,15 +229,17 @@ struct BuildSetup {
StringList testDirs; ///< List of all folders containing tests StringList testDirs; ///< List of all folders containing tests
bool devTools; ///< Generate project files for the tools bool devTools; ///< Generate project files for the tools
bool tests; ///< Generate project files for the tests bool tests; ///< Generate project files for the tests
bool runBuildEvents; ///< Run build events as part of the build (generate revision number and copy engine/theme data & needed files to the build folder bool runBuildEvents; ///< Run build events as part of the build (generate revision number and copy engine/theme data & needed files to the build folder
bool createInstaller; ///< Create NSIS installer after the build bool createInstaller; ///< Create NSIS installer after the build
bool useSDL2; ///< Whether to use SDL2 or not.
BuildSetup() { BuildSetup() {
devTools = false; devTools = false;
tests = false; tests = false;
runBuildEvents = false; runBuildEvents = false;
createInstaller = false; createInstaller = false;
useSDL2 = false;
} }
}; };

View file

@ -2,6 +2,7 @@
MODULE := devtools/create_project MODULE := devtools/create_project
MODULE_OBJS := \ MODULE_OBJS := \
cmake.o \
create_project.o \ create_project.o \
codeblocks.o \ codeblocks.o \
msvc.o \ msvc.o \

Some files were not shown because too many files have changed in this diff Show more