diff options
author | Vicent Marti | 2008-09-20 11:21:35 +0000 |
---|---|---|
committer | Vicent Marti | 2008-09-20 11:21:35 +0000 |
commit | 9feb0f5f6710970fb64e525622d22a5aca18de92 (patch) | |
tree | 620d6c7b94be463bd71c7419e41c7e8d120305d4 /common | |
parent | c7e07102b69a5fd66a89605c619e008060744bf4 (diff) | |
parent | 221b4a47aea63bdf05b17def32f2a722f230d433 (diff) | |
download | scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.tar.gz scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.tar.bz2 scummvm-rg350-9feb0f5f6710970fb64e525622d22a5aca18de92.zip |
- Merged the new RTL changes into the branch.
- Fixed conflicts.
- Added new RTL dialogs to the Theme Description files.
Full SVNMerge log:
==================
Merged revisions 33928,33930,33932-33936,33938-33940,33942-33943,33948,33950,33953,33967,33973,33976,33978,33980,33985,33991,33993,33999-34000,34006,34009,34011,34013,34015,34019,34021-34023,34025,34027-34028,34030,34032-34034,34036,34038-34039,34041,34046-34048,34050-34055,34057,34059-34065,34067,34072,34074,34076,34078-34081,34084,34086-34087,34089-34090,34093,34096-34102,34104,34107,34113,34116,34119,34122,34124,34126,34128,34131-34132,34135,34138,34141,34144,34146,34149,34152-34154,34156-34157,34160,34163-34164,34169,34173,34179-34194,34196-34198,34200-34201,34205-34206,34208-34217,34219-34225,34227-34228,34234-34237,34239-34249,34251-34279,34281-34284,34286-34288,34290-34320,34323-34324,34326,34328-34329,34332,34334,34336,34338-34340,34343-34353,34356-34357,34359-34371,34373,34375,34378,34381-34382,34384-34385,34389-34391,34393-34394,34396-34397,34399-34405,34407-34409,34411,34413,34415,34417-34420,34423-34426,34428-34438,34440-34454,34456-34458,34460,34462-34469,34472,34474,34479-34481,34483-34498,34501-34505,34508,34511-34518,34520-34524,34526-34563,34566-34569,34571-34590,34592,34595-34599,34602-34603 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
........
r33928 | peres001 | 2008-08-16 08:39:58 +0200 (Sat, 16 Aug 2008) | 1 line
Fixed label positioning in BRA.
........
r33930 | peres001 | 2008-08-16 09:47:44 +0200 (Sat, 16 Aug 2008) | 1 line
Enabled interaction with movable zones - mainly NPCs - which are linked to animations.
........
r33932 | anotherguest | 2008-08-16 10:49:36 +0200 (Sat, 16 Aug 2008) | 1 line
Enable CINE
........
r33933 | peres001 | 2008-08-16 10:57:07 +0200 (Sat, 16 Aug 2008) | 1 line
Fixed half-invisible balloons.
........
r33934 | fingolfin | 2008-08-16 13:37:36 +0200 (Sat, 16 Aug 2008) | 1 line
Replaced ARM_USE_GFX_ASM by USE_ARM_GFX_ASM
........
r33935 | buddha_ | 2008-08-16 13:38:43 +0200 (Sat, 16 Aug 2008) | 1 line
Changed AdlibRegisterSoundInstrument's member variables from unsigned 16-bit to unsigned 8-bit. Maybe this'll fix the crash in AdlibSoundDriver::setupInstrument() eriktorbjorn was getting in Future Wars when teleporting from the photocopier room to the swamp. There was a OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease) call with sustainRelease = 65452. Now there shouldn't be any such calls made because the sustainRelease value is always 8-bit now. Hopefully this won't break anything.
........
r33936 | eriktorbjorn | 2008-08-16 13:50:36 +0200 (Sat, 16 Aug 2008) | 2 lines
Removed unused variable.
........
r33938 | athrxx | 2008-08-16 14:38:37 +0200 (Sat, 16 Aug 2008) | 4 lines
- KYRA: FM-Towns/PC-98 Audio: fixed several bugs and got rid of some floating point arithmetic (or at least replaced some doubles with floats)
- Improved support for PC-98 music: HOF tracks seem to be fine, KYRA should be okay, too (I can't compare with an emulator since I am missing the floppy boot disk with the executable)
- There are still tempo issues. Some tracks play way too slow, others way too fast
- PC-98 sound effects in Kyra 1 don't work (I would need the floppy disk with the executable for that)
........
r33939 | peres001 | 2008-08-16 14:49:27 +0200 (Sat, 16 Aug 2008) | 1 line
Multiple balloons (answers) are now positioned correctly in BRA.
........
r33940 | peres001 | 2008-08-16 15:10:54 +0200 (Sat, 16 Aug 2008) | 1 line
Extended balloon manager to handle color constants and fixed color of text in balloons for BRA.
........
r33942 | athrxx | 2008-08-16 16:25:03 +0200 (Sat, 16 Aug 2008) | 1 line
KYRA: Fm-Towns Audio: fixed music fading
........
r33943 | athrxx | 2008-08-16 17:24:52 +0200 (Sat, 16 Aug 2008) | 1 line
KYRA: Fm-Towns Audio: fixed crash
........
r33948 | lordhoto | 2008-08-16 23:51:56 +0200 (Sat, 16 Aug 2008) | 2 lines
Cleanup.
........
r33950 | buddha_ | 2008-08-17 00:15:57 +0200 (Sun, 17 Aug 2008) | 5 lines
Workaround for bug #2054882 (FW: Impossible to survive entering monastery (regression)):
For Future Wars o1_compareGlobalVar now compares global variable 255 to be equal to everything.
The scripts probably tested global variable 255 for equality with some value (Maybe 143?)
to see whether copy protection was properly passed.
........
r33953 | lordhoto | 2008-08-17 00:30:47 +0200 (Sun, 17 Aug 2008) | 2 lines
Properly close files opened when checking for config file on WIN32.
........
r33967 | buddha_ | 2008-08-17 12:43:54 +0200 (Sun, 17 Aug 2008) | 1 line
Forwardport of branch-0-12-0's r33966: Fix to Future Wars's rendering of type 0 overlays (i.e. color sprites). Objects with negative frame values are supposed to be jumped over (Verified with disassembly).
........
r33973 | sev | 2008-08-17 20:58:23 +0200 (Sun, 17 Aug 2008) | 2 lines
Patch #2045543: Possible fix for Drascula's decodeRLE()
........
r33976 | buddha_ | 2008-08-17 22:53:18 +0200 (Sun, 17 Aug 2008) | 1 line
Added some documentation about how data is unpacked in gfxConvertSpriteToRaw (Learned this from trying to implement convertPI1_2 i.e. gfxConvertSpriteToRaw myself to see if that was the problem with the Operation Stealth's labyrinth arcade sequence).
........
r33978 | anotherguest | 2008-08-17 23:16:07 +0200 (Sun, 17 Aug 2008) | 1 line
Improved filehandling for securer and quicker way to get ref to file session
........
r33980 | athrxx | 2008-08-18 00:49:34 +0200 (Mon, 18 Aug 2008) | 4 lines
KYRA: FM-Towns/PC-98 Audio:
- improved accuracy
- complete percussion channel support (does not work atm though, since the instrument data is missing)
- some cleanup
........
r33985 | peres001 | 2008-08-18 09:12:05 +0200 (Mon, 18 Aug 2008) | 3 lines
* Split up blt routine (there is room for a ton of improvements)
* Added scaling as a new blt option
* Activated scaling for the main character in BRA
........
r33991 | knakos | 2008-08-18 19:24:25 +0200 (Mon, 18 Aug 2008) | 1 line
do away with the smush force redraw hack
........
r33993 | athrxx | 2008-08-18 19:42:32 +0200 (Mon, 18 Aug 2008) | 3 lines
KYRA: FM-Towns/PC-98 Audio:
- adpcm decoding for rhythm channel
- cleanup
........
r33999 | knakos | 2008-08-18 20:15:32 +0200 (Mon, 18 Aug 2008) | 1 line
switching to libTremolo
........
r34000 | anotherguest | 2008-08-18 20:16:24 +0200 (Mon, 18 Aug 2008) | 1 line
Do Deinit of pixel buffer when hiding menu.That saves 600KB in VGA games for low memory devices.
........
r34006 | robinwatts | 2008-08-18 22:04:15 +0200 (Mon, 18 Aug 2008) | 8 lines
Updates to the scummvm blitting code as discussed on the mailing list.
1) Remove DS version of the ARM blitters in favour of the 'normal' ARM one.
2) Update normal ARM blitter to use Carlo's clever algorithm.
3) Update C version with Max Horns patch (slightly tweaked - counting down
on loops is better, M'kay).
........
r34009 | tramboi | 2008-08-18 22:43:44 +0200 (Mon, 18 Aug 2008) | 1 line
Compile fix for 34006
........
r34011 | anotherguest | 2008-08-18 23:09:46 +0200 (Mon, 18 Aug 2008) | 1 line
Enable quick F5 save key for Touche!
........
r34013 | anotherguest | 2008-08-18 23:19:18 +0200 (Mon, 18 Aug 2008) | 1 line
Enable save game action key in Touche for WinCE devices.
........
r34015 | athrxx | 2008-08-19 03:00:15 +0200 (Tue, 19 Aug 2008) | 2 lines
fixed bug that caused a lockup in certain configurations when the music was fading
........
r34019 | athrxx | 2008-08-19 08:31:57 +0200 (Tue, 19 Aug 2008) | 1 line
fixed warnings
........
r34021 | anotherguest | 2008-08-19 09:44:35 +0200 (Tue, 19 Aug 2008) | 1 line
Remove Deinit when hiding menu! UI infoprints needed the pixelbuffer.
........
r34022 | peres001 | 2008-08-19 10:08:32 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed segfault when quitting BRA.
........
r34023 | thebluegr | 2008-08-19 10:49:53 +0200 (Tue, 19 Aug 2008) | 1 line
Fix for bug #2057194 - "IHNM: -x option crashes ScummVM, if savegame doesn't exist"
........
r34025 | anotherguest | 2008-08-19 10:54:28 +0200 (Tue, 19 Aug 2008) | 1 line
Don't Use CEikonEnv::Static, get FS from system class instead
........
r34027 | anotherguest | 2008-08-19 11:26:41 +0200 (Tue, 19 Aug 2008) | 1 line
Use the correct and specified datatype int32 instead of only int.
........
r34028 | thebluegr | 2008-08-19 12:05:07 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed regression from commit #33576. Fixes bug #2056282 - "DRASCULA: can't use inventory objects"
........
r34030 | thebluegr | 2008-08-19 12:12:35 +0200 (Tue, 19 Aug 2008) | 1 line
Fix for bug #2057664 - "DRASCULA: No GUI warning when playing from CD"
........
r34032 | fingolfin | 2008-08-19 12:52:39 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed GCC warning
........
r34033 | fingolfin | 2008-08-19 12:58:35 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed 'make install' when building outside srcdir
........
r34034 | buddha_ | 2008-08-19 13:55:20 +0200 (Tue, 19 Aug 2008) | 5 lines
Fix for bug #2057637: FW: Spaceship glitches in demo (regression).
This was caused by assuming in-place decompression is ok, it wasn't,
although AFAIK the original did decompression in-place too.
Changed unpacking to be done not in-place and the glitch vanished.
Also changed the unpacker to also handle uncompressed input data.
........
r34036 | buddha_ | 2008-08-19 15:05:38 +0200 (Tue, 19 Aug 2008) | 6 lines
Fix for bug #2057656: FW: Assert during demo (regression).
Future Wars's Amiga demo is trying to load collision data files
'L8_MK.NEO' and 'L23_MK.NEO' that aren't supplied with the demo.
Previous code crashed when a file couldn't be found,
now it gives a warning instead.
........
r34038 | peres001 | 2008-08-19 16:07:48 +0200 (Tue, 19 Aug 2008) | 1 line
Fixed bug in low-level parser. Block comments weren't interpreted correctly.
........
r34039 | buddha_ | 2008-08-19 16:19:28 +0200 (Tue, 19 Aug 2008) | 2 lines
Fix for bug #2057619: FW: Glitches in title display of demo (regression).
Removed incorrect transparency data used for logo. Now it's shown correctly.
........
r34041 | peres001 | 2008-08-19 16:36:05 +0200 (Tue, 19 Aug 2008) | 1 line
Deleted debug code that slipped in.
........
r34046 | peres001 | 2008-08-20 05:36:49 +0200 (Wed, 20 Aug 2008) | 2 lines
* Enlarged buffer for frame decoding. Crashes in the introduction were caused by a small buffer and subsequent out-of-bound writes.
* Disabled debug code.
........
r34047 | peres001 | 2008-08-20 06:02:12 +0200 (Wed, 20 Aug 2008) | 1 line
Engine now returns to the menu when intro is over.
........
r34048 | eriktorbjorn | 2008-08-20 11:12:11 +0200 (Wed, 20 Aug 2008) | 4 lines
I believe the setVolume() function has to be guarded by a mutex. (I added this to
the Tinsel engine a while back to fix mysterious problems, but forgot to add it
elsewhere.) Maybe this will fix the mysterious IHNM crashes, as well?
........
r34050 | eriktorbjorn | 2008-08-20 11:15:59 +0200 (Wed, 20 Aug 2008) | 2 lines
Moved the mutex locking a bit. (Consistent with how the AGOS engine does it.)
........
r34051 | fingolfin | 2008-08-20 12:18:59 +0200 (Wed, 20 Aug 2008) | 1 line
Extended HashMap debug output
........
r34052 | fingolfin | 2008-08-20 13:07:16 +0200 (Wed, 20 Aug 2008) | 1 line
Unified member names in container/storage classes Array, HashMap and String: _storage, _size, _capacity
........
r34053 | lordhoto | 2008-08-20 16:03:34 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement". (Without Max' compressed backward seeking support for now)
........
r34054 | lordhoto | 2008-08-20 16:24:16 +0200 (Wed, 20 Aug 2008) | 4 lines
- Committed Max' compressed save backseeking support from patch #2050337 "KYRA/SCUMM: Thumbnail support/improvement"
- Extended SCUMM engine to support savegames without thumbnail header. (Increased savegame version to prevent saves to be loaded from older ScummVM versions)
- Fixed KYRA to properly support savegames without thumbnail header.
........
r34055 | lordhoto | 2008-08-20 16:30:40 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch #2055831 "KYRA: ResFileEntry parent cache optimization".
........
r34057 | buddha_ | 2008-08-20 16:56:46 +0200 (Wed, 20 Aug 2008) | 1 line
Fix compilation: Changed 'not' to '!'.
........
r34059 | buddha_ | 2008-08-20 17:06:26 +0200 (Wed, 20 Aug 2008) | 1 line
Added graphics/thumbnail.cpp and graphics/thumbnail.h to MSVC project files.
........
r34060 | lordhoto | 2008-08-20 17:08:00 +0200 (Wed, 20 Aug 2008) | 2 lines
Cleanup of thumbnail saving/loading code.
........
r34061 | lordhoto | 2008-08-20 17:12:36 +0200 (Wed, 20 Aug 2008) | 2 lines
Oops fix save loading after last commit.
........
r34062 | buddha_ | 2008-08-20 17:17:35 +0200 (Wed, 20 Aug 2008) | 1 line
Removed already deleted file engines/scumm/thumbnail.cpp from MSVC project files.
........
r34063 | buddha_ | 2008-08-20 17:58:52 +0200 (Wed, 20 Aug 2008) | 1 line
Renamed graphics/scaler/thumbnail.cpp to thumbnail_intern.cpp. Fixes compiling under MSVC.
........
r34064 | athrxx | 2008-08-20 18:14:10 +0200 (Wed, 20 Aug 2008) | 1 line
tempo fix
........
r34065 | buddha_ | 2008-08-20 19:31:35 +0200 (Wed, 20 Aug 2008) | 4 lines
Fix font loading:
Fixes bug #2058539: OS: Assert starting demo (regression).
May possibly also fix bug #2019344: FW: crash with Amiga Italian version (photocopy room),
but not sure about that because I couldn't reproduce the bug myself.
........
r34067 | athrxx | 2008-08-20 21:57:57 +0200 (Wed, 20 Aug 2008) | 2 lines
- add support for Italian floppy version
- more work on fm-towns music tempo
........
r34072 | lordhoto | 2008-08-20 23:23:30 +0200 (Wed, 20 Aug 2008) | 2 lines
Fixed warning.
........
r34074 | lordhoto | 2008-08-20 23:28:59 +0200 (Wed, 20 Aug 2008) | 2 lines
Committed patch from bug #2062926 "GCC 4.x versions not detected by configure script".
........
r34076 | athrxx | 2008-08-21 00:38:36 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: fix bug where pitch wheel is processed twice instead of once
........
r34078 | athrxx | 2008-08-21 04:17:52 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: tempo fix for output rates other than 44100 Hz
........
r34079 | athrxx | 2008-08-21 14:04:55 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: increased precision for envelope generator timing and tempo when using "odd" output rates like 48 kHz or 8 kHz
........
r34080 | peres001 | 2008-08-21 14:11:24 +0200 (Thu, 21 Aug 2008) | 1 line
Removed unused code and structures, and a bit of cleanup.
........
r34081 | buddha_ | 2008-08-21 16:14:33 +0200 (Thu, 21 Aug 2008) | 4 lines
Fix for bug #2057619: FW: Glitches in title display of demo (regression).
This fix doesn't seem to break other Future Wars versions like r34039 did.
Some versions of TITRE.ANI use 15 for transparency color, others use 0.
Previously only one of the choices was supported, now both are recognized.
........
r34084 | buddha_ | 2008-08-21 16:43:03 +0200 (Thu, 21 Aug 2008) | 1 line
Fix typo.
........
r34086 | eriktorbjorn | 2008-08-21 16:52:55 +0200 (Thu, 21 Aug 2008) | 2 lines
Fixed warning.
........
r34087 | athrxx | 2008-08-21 20:24:52 +0200 (Thu, 21 Aug 2008) | 1 line
KYRA: Towns/PC-98-Audio: fixed bug where notes for which the hold flag was set were turned off nonetheless
........
r34089 | peres001 | 2008-08-22 02:19:12 +0200 (Fri, 22 Aug 2008) | 1 line
Implement transition when entering a new location for BRA. Not pixel-perfect, but... let's e happy about it.
........
r34090 | Kirben | 2008-08-22 05:37:43 +0200 (Fri, 22 Aug 2008) | 1 line
Add another 3DO version of Fatty Bear's Birthday Surprise.
........
r34093 | peres001 | 2008-08-22 08:32:12 +0200 (Fri, 22 Aug 2008) | 1 line
Fixed error in parsing.
........
r34096 | fingolfin | 2008-08-22 13:17:12 +0200 (Fri, 22 Aug 2008) | 1 line
code formatting cleanup
........
r34097 | fingolfin | 2008-08-22 13:19:41 +0200 (Fri, 22 Aug 2008) | 1 line
Moved POSIXFilesystemNode class declaration to a new header file, to enable subclassing
........
r34098 | fingolfin | 2008-08-22 13:36:47 +0200 (Fri, 22 Aug 2008) | 1 line
Turned Windows, AmigaOS and POSIX FSFactories into plain classes; no need for them to be singletons (actually true for all other FS factories)
........
r34099 | fingolfin | 2008-08-22 13:41:14 +0200 (Fri, 22 Aug 2008) | 1 line
Symbian backend does not have to implement config file methods, as long as they are identical to those in the SDL backend...
........
r34100 | fingolfin | 2008-08-22 13:45:29 +0200 (Fri, 22 Aug 2008) | 1 line
SDL backend: Simplified openConfigFileForReading/openConfigFileForWriting impl; also init _fsFactory in constructor, as it is needed to load the config file
........
r34101 | fingolfin | 2008-08-22 13:49:34 +0200 (Fri, 22 Aug 2008) | 1 line
Turned SymbianFilesystemFactory from a singleton into a normal class; adapted symbian backend accordingly
........
r34102 | buddha_ | 2008-08-22 14:11:51 +0200 (Fri, 22 Aug 2008) | 1 line
Designate fix for bug #2057619 as a hack, as that's what it is.
........
r34104 | Kirben | 2008-08-22 15:01:23 +0200 (Fri, 22 Aug 2008) | 1 line
Remove warning about change of config file location under Windows, since it is frequently repeated (due to code restructures). The information is mentioned in the README anyway.
........
r34107 | Kirben | 2008-08-23 08:09:30 +0200 (Sat, 23 Aug 2008) | 1 line
Another French version Humongous Catalog and another English DOS version of Fatty Bear's Birthday Surprise.
........
r34113 | drmccoy | 2008-08-23 16:18:12 +0200 (Sat, 23 Aug 2008) | 2 lines
Fixing _itemsMap access (bug #2069177)
........
r34116 | Kirben | 2008-08-24 09:48:44 +0200 (Sun, 24 Aug 2008) | 1 line
Add more versions of HE games.
........
r34119 | aquadran | 2008-08-24 09:54:36 +0200 (Sun, 24 Aug 2008) | 1 line
remove broken code, but i'll add better feature into compression tool
........
r34122 | sev | 2008-08-24 23:28:20 +0200 (Sun, 24 Aug 2008) | 2 lines
Fix inventory.
........
r34124 | sev | 2008-08-24 23:31:20 +0200 (Sun, 24 Aug 2008) | 3 lines
Italian version now has properly translated verbs area as well as numerous
fixes to object names. So new version of packet.005 was prepared.
........
r34126 | sev | 2008-08-24 23:32:37 +0200 (Sun, 24 Aug 2008) | 2 lines
Fixes for Italian strings thanks to glorfindel & co.
........
r34128 | sev | 2008-08-24 23:34:03 +0200 (Sun, 24 Aug 2008) | 2 lines
New drascula.dat with fixed Italian strings
........
r34131 | wjpalenstijn | 2008-08-25 00:09:55 +0200 (Mon, 25 Aug 2008) | 1 line
new tools
........
r34132 | buddha_ | 2008-08-25 01:16:37 +0200 (Mon, 25 Aug 2008) | 3 lines
Fix for bug #2055912: FW: incrustSprite fails on savegame loading.
What little testing I did, this seems to work, but more testing
would be nice.
........
r34135 | peres001 | 2008-08-25 08:32:08 +0200 (Mon, 25 Aug 2008) | 1 line
Added workaround for bug 2070751, long standing issue with item matching exposed after revision 32873.
........
r34138 | knakos | 2008-08-25 10:11:52 +0200 (Mon, 25 Aug 2008) | 1 line
patch 1984130: Add Tremolo info
........
r34141 | knakos | 2008-08-25 10:48:46 +0200 (Mon, 25 Aug 2008) | 1 line
patch 1868881: ini option to disable doubletap rmb
........
r34144 | peres001 | 2008-08-25 11:35:22 +0200 (Mon, 25 Aug 2008) | 1 line
Fixed regression: show mouse and enable input in NS Demo.
........
r34146 | buddha_ | 2008-08-25 14:00:38 +0200 (Mon, 25 Aug 2008) | 1 line
Added a warning to bug #2055912's fix committed in revision 34132.
........
r34149 | lordhoto | 2008-08-25 15:52:10 +0200 (Mon, 25 Aug 2008) | 2 lines
Added short delay(Millis) call while waiting for text input, should reduce CPU usage a little bit.
........
r34152 | thebluegr | 2008-08-25 16:55:11 +0200 (Mon, 25 Aug 2008) | 3 lines
Fix for bug #2073159 - "MICKEY: Incomplete computer message".
Random numbers are calculated from 1 onwards in the preAGI engines, but there was an off-by one error. I'm currently hesitant to add this fix to the 0.12.0 branch, as I'm unsure if it has any possible regressions in Troll's Tale or Winnie the Pooh
........
r34153 | buddha_ | 2008-08-25 17:04:48 +0200 (Mon, 25 Aug 2008) | 1 line
Added Cinematique archive file unpacker and script disassembler to tools. NOT polished code so caveat emptor.
........
r34154 | thebluegr | 2008-08-25 17:07:05 +0200 (Mon, 25 Aug 2008) | 1 line
Fix for bug #2062024 - "DRASCULA: Error talking with blind man"
........
r34156 | buddha_ | 2008-08-25 17:14:20 +0200 (Mon, 25 Aug 2008) | 1 line
Added info about cine_tools to tools/README. Also added a couple of FIXMEs to the cine_tools files about missing endian safeness.
........
r34157 | lordhoto | 2008-08-25 17:14:29 +0200 (Mon, 25 Aug 2008) | 2 lines
Implemented continous screen updating while waiting for text input in v2 GUI. (based on LoK implementation)
........
r34160 | thebluegr | 2008-08-25 17:58:45 +0200 (Mon, 25 Aug 2008) | 2 lines
Fix for original game bug with the wall plug in chapter 5.
Fixes bug #2059621 - DRASCULA: Plug bug
........
r34163 | buddha_ | 2008-08-25 19:41:00 +0200 (Mon, 25 Aug 2008) | 1 line
Reverted revision 34156 and revision 34153 (extract_cine and decine got properly placed in revision 34162).
........
r34164 | knakos | 2008-08-25 19:43:56 +0200 (Mon, 25 Aug 2008) | 1 line
Update readme
........
r34169 | eriktorbjorn | 2008-08-25 20:47:27 +0200 (Mon, 25 Aug 2008) | 5 lines
Refined the workaround for wrongly compressed audio. If the sample rate is given
as 11025 Hz, it should be 11840 Hz. However, a fixed version of compress_queen
won't necessarily produce files with that sample rate, since LAME will resample
the sounds to 12000 Hz. I.e. we can only override the rate if it's exactly 11025.
........
r34173 | wjpalenstijn | 2008-08-25 21:22:16 +0200 (Mon, 25 Aug 2008) | 1 line
package tools_gui as scummvm_tools_gui
........
r34179 | thebluegr | 2008-08-26 09:48:19 +0200 (Tue, 26 Aug 2008) | 1 line
Cleanup
........
r34180 | thebluegr | 2008-08-26 10:05:36 +0200 (Tue, 26 Aug 2008) | 1 line
Merged talk_vonBraun and talk_vonBraunpuerta
........
r34181 | thebluegr | 2008-08-26 10:21:21 +0200 (Tue, 26 Aug 2008) | 1 line
Simplified several calls to copyBackground()
........
r34182 | thebluegr | 2008-08-26 10:35:02 +0200 (Tue, 26 Aug 2008) | 2 lines
talk_dr_grande -> talk_drascula_big
talk_baul -> talk_trunk
........
r34183 | thebluegr | 2008-08-26 12:59:59 +0200 (Tue, 26 Aug 2008) | 1 line
Removed some unneeded sanity checks that have been introduced with the latest cleanups
........
r34184 | Kirben | 2008-08-26 13:15:01 +0200 (Tue, 26 Aug 2008) | 1 line
Add more versions of HE games.
........
r34185 | peres001 | 2008-08-26 14:15:11 +0200 (Tue, 26 Aug 2008) | 1 line
Cleanup.
........
r34186 | thebluegr | 2008-08-26 14:34:05 +0200 (Tue, 26 Aug 2008) | 1 line
Correct fix for bug #2073159 - "MICKEY: Incomplete computer message"
........
r34187 | lordhoto | 2008-08-26 15:51:26 +0200 (Tue, 26 Aug 2008) | 2 lines
Fixed typo. (Thanks to salty-horse for spotting it).
........
r34188 | lordhoto | 2008-08-26 15:56:58 +0200 (Tue, 26 Aug 2008) | 2 lines
And for all of those who love recompiling most of ScummVM... fixed typo properly :-P
........
r34189 | thebluegr | 2008-08-26 16:26:43 +0200 (Tue, 26 Aug 2008) | 1 line
Fix for bug #2057200 - "IHNM: Invisible inventory objects"
........
r34190 | thebluegr | 2008-08-27 12:00:32 +0200 (Wed, 27 Aug 2008) | 1 line
Document some animations
........
r34191 | fingolfin | 2008-08-27 19:41:05 +0200 (Wed, 27 Aug 2008) | 1 line
cleanup
........
r34192 | fingolfin | 2008-08-27 20:21:03 +0200 (Wed, 27 Aug 2008) | 1 line
Slightly cleaned up version of patch #2072006: Enhance OSystem_SDL::setupIcon
........
r34193 | fingolfin | 2008-08-27 20:38:06 +0200 (Wed, 27 Aug 2008) | 1 line
Slightly modified form of patch #2043093: OS/2 patches for posix-fs
........
r34194 | fingolfin | 2008-08-27 20:52:21 +0200 (Wed, 27 Aug 2008) | 1 line
Partial commit of patch #2012839: Atari Patch for adding Native MIDI and Fix Compile
........
r34196 | fingolfin | 2008-08-27 21:29:41 +0200 (Wed, 27 Aug 2008) | 1 line
Fix bug #2078922: DW: Pushing ESC repeatedly at beginning causes odd behavior
........
r34197 | fingolfin | 2008-08-27 22:31:22 +0200 (Wed, 27 Aug 2008) | 1 line
FSNode code: Merged most versions of lastPathComponent() into one new AbstractFilesystemNode::lastPathComponent() method, with customizable path separator character
........
r34198 | fingolfin | 2008-08-27 22:41:28 +0200 (Wed, 27 Aug 2008) | 1 line
Removed various uses of scumm_stricmp by the more readable String::equalsIgnoreCase and String:: compareToIgnoreCase
........
r34200 | fingolfin | 2008-08-28 11:03:43 +0200 (Thu, 28 Aug 2008) | 1 line
Some extra HashMap tests
........
r34201 | fingolfin | 2008-08-29 11:44:05 +0200 (Fri, 29 Aug 2008) | 1 line
Made out-of-memory error in SCUMM a bit more verbose
........
r34205 | lordhoto | 2008-08-30 00:04:15 +0200 (Sat, 30 Aug 2008) | 1 line
Updated msvc8 and msvc9 project files for latest FS changes.
........
r34206 | peres001 | 2008-08-30 12:27:20 +0200 (Sat, 30 Aug 2008) | 1 line
Moved mouse cursor loading/handling to Input class.
........
r34208 | eriktorbjorn | 2008-08-30 14:54:54 +0200 (Sat, 30 Aug 2008) | 2 lines
Added a whitespace, just for salty-horse.
........
r34209 | peres001 | 2008-08-30 17:49:54 +0200 (Sat, 30 Aug 2008) | 1 line
Removed global g_system.
........
r34210 | fingolfin | 2008-08-30 23:03:15 +0200 (Sat, 30 Aug 2008) | 1 line
TINSEL: Added support for the 3,4 and 5 FLAGS (multi lingual) versions of DW (only 4 flags version has been tested; see also bug #2048383)
........
r34211 | fingolfin | 2008-08-30 23:43:36 +0200 (Sat, 30 Aug 2008) | 1 line
cleanup
........
r34212 | fingolfin | 2008-08-30 23:51:13 +0200 (Sat, 30 Aug 2008) | 1 line
TINSEL: Write config changes to disk
........
r34213 | fingolfin | 2008-08-31 00:09:35 +0200 (Sun, 31 Aug 2008) | 1 line
TINSEL: Remove some unused code; and duplicated the 4-FLAGS version detection entry (one copy for each language) for the user's convenience
........
r34214 | fingolfin | 2008-08-31 00:10:48 +0200 (Sun, 31 Aug 2008) | 1 line
TINSEL: The engine version is an integer, not a bitfield
........
r34215 | fingolfin | 2008-08-31 00:16:59 +0200 (Sun, 31 Aug 2008) | 1 line
cleanup
........
r34216 | fingolfin | 2008-08-31 00:26:16 +0200 (Sun, 31 Aug 2008) | 1 line
Fix (?) Solaris detection in some workaround code in the MT-32 emulator
........
r34217 | drmccoy | 2008-08-31 01:59:46 +0200 (Sun, 31 Aug 2008) | 2 lines
Added some The Last Dynasty stubs
........
r34219 | peres001 | 2008-08-31 07:18:25 +0200 (Sun, 31 Aug 2008) | 1 line
Uniformed the interface of Parallaction class (and its hierarchy) with regards of gui code, which is now independent of engine version.
........
r34220 | peres001 | 2008-08-31 08:14:45 +0200 (Sun, 31 Aug 2008) | 1 line
Moved save/load code into SaveLoad class.
........
r34221 | peres001 | 2008-08-31 10:27:40 +0200 (Sun, 31 Aug 2008) | 1 line
Removed extra semicolon detected by salty-horse pesky compiler.
........
r34222 | peres001 | 2008-08-31 11:30:16 +0200 (Sun, 31 Aug 2008) | 2 lines
Cleanup.
........
r34223 | peres001 | 2008-08-31 12:24:32 +0200 (Sun, 31 Aug 2008) | 1 line
More cleanup.
........
r34224 | peres001 | 2008-08-31 12:43:32 +0200 (Sun, 31 Aug 2008) | 1 line
Fixed leak with Input class, introduced in commit 34206.
........
r34225 | drmccoy | 2008-08-31 13:37:07 +0200 (Sun, 31 Aug 2008) | 2 lines
Shutting up a warning on systems where char is signed by default
........
r34227 | peres001 | 2008-08-31 15:58:17 +0200 (Sun, 31 Aug 2008) | 4 lines
* Added Archive, an interface for searching into file containers.
* Added FSDirectory, an Archive implementation that models a directory from the filesystem.
* Added SearchSet, an Archive implementation that allows searching multiple Archives.
See patch 2034983 on sf.net.
........
r34228 | fingolfin | 2008-08-31 17:30:07 +0200 (Sun, 31 Aug 2008) | 1 line
Fix warnings
........
r34234 | lordhoto | 2008-09-01 01:11:55 +0200 (Mon, 01 Sep 2008) | 2 lines
Added newly added archive.cpp to the build system, just in case someone wants to play with the code and wonders about errors while linking.
........
r34235 | thebluegr | 2008-09-01 12:07:48 +0200 (Mon, 01 Sep 2008) | 1 line
Updated all MSVC project files with the latest changes to the code (gob and parallaction engines and the file system)
........
r34236 | thebluegr | 2008-09-01 12:09:48 +0200 (Mon, 01 Sep 2008) | 1 line
Silence MSVC warning about potentially uninitialized variable
........
r34237 | fingolfin | 2008-09-01 12:54:03 +0200 (Mon, 01 Sep 2008) | 1 line
New Queue class, from RTL branch
........
r34239 | lordhoto | 2008-09-01 17:39:48 +0200 (Mon, 01 Sep 2008) | 2 lines
Fixed warnings.
........
r34240 | lordhoto | 2008-09-01 18:52:09 +0200 (Mon, 01 Sep 2008) | 3 lines
- Added tests for newly added Common::Queue
- Changed Common::Queue::front and Common::Queue::back to return references instead of values
........
r34241 | fingolfin | 2008-09-01 19:30:03 +0200 (Mon, 01 Sep 2008) | 1 line
First part of GSoC2008 RTL branch merge
........
r34242 | fingolfin | 2008-09-01 19:46:05 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: AGI
........
r34243 | fingolfin | 2008-09-01 19:46:53 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: AGOS
........
r34244 | fingolfin | 2008-09-01 19:47:36 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: CINE
........
r34245 | fingolfin | 2008-09-01 19:50:00 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: GOB
........
r34246 | fingolfin | 2008-09-01 19:52:50 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: KYRA
........
r34247 | fingolfin | 2008-09-01 19:55:52 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: QUEEN
........
r34248 | lordhoto | 2008-09-01 20:14:55 +0200 (Mon, 01 Sep 2008) | 2 lines
Cleanup.
........
r34249 | lordhoto | 2008-09-01 20:26:28 +0200 (Mon, 01 Sep 2008) | 2 lines
Formatting.
........
r34251 | fingolfin | 2008-09-01 22:18:17 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: LURE
........
r34252 | fingolfin | 2008-09-01 22:19:28 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SAGA
........
r34253 | fingolfin | 2008-09-01 22:20:20 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SCUMM
........
r34254 | fingolfin | 2008-09-01 22:20:57 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SKY
........
r34255 | fingolfin | 2008-09-01 22:21:30 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SWORD1
........
r34256 | fingolfin | 2008-09-01 22:21:53 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: SWORD2
........
r34257 | fingolfin | 2008-09-01 22:22:10 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: TINSEL
........
r34258 | fingolfin | 2008-09-01 22:22:29 +0200 (Mon, 01 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: TOUCHE
........
r34259 | athrxx | 2008-09-01 22:23:25 +0200 (Mon, 01 Sep 2008) | 1 line
- kyra: fm-towns/pc-98 audio: restructured driver, added rhythm channel data
........
r34260 | fingolfin | 2008-09-01 22:31:44 +0200 (Mon, 01 Sep 2008) | 1 line
Clarified some comments
........
r34261 | fingolfin | 2008-09-01 22:41:43 +0200 (Mon, 01 Sep 2008) | 1 line
Clarified clarification ;)
........
r34262 | fingolfin | 2008-09-01 23:06:32 +0200 (Mon, 01 Sep 2008) | 1 line
Document each MetaEngineFeature (instead of listing just 'examples'). Wording could be better, feel free to improve it
........
r34263 | fingolfin | 2008-09-01 23:13:11 +0200 (Mon, 01 Sep 2008) | 1 line
TINSEL: Enabled listSaves support
........
r34264 | fingolfin | 2008-09-01 23:30:38 +0200 (Mon, 01 Sep 2008) | 1 line
cleanup
........
r34265 | thebluegr | 2008-09-02 01:36:59 +0200 (Tue, 02 Sep 2008) | 1 line
Silence MSVC warning about empty switch statement
........
r34266 | thebluegr | 2008-09-02 01:37:24 +0200 (Tue, 02 Sep 2008) | 1 line
Silence MSVC warning about empty switch statement
........
r34267 | joostp | 2008-09-02 02:31:27 +0200 (Tue, 02 Sep 2008) | 2 lines
fix Virgin logo screen breakage that was introduced in the RTL merge
........
r34268 | peres001 | 2008-09-02 03:58:55 +0200 (Tue, 02 Sep 2008) | 1 line
Merging more of the GSoC 2008 RTL branch: PARALLACTION
........
r34269 | thebluegr | 2008-09-02 09:32:09 +0200 (Tue, 02 Sep 2008) | 1 line
Added new files to the MSVC projects (engines/dialogs.* and common/queue.h)
........
r34270 | thebluegr | 2008-09-02 09:59:52 +0200 (Tue, 02 Sep 2008) | 1 line
Changed the MSVC optimization settings for the release version of all current engines, according to the settings proposed in patch #1877032 - "better optimization settings for msvc9". SSE has NOT been enabled by default though, as it's not available under 64-bit platforms. Updated the MSVC 8 -> MSVC 7/7.1 batch file accordingly
........
r34271 | thebluegr | 2008-09-02 10:02:40 +0200 (Tue, 02 Sep 2008) | 1 line
Added the missing tinsel engine project files for MSVC 7/7.1
........
r34272 | fingolfin | 2008-09-02 13:32:38 +0200 (Tue, 02 Sep 2008) | 1 line
Added two new global funcs which ease proper handling of 'path' strings: Common::lastPathComponent() and Common::normalizePath()
........
r34273 | fingolfin | 2008-09-02 13:34:12 +0200 (Tue, 02 Sep 2008) | 1 line
Revised HashMap implementation
........
r34274 | thebluegr | 2008-09-02 13:42:15 +0200 (Tue, 02 Sep 2008) | 2 lines
Enabled the new optimizations for older versions of MSVC as well
Also, included the tinsel engine library for the release version as well (fixes compilation of the release version)
........
r34275 | lordhoto | 2008-09-02 15:05:43 +0200 (Tue, 02 Sep 2008) | 2 lines
Added missing include.
........
r34276 | lordhoto | 2008-09-02 15:11:54 +0200 (Tue, 02 Sep 2008) | 2 lines
Handle OSystem::lockScreen fail in default OSystem::clearScreen implementation.
........
r34277 | lordhoto | 2008-09-02 15:13:02 +0200 (Tue, 02 Sep 2008) | 2 lines
Updated NULL backend for FS changes.
........
r34278 | lordhoto | 2008-09-02 15:16:51 +0200 (Tue, 02 Sep 2008) | 2 lines
Fixed copy&paste error when checking y and h of a widget on layout change.
........
r34279 | lordhoto | 2008-09-02 15:17:40 +0200 (Tue, 02 Sep 2008) | 2 lines
Fake 320x200 resolution instead of 200x320.
........
r34281 | lordhoto | 2008-09-02 15:27:26 +0200 (Tue, 02 Sep 2008) | 2 lines
Applied my patch from -devel, which reenables GMM opening via F6.
........
r34282 | lordhoto | 2008-09-02 16:36:47 +0200 (Tue, 02 Sep 2008) | 4 lines
Cleanup: Remove now unneeded KyraEngine_v1::quitGame.
Peres proposal for this commit log was: 'fixing .... as peres pointed out in his very interesting mail on -devel that everybody should read'.
........
r34283 | fingolfin | 2008-09-02 17:19:31 +0200 (Tue, 02 Sep 2008) | 1 line
Modified POSIX FSNode implementation to use Common::normalizePath & Common::lastPathComponent; added a TODO regarding relative paths
........
r34284 | fingolfin | 2008-09-02 18:35:16 +0200 (Tue, 02 Sep 2008) | 1 line
Change FilesystemNode::getChild to new desired behavior: namely, that it should return valid nodes even for names for which no child exists (yet?) -- mail to scummvm-devel pending
........
r34286 | drmccoy | 2008-09-02 22:15:42 +0200 (Tue, 02 Sep 2008) | 2 lines
Urban Runner stubs
........
r34287 | drmccoy | 2008-09-02 23:29:06 +0200 (Tue, 02 Sep 2008) | 2 lines
Added French Bargon Attack, as supplied by kizkoool in bugreport #2089734
........
r34288 | athrxx | 2008-09-02 23:31:53 +0200 (Tue, 02 Sep 2008) | 1 line
some minor bug fixes
........
r34290 | Kirben | 2008-09-03 03:47:01 +0200 (Wed, 03 Sep 2008) | 1 line
Add Nintendo Wii versions of Freddi Fish 1 and Pajama Sam 1.
........
r34291 | Kirben | 2008-09-03 04:06:11 +0200 (Wed, 03 Sep 2008) | 1 line
Add another Dutch demo of Pajama Sam 1.
........
r34292 | thebluegr | 2008-09-03 09:32:59 +0200 (Wed, 03 Sep 2008) | 1 line
Updated gob MSVC project files for commit #34286
........
r34293 | fingolfin | 2008-09-03 10:57:39 +0200 (Wed, 03 Sep 2008) | 1 line
If launching scummvm with no game selected, clear the transient domain (and hence the effect of all command line args) before opening the launcher (may cause regressions)
........
r34294 | fingolfin | 2008-09-03 10:58:19 +0200 (Wed, 03 Sep 2008) | 1 line
In the launcher load dialog code, store the save_slot in the transient domain (fixing bug #2089740)
........
r34295 | thebluegr | 2008-09-03 11:03:21 +0200 (Wed, 03 Sep 2008) | 1 line
Cleanup
........
r34296 | thebluegr | 2008-09-03 11:55:29 +0200 (Wed, 03 Sep 2008) | 1 line
Silence MSVC warning about ambiguous usage of CLIP
........
r34297 | thebluegr | 2008-09-03 11:58:28 +0200 (Wed, 03 Sep 2008) | 1 line
Commented out currently broken code, adding a FIXME
........
r34298 | thebluegr | 2008-09-03 12:00:43 +0200 (Wed, 03 Sep 2008) | 1 line
Silence MSVC warning about uninitialized variables
........
r34299 | thebluegr | 2008-09-03 12:10:45 +0200 (Wed, 03 Sep 2008) | 1 line
Fix for MSVC warning about ambiguous usage of MIN
........
r34300 | fingolfin | 2008-09-03 12:11:36 +0200 (Wed, 03 Sep 2008) | 1 line
Added new StdioStream class, a thin wrapper around FILE
........
r34301 | fingolfin | 2008-09-03 12:40:46 +0200 (Wed, 03 Sep 2008) | 1 line
Added new AbstractFilesystemNode::openForReading & ::openForWriting method, based on StdioStream; changed FilesystemNode to use them
........
r34302 | fingolfin | 2008-09-03 13:22:51 +0200 (Wed, 03 Sep 2008) | 1 line
Moved FilesystemNode / FSList to namespace Common; also got rid of some 'typedef Common::String String;' name aliases
........
r34303 | fingolfin | 2008-09-03 13:49:02 +0200 (Wed, 03 Sep 2008) | 1 line
Moved StdioStream to its own files inside backends
........
r34304 | fingolfin | 2008-09-03 14:56:46 +0200 (Wed, 03 Sep 2008) | 1 line
Pushed AbstractFilesystemNode::openForReading() / openForWriting() impls out to backends
........
r34305 | Kirben | 2008-09-03 15:49:24 +0200 (Wed, 03 Sep 2008) | 1 line
Added more versions of HE games.
........
r34306 | thebluegr | 2008-09-03 16:06:54 +0200 (Wed, 03 Sep 2008) | 1 line
Updated MSVC project files for commit #34303
........
r34307 | fingolfin | 2008-09-03 16:55:19 +0200 (Wed, 03 Sep 2008) | 1 line
POSIX FSNode: got rid of Double-slashes in paths for childs of the root; simplified code
........
r34308 | fingolfin | 2008-09-03 17:22:19 +0200 (Wed, 03 Sep 2008) | 1 line
Some cleanup by peres
........
r34309 | fingolfin | 2008-09-03 17:58:40 +0200 (Wed, 03 Sep 2008) | 1 line
TODO: bdf_getline seems to duplicate code from SeekableReadStream::readLine(_new) -> fix that
........
r34310 | fingolfin | 2008-09-03 18:56:40 +0200 (Wed, 03 Sep 2008) | 1 line
Moved check for shouldRTL() from engines to scummvm_main
........
r34311 | fingolfin | 2008-09-03 19:06:24 +0200 (Wed, 03 Sep 2008) | 1 line
clarified comment
........
r34312 | fingolfin | 2008-09-03 19:07:13 +0200 (Wed, 03 Sep 2008) | 1 line
Changed Archive::openFile to return a SeekableReadStream* instead of a FilePtr
........
r34313 | fingolfin | 2008-09-03 19:39:18 +0200 (Wed, 03 Sep 2008) | 1 line
Modified Common::Str to use exponential growth for its storage; also changed the meaning of 'capacity' from 'max length of string' to 'size of storage' (i.e. added one)
........
r34314 | fingolfin | 2008-09-03 19:46:42 +0200 (Wed, 03 Sep 2008) | 1 line
Removed unused readLine code from the MT-32 emu
........
r34315 | fingolfin | 2008-09-03 19:53:25 +0200 (Wed, 03 Sep 2008) | 1 line
Renamed SeekableReadStream::readLine to SeekableReadStream::readLine_OLD; added a new alternate SeekableReadStream::readLine() instead
........
r34316 | fingolfin | 2008-09-03 20:07:31 +0200 (Wed, 03 Sep 2008) | 1 line
Fixed Stream::readLine implementation to match its doxygen comment
........
r34317 | fingolfin | 2008-09-03 20:38:01 +0200 (Wed, 03 Sep 2008) | 1 line
Fix nasty off-by-one errors
........
r34318 | fingolfin | 2008-09-03 20:40:49 +0200 (Wed, 03 Sep 2008) | 1 line
Changed some code to use the new Stream::readLine() method
........
r34319 | lordhoto | 2008-09-03 21:07:38 +0200 (Wed, 03 Sep 2008) | 2 lines
Minor formatting cleanup.
........
r34320 | mthreepwood | 2008-09-03 23:37:19 +0200 (Wed, 03 Sep 2008) | 1 line
correct a typo (thanks to salty-horse)
........
r34323 | Kirben | 2008-09-04 10:11:35 +0200 (Thu, 04 Sep 2008) | 1 line
Correct HE version for Wii version of Freddi Fish 1.
........
r34324 | joostp | 2008-09-04 10:16:39 +0200 (Thu, 04 Sep 2008) | 2 lines
remove deprecated SCUMMVM_SAVEPATH define -- pass default savepath to DefaultSaveFileManager ctor
........
r34326 | joostp | 2008-09-04 10:34:02 +0200 (Thu, 04 Sep 2008) | 2 lines
move save directory detection/creation from main() to OSystem_PSP::initBackend()
........
r34328 | Kirben | 2008-09-04 16:12:27 +0200 (Thu, 04 Sep 2008) | 1 line
Add missing case in o100_resourceRoutines.
........
r34329 | drmccoy | 2008-09-04 19:39:22 +0200 (Thu, 04 Sep 2008) | 2 lines
Ooops, adding Lost in Time and Woodruff
........
r34332 | drmccoy | 2008-09-04 21:20:51 +0200 (Thu, 04 Sep 2008) | 2 lines
Added another version of Lost in Time CD, as supplied by SiRoCs in bug report #2093672
........
r34334 | fingolfin | 2008-09-04 22:03:08 +0200 (Thu, 04 Sep 2008) | 1 line
Changed FSDirectory::getSubDirectory to return a FSDirectory pointer instead of a SharedPtr
........
r34336 | eriktorbjorn | 2008-09-04 23:40:32 +0200 (Thu, 04 Sep 2008) | 2 lines
Use readLine() instead of readLine_OLD().
........
r34338 | anotherguest | 2008-09-05 13:06:27 +0200 (Fri, 05 Sep 2008) | 1 line
Updated buildscripts to support tinsel
........
r34339 | anotherguest | 2008-09-05 13:09:29 +0200 (Fri, 05 Sep 2008) | 1 line
Updated package revision no to 0.13. Updated default engine list
........
r34340 | anotherguest | 2008-09-05 13:31:51 +0200 (Fri, 05 Sep 2008) | 1 line
Updated Symbian OS file actions with ferror and fflush.
........
r34343 | peres001 | 2008-09-05 13:41:39 +0200 (Fri, 05 Sep 2008) | 1 line
Removed useless dependencies from common/file.h in common code. When complete removal was not possibile, dependency has been pushed to the cpp files from the headers.
........
r34344 | anotherguest | 2008-09-05 13:55:58 +0200 (Fri, 05 Sep 2008) | 1 line
Added two new files
........
r34345 | fingolfin | 2008-09-05 13:59:33 +0200 (Fri, 05 Sep 2008) | 1 line
Ported AMIGA specific file buffering 'hack' from class File to StdioStream
........
r34346 | anotherguest | 2008-09-05 14:02:15 +0200 (Fri, 05 Sep 2008) | 1 line
Updated filehandling for Symbian OS
........
r34347 | anotherguest | 2008-09-05 14:30:19 +0200 (Fri, 05 Sep 2008) | 1 line
Updated build script with new dialog.cpp
........
r34348 | anotherguest | 2008-09-05 14:53:43 +0200 (Fri, 05 Sep 2008) | 1 line
Still need to get that build working. Readjust buildscript
........
r34349 | thebluegr | 2008-09-05 15:02:03 +0200 (Fri, 05 Sep 2008) | 1 line
Hopefully fixed the chaos with the SAGA volume values. This also fixes the broken volume introduced with the introduction of the RTL code in the engine
........
r34350 | anotherguest | 2008-09-05 15:03:31 +0200 (Fri, 05 Sep 2008) | 1 line
Add missing dialogs.cpp
........
r34351 | anotherguest | 2008-09-05 15:13:51 +0200 (Fri, 05 Sep 2008) | 1 line
ADded Tinsel as supported engine strings
........
r34352 | Kirben | 2008-09-05 15:35:27 +0200 (Fri, 05 Sep 2008) | 1 line
Use exact case numbers, to avoid unneeded subtractions.
........
r34353 | anotherguest | 2008-09-05 16:11:23 +0200 (Fri, 05 Sep 2008) | 1 line
Enum needs to be minimum four chars to compile (32 bit number I guess)
........
r34356 | fingolfin | 2008-09-05 19:23:44 +0200 (Fri, 05 Sep 2008) | 1 line
whitespace 'fix'
........
r34357 | eriktorbjorn | 2008-09-05 19:34:38 +0200 (Fri, 05 Sep 2008) | 2 lines
Set the date for 0.12.0.
........
r34359 | peres001 | 2008-09-05 20:24:41 +0200 (Fri, 05 Sep 2008) | 2 lines
* Implemented a default matchPattern for Archive subclasses (courtesy of Fingolfin).
* Fixed bug in FSDirectory::matchPattern.
........
r34360 | peres001 | 2008-09-05 20:28:25 +0200 (Fri, 05 Sep 2008) | 1 line
Made FSDirectory use the default matchPattern implementation.
........
r34361 | anotherguest | 2008-09-05 20:45:04 +0200 (Fri, 05 Sep 2008) | 1 line
Remove usage of main_features.inl and the file
........
r34362 | anotherguest | 2008-09-05 20:49:13 +0200 (Fri, 05 Sep 2008) | 1 line
Change location of create fs factory for Symbian!
........
r34363 | anotherguest | 2008-09-05 21:03:30 +0200 (Fri, 05 Sep 2008) | 1 line
Add symbian implementations to create read/write configfile handles
........
r34364 | fingolfin | 2008-09-05 22:07:34 +0200 (Fri, 05 Sep 2008) | 1 line
Moved matchString from util.* to str.*; added new String::matchString method; fixed matchString doxygen comment (it confused pattern & string); added unit tests for matchString
........
r34365 | fingolfin | 2008-09-05 22:08:29 +0200 (Fri, 05 Sep 2008) | 1 line
Make use of String::matchString
........
r34366 | fingolfin | 2008-09-05 22:26:36 +0200 (Fri, 05 Sep 2008) | 1 line
Fix class FSDirectory (matchPattern would call getAllNames would call matchPattern would call ...); some cleanup
........
r34367 | fingolfin | 2008-09-05 22:29:03 +0200 (Fri, 05 Sep 2008) | 1 line
Optimized matchString for the common case where there is a trailing * (if that is the case, abort immediately instead of scanning the rest of the string)
........
r34368 | fingolfin | 2008-09-05 22:42:41 +0200 (Fri, 05 Sep 2008) | 1 line
Some tweaks to help (?) OS/2
........
r34369 | wjpalenstijn | 2008-09-05 22:53:30 +0200 (Fri, 05 Sep 2008) | 1 line
additional Common::String tests
........
r34370 | fingolfin | 2008-09-06 00:12:46 +0200 (Sat, 06 Sep 2008) | 1 line
Added simple ZipArchive class, and changed some GUI code to use it, instead of the ugly C API to the unzip code
........
r34371 | fingolfin | 2008-09-06 00:14:43 +0200 (Sat, 06 Sep 2008) | 1 line
Updated some copyright strings to 2001-2008
........
r34373 | fingolfin | 2008-09-06 00:16:29 +0200 (Sat, 06 Sep 2008) | 1 line
Added Chris to credits
........
r34375 | Kirben | 2008-09-06 03:02:45 +0200 (Sat, 06 Sep 2008) | 1 line
Add debugInput opcode for HE 100 games.
........
r34378 | Kirben | 2008-09-06 09:03:38 +0200 (Sat, 06 Sep 2008) | 1 line
Add Wii version of SPY Fox 1.
........
r34381 | thebluegr | 2008-09-06 10:37:03 +0200 (Sat, 06 Sep 2008) | 1 line
Added missing common/archive.*
........
r34382 | anotherguest | 2008-09-06 12:30:05 +0200 (Sat, 06 Sep 2008) | 2 lines
Portdefs cleanup, use snprintf from SDL and not sprintf (Which can cause memory overwrites).
Use bsearch implementation from WINCE port.
........
r34384 | fingolfin | 2008-09-06 18:46:28 +0200 (Sat, 06 Sep 2008) | 1 line
Added some unit tests for Stream::readLine_NEW, and clarified that readLine_NEW is essentially fgets in disguise
........
r34385 | fingolfin | 2008-09-06 19:00:50 +0200 (Sat, 06 Sep 2008) | 1 line
Unlike ferror, our Stream::ioFailed() is also supposed to return true when the end of stream has been reached
........
r34389 | fingolfin | 2008-09-06 22:34:21 +0200 (Sat, 06 Sep 2008) | 1 line
ScummFile: Don't use the File::_ioFailed flag, rather track the io status separately; also, changed eof() -> eos()
........
r34390 | fingolfin | 2008-09-06 22:36:47 +0200 (Sat, 06 Sep 2008) | 1 line
MT32 emu: eof -> eos
........
r34391 | fingolfin | 2008-09-06 22:49:48 +0200 (Sat, 06 Sep 2008) | 1 line
Switched class File & DumpFile to use StdioStream internally
........
r34393 | fingolfin | 2008-09-06 23:04:42 +0200 (Sat, 06 Sep 2008) | 1 line
Removed last traces of fopen / FILE from common/file.cpp
........
r34394 | fingolfin | 2008-09-06 23:09:34 +0200 (Sat, 06 Sep 2008) | 1 line
Clarified / fixed some Common::Archive doxygen comments
........
r34396 | fingolfin | 2008-09-06 23:23:08 +0200 (Sat, 06 Sep 2008) | 1 line
Got rid of File::eof()
........
r34397 | lordhoto | 2008-09-07 00:09:34 +0200 (Sun, 07 Sep 2008) | 1 line
Added hasArchive to SearchSet.
........
r34399 | anotherguest | 2008-09-07 12:57:28 +0200 (Sun, 07 Sep 2008) | 1 line
Remove symbian defines from stdiostream.cpp
........
r34400 | anotherguest | 2008-09-07 14:37:14 +0200 (Sun, 07 Sep 2008) | 1 line
StdioStream implemented with Symbian file handling.
........
r34401 | anotherguest | 2008-09-07 14:38:35 +0200 (Sun, 07 Sep 2008) | 1 line
Updated to include SymbianStream instead of StdioStream
........
r34402 | anotherguest | 2008-09-07 14:39:56 +0200 (Sun, 07 Sep 2008) | 1 line
Need to have own implementation of snprintf and vsnprintf.
........
r34403 | anotherguest | 2008-09-07 14:54:26 +0200 (Sun, 07 Sep 2008) | 1 line
Remove SYMBIAN special handing from default handler.
........
r34404 | drmccoy | 2008-09-07 15:16:58 +0200 (Sun, 07 Sep 2008) | 2 lines
Added another demo version of Gobliiins (bug #2098412)
........
r34405 | anotherguest | 2008-09-07 15:17:21 +0200 (Sun, 07 Sep 2008) | 1 line
H file cleanup, remove old vibra support
........
r34407 | anotherguest | 2008-09-07 15:40:30 +0200 (Sun, 07 Sep 2008) | 3 lines
Updated readme about usage of snprintf source
Added vsnprintf implementation.
Cleanout SymbianOS.cpp from old file functions.
........
r34408 | fingolfin | 2008-09-07 17:16:45 +0200 (Sun, 07 Sep 2008) | 1 line
Temporary workaround for bug #2098279: ALL: Game path with no trailing backslash fails
........
r34409 | drmccoy | 2008-09-07 17:21:52 +0200 (Sun, 07 Sep 2008) | 2 lines
Clipping setMousePos() parameters to sane values
........
r34411 | drmccoy | 2008-09-07 17:29:47 +0200 (Sun, 07 Sep 2008) | 2 lines
Actually, /now/ the values are sane ^^; (also fixes Ween mouse position bug #2046244)
........
r34413 | drmccoy | 2008-09-07 17:39:06 +0200 (Sun, 07 Sep 2008) | 2 lines
Added a spanish floppy version of Gob3, as supplied by SiRoCs in bug report #2098621
........
r34415 | drmccoy | 2008-09-07 18:27:04 +0200 (Sun, 07 Sep 2008) | 2 lines
Added polish version of Woodruff, as supplied by goodoldgeorg in bug report #2098838
........
r34417 | anotherguest | 2008-09-07 18:43:03 +0200 (Sun, 07 Sep 2008) | 2 lines
Set default save path via save manager.
Fix bug in symbian-fs GetChild function.
........
r34418 | anotherguest | 2008-09-07 20:28:58 +0200 (Sun, 07 Sep 2008) | 1 line
Updated with two new variations, scumm and brokensword
........
r34419 | anotherguest | 2008-09-07 20:30:07 +0200 (Sun, 07 Sep 2008) | 1 line
Slightly updated built script. Faster?
........
r34420 | sev | 2008-09-07 20:36:40 +0200 (Sun, 07 Sep 2008) | 2 lines
Generate drascula.dat by the latest create_drascula
........
r34423 | anotherguest | 2008-09-07 21:19:45 +0200 (Sun, 07 Sep 2008) | 2 lines
Symbian already store all paths with a trailing "\".
Quick fix waiting for proper solution
........
r34424 | fingolfin | 2008-09-07 23:30:55 +0200 (Sun, 07 Sep 2008) | 1 line
Added new OSystem method addSysArchivesToSearchSet() [better name pending, suggestions welcome]
........
r34425 | fingolfin | 2008-09-07 23:38:53 +0200 (Sun, 07 Sep 2008) | 1 line
Comment out some #defines in skydefs.h as they conflict with other headers (esp. T2 conflicts with some template defs)
........
r34426 | fingolfin | 2008-09-07 23:43:36 +0200 (Sun, 07 Sep 2008) | 1 line
added two FIXMEs to M4 -- somehow, adding two subdirs of CWD named 'goodstuf' and 'resource' to the list of default dirs doesn't sound very sensible to me ;)
........
r34428 | lordhoto | 2008-09-07 23:46:37 +0200 (Sun, 07 Sep 2008) | 2 lines
Moved Kyra resource code to a SearchSet/Archive based implementation, this removes dependencies on Common::File.
........
r34429 | fingolfin | 2008-09-07 23:47:01 +0200 (Sun, 07 Sep 2008) | 1 line
Allow invoking FilesystemNode::getChild on non-dir nodes, by returning an invalid node in that case
........
r34430 | fingolfin | 2008-09-07 23:47:46 +0200 (Sun, 07 Sep 2008) | 1 line
Made File::addDefaultDirectory(Recursive) ignore FSNodes which are not dirs / are invalid, instead of erroring out
........
r34431 | fingolfin | 2008-09-07 23:51:59 +0200 (Sun, 07 Sep 2008) | 1 line
oops
........
r34432 | fingolfin | 2008-09-07 23:59:25 +0200 (Sun, 07 Sep 2008) | 1 line
Add a priority param to OSystem::addSysArchivesToSearchSet (still in search for a better name ;)
........
r34433 | fingolfin | 2008-09-08 00:00:04 +0200 (Mon, 08 Sep 2008) | 1 line
Fix warning about missing virtual destructor
........
r34434 | fingolfin | 2008-09-08 00:10:58 +0200 (Mon, 08 Sep 2008) | 1 line
Replaced Engine::_gameDataPath (a String) by Engine::_gameDataDir (an FSNode); adapted code to that (by using getChild() to get subdirs, not string concatenation
........
r34435 | lordhoto | 2008-09-08 00:30:34 +0200 (Mon, 08 Sep 2008) | 1 line
Got rid of all Common::File usages in Kyra.
........
r34436 | lordhoto | 2008-09-08 00:35:13 +0200 (Mon, 08 Sep 2008) | 2 lines
- Fixed regression in Resource::unloadPakFile
- Changed priority value for OSystem::addSysArchivesToSearchSet call
........
r34437 | fingolfin | 2008-09-08 00:37:27 +0200 (Mon, 08 Sep 2008) | 1 line
Changed md5_file(FSNode) to use FSNode::openForReading
........
r34438 | lordhoto | 2008-09-08 00:41:57 +0200 (Mon, 08 Sep 2008) | 1 line
Changed priorities for search paths. (Just in case system specific data paths contain an outdated kyra.dat version)
........
r34440 | thebluegr | 2008-09-08 10:07:06 +0200 (Mon, 08 Sep 2008) | 1 line
Cleanup
........
r34441 | thebluegr | 2008-09-08 10:09:22 +0200 (Mon, 08 Sep 2008) | 1 line
Added kyra/resource_intern.* to the kyra MSVC project files
........
r34442 | thebluegr | 2008-09-08 10:26:54 +0200 (Mon, 08 Sep 2008) | 1 line
Free the current voice lookup table a bit earlier in loadGlobalResources()
........
r34443 | thebluegr | 2008-09-08 12:36:53 +0200 (Mon, 08 Sep 2008) | 1 line
Reduced calls to File::exists()
........
r34444 | fingolfin | 2008-09-08 13:11:32 +0200 (Mon, 08 Sep 2008) | 1 line
Switched File::open, File::addDefaultDirectory to use a SearchSet internally. Code is a lot shorter & simpler now, far less failing fopen calls (good for NDS and other ports); drawback: regressions :). Good bug hunting to everybody
........
r34445 | thebluegr | 2008-09-08 13:45:15 +0200 (Mon, 08 Sep 2008) | 1 line
decompiler.cpp is not used anywhere by default. Remove it to prevent a warning under MSVC that the object file is empty (since DUMP_SCRIPT is not defined by default, the whole code in this file is not used)
........
r34446 | thebluegr | 2008-09-08 13:57:49 +0200 (Mon, 08 Sep 2008) | 1 line
Changed WarnAsError to be true across all engines, in both debug and release builds
........
r34447 | thebluegr | 2008-09-08 14:38:55 +0200 (Mon, 08 Sep 2008) | 1 line
Removed some unneeded conversions from the MSVC8->MSVC7/7.1 conversion tool
........
r34448 | thebluegr | 2008-09-08 15:00:43 +0200 (Mon, 08 Sep 2008) | 5 lines
Some more unification of options:
- AdditionalIncludeDirectories is set to "../../;../../engines"
- InlineFunctionExpansion is set to "0" for debug and "2" for release builds
- DisableLanguageExtensions is set to "false" (disabling language extensions leads to some very weird errors)
- Detect64BitPortabilityProblems is set to "false", as setting it to "true" throws loads of warnings too (mainly related to strlen, when trying to store its result in an integer)
........
r34449 | thebluegr | 2008-09-08 16:00:26 +0200 (Mon, 08 Sep 2008) | 1 line
Don't use fileName both as a structure and as a function parameter
........
r34450 | peres001 | 2008-09-08 16:38:07 +0200 (Mon, 08 Sep 2008) | 1 line
Made searching the game path recursive (with the default depth of 4 levels). This is a temporary fix to make some games work, until we decide what to do with the file/directory searching.
........
r34451 | lordhoto | 2008-09-08 20:48:39 +0200 (Mon, 08 Sep 2008) | 2 lines
Fixed LoL file loading regression.
........
r34452 | lordhoto | 2008-09-08 20:55:29 +0200 (Mon, 08 Sep 2008) | 2 lines
Made some filenames uppercase for consistency.
........
r34453 | anotherguest | 2008-09-08 23:54:04 +0200 (Mon, 08 Sep 2008) | 2 lines
Updated/Fixed Symbian Filesystem handling.
Does not store ending backslash on path, and will list any sub folder properly, by adding '\' when needed.
........
r34454 | athrxx | 2008-09-08 23:57:38 +0200 (Mon, 08 Sep 2008) | 1 line
HOF: msvc8 compile fix (ARRAYSIZE used with run-time allocated array)
........
r34456 | peres001 | 2008-09-09 01:24:20 +0200 (Tue, 09 Sep 2008) | 1 line
Documented commit 34450 (game path searched recursively).
........
r34457 | thebluegr | 2008-09-09 08:47:41 +0200 (Tue, 09 Sep 2008) | 1 line
Fix for bug #2101083 - "ANY - MSVC71 compilation fails due to warnings-as-errors"
........
r34458 | thebluegr | 2008-09-09 09:05:47 +0200 (Tue, 09 Sep 2008) | 1 line
Committed patch #2100962 - "Saga engine reduced memory usage"
........
r34460 | thebluegr | 2008-09-09 13:20:34 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup. Simplified converse()
........
r34462 | thebluegr | 2008-09-09 14:57:12 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup
........
r34463 | thebluegr | 2008-09-09 14:57:57 +0200 (Tue, 09 Sep 2008) | 1 line
Cleanup of exitRoom()
........
r34464 | thebluegr | 2008-09-09 17:59:06 +0200 (Tue, 09 Sep 2008) | 4 lines
- Cleanup and simplification
- Moved several simple animations out of animation.cpp
- Moved some animations with talk sequences inside drascula.dat
- A new version of drascula.dat is needed (will be uploaded shortly)
........
r34465 | thebluegr | 2008-09-09 17:59:52 +0200 (Tue, 09 Sep 2008) | 1 line
New version of the create_drascula tool
........
r34466 | thebluegr | 2008-09-09 18:00:28 +0200 (Tue, 09 Sep 2008) | 1 line
New version of drascula.dat
........
r34467 | lordhoto | 2008-09-09 20:09:46 +0200 (Tue, 09 Sep 2008) | 2 lines
Changed static resource code to use Streams instead of operating on buffers.
........
r34468 | thebluegr | 2008-09-10 08:57:32 +0200 (Wed, 10 Sep 2008) | 1 line
Fix in the Igor engine for bug #2101083 - "ANY - MSVC71 compilation fails due to warnings-as-errors"
........
r34469 | thebluegr | 2008-09-10 08:59:55 +0200 (Wed, 10 Sep 2008) | 1 line
Fix for bug #2102828 - "AGOS - compilation error, uninitialized variable"
........
r34472 | thebluegr | 2008-09-10 10:25:12 +0200 (Wed, 10 Sep 2008) | 1 line
Reduced game memory usage by about 400KB by only loading the current language strings, not all strings
........
r34474 | fingolfin | 2008-09-10 11:20:38 +0200 (Wed, 10 Sep 2008) | 1 line
Small fix to help with compile problems on Amiga
........
r34479 | thebluegr | 2008-09-10 14:03:42 +0200 (Wed, 10 Sep 2008) | 1 line
Merged all the methods to assign and set default palettes
........
r34480 | thebluegr | 2008-09-10 15:06:40 +0200 (Wed, 10 Sep 2008) | 1 line
Removed the unused variable changeColor
........
r34481 | lordhoto | 2008-09-10 20:01:02 +0200 (Wed, 10 Sep 2008) | 2 lines
Cleanup.
........
r34483 | vinterstum | 2008-09-10 21:46:08 +0200 (Wed, 10 Sep 2008) | 1 line
Merged up iPhone backend changes from 0.12 to trunk
........
r34484 | lordhoto | 2008-09-10 22:47:58 +0200 (Wed, 10 Sep 2008) | 2 lines
Cleanup.
........
r34485 | fingolfin | 2008-09-11 11:25:13 +0200 (Thu, 11 Sep 2008) | 1 line
Simplify check for a slash in the string *g*
........
r34486 | fingolfin | 2008-09-11 11:26:27 +0200 (Thu, 11 Sep 2008) | 1 line
Added detection for 4-language floppy version of DW (see report on forum post 39703)
........
r34487 | fingolfin | 2008-09-11 11:28:14 +0200 (Thu, 11 Sep 2008) | 1 line
Remove obsolete note about fopen
........
r34488 | thebluegr | 2008-09-11 11:31:45 +0200 (Thu, 11 Sep 2008) | 5 lines
- The game's cursor is now handled via ScummVM's cursor manager, instead of the game itself (this means that there might be regressions where the cursor is visible when it shouldn't be)
- Removed the textSurface pointer, which was used in the Spanish version. Non-Spanish versions of the game hold the font data in the tableSurface buffer (which contains picture 96). The font data for Spanish versions is in picture 974. Now both versions load their font data from the tableSurface buffer
- hay_que_load -> loadedDifferentChapter
- Merged withoutVerb() and selectVerb()
This is a big change, it might lead to regressions!
........
r34489 | thebluegr | 2008-09-11 11:33:15 +0200 (Thu, 11 Sep 2008) | 1 line
Fixed the hotspot for the crosshair cursor
........
r34490 | thebluegr | 2008-09-11 11:37:42 +0200 (Thu, 11 Sep 2008) | 1 line
Cleanup
........
r34491 | thebluegr | 2008-09-11 14:04:45 +0200 (Thu, 11 Sep 2008) | 1 line
Code optimizations from Fingolfin
........
r34492 | peres001 | 2008-09-11 15:24:01 +0200 (Thu, 11 Sep 2008) | 1 line
Added first version of the SearchManager, as it is presented in patch tracker item 2093502.
........
r34493 | thebluegr | 2008-09-11 16:49:04 +0200 (Thu, 11 Sep 2008) | 5 lines
- Merged openDoor() and closeDoor()
- Cleaned up updateDoor()
- Bugfixes to exitRoom() and gotoObject()
- Moved cursor-related functions to interface.cpp
- alapuertakeva -> roomExits
........
r34494 | thebluegr | 2008-09-11 17:35:56 +0200 (Thu, 11 Sep 2008) | 1 line
Cleanup
........
r34495 | lordhoto | 2008-09-11 21:47:45 +0200 (Thu, 11 Sep 2008) | 2 lines
Committed my patch #2105593 "Launcher/MetaEngine: Finnished removeSaveState".
........
r34496 | lordhoto | 2008-09-11 22:20:02 +0200 (Thu, 11 Sep 2008) | 4 lines
- Moved delete confirm dialog to SaveLoadChooser, allows the user to check which save he was trying to delete
- Cleaned up the SaveLoadChooser / Launcher code
-> Should reduce memory usage a little bit
........
r34497 | lordhoto | 2008-09-11 22:34:46 +0200 (Thu, 11 Sep 2008) | 2 lines
Little more cleanup.
........
r34498 | anotherguest | 2008-09-11 23:32:40 +0200 (Thu, 11 Sep 2008) | 3 lines
Added SymbianStream.h for SymbianStdioStream definition
Renamed Symbian stream implementation to
SymbianStdioStream instead of StdioStream.
........
r34501 | Kirben | 2008-09-12 03:28:28 +0200 (Fri, 12 Sep 2008) | 1 line
Fix compiling under mingw, when using latest mingw-runtime (3.15).
........
r34502 | lordhoto | 2008-09-12 14:25:56 +0200 (Fri, 12 Sep 2008) | 2 lines
Fixed slot 0 savefile name in Kyra3. (Now using 'New game' instead of 'German')
........
r34503 | thebluegr | 2008-09-12 14:54:16 +0200 (Fri, 12 Sep 2008) | 5 lines
- Moved more animation data inside drascula.dat
- Merged copyRect and copyRectClip
- Added enums for all the possible character directions and removed duplicate directions
- Extended the talk sequence commands a bit
- Removed unnecessary buffer faceBuffer and the unneeded casts between byte * and char * that were used
........
r34504 | thebluegr | 2008-09-12 14:54:47 +0200 (Fri, 12 Sep 2008) | 1 line
New version of the create_drascula tool
........
r34505 | thebluegr | 2008-09-12 14:55:25 +0200 (Fri, 12 Sep 2008) | 1 line
New version of drascula.dat
........
r34508 | Kirben | 2008-09-13 02:33:40 +0200 (Sat, 13 Sep 2008) | 1 line
Add missing targets.
........
r34511 | anotherguest | 2008-09-13 10:34:38 +0200 (Sat, 13 Sep 2008) | 1 line
Fixed drascula dat path and version nr.
........
r34512 | anotherguest | 2008-09-13 10:35:38 +0200 (Sat, 13 Sep 2008) | 1 line
Fixed rev nr. 130 will give wrong ver. in installation.
........
r34513 | eriktorbjorn | 2008-09-13 17:23:23 +0200 (Sat, 13 Sep 2008) | 2 lines
Indentation.
........
r34514 | fingolfin | 2008-09-13 18:51:46 +0200 (Sat, 13 Sep 2008) | 1 line
Big patch changing the signature of various Stream methods (some ports may need to be slightly tweaked to fix overloading errors/warnings)
........
r34515 | sev | 2008-09-13 19:41:42 +0200 (Sat, 13 Sep 2008) | 2 lines
Portability fixes.
........
r34516 | fingolfin | 2008-09-13 22:04:19 +0200 (Sat, 13 Sep 2008) | 1 line
SCUMM: Merged class BaseChunk & Chunk; got rid of MemoryChunk
........
r34517 | fingolfin | 2008-09-13 22:22:52 +0200 (Sat, 13 Sep 2008) | 1 line
SCUMM: Merged class Chunk & FileChunk
........
r34518 | fingolfin | 2008-09-14 00:41:30 +0200 (Sun, 14 Sep 2008) | 1 line
SCUMM: Got rid of class Chunk
........
r34520 | lordhoto | 2008-09-14 16:01:24 +0200 (Sun, 14 Sep 2008) | 2 lines
Rename save slots in KyraMetaEngine::removeSaveState, so it matches behavior in GUI_v2::deleteMenu at least a little bit more.
........
r34521 | lordhoto | 2008-09-14 16:08:14 +0200 (Sun, 14 Sep 2008) | 2 lines
Added a hack in KyraMetaEngine::listSaves to prevent slot 0 from being listed. Check comment for additional information.
........
r34522 | lordhoto | 2008-09-14 16:58:37 +0200 (Sun, 14 Sep 2008) | 2 lines
Only setup 'cdaudio' config default for FM-Towns/PC98.
........
r34523 | lordhoto | 2008-09-14 17:35:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Fixed regression introduced with r34522. (Now games without 'cdaudio' config value set should startup again).
........
r34524 | lordhoto | 2008-09-14 17:36:16 +0200 (Sun, 14 Sep 2008) | 2 lines
Implemented opcode 151: o1_resetMaskRegion
........
r34526 | thebluegr | 2008-09-14 18:21:31 +0200 (Sun, 14 Sep 2008) | 1 line
Fix for bug #2110375 - "DRASCULA: Mouse visible in screen saver", a regression from moving mouse handling to OSystem
........
r34527 | lordhoto | 2008-09-14 18:29:14 +0200 (Sun, 14 Sep 2008) | 2 lines
Fixed thumbnail creation / loading in kyra.
........
r34528 | lordhoto | 2008-09-14 18:48:20 +0200 (Sun, 14 Sep 2008) | 2 lines
Typo.
........
r34529 | thebluegr | 2008-09-14 20:00:06 +0200 (Sun, 14 Sep 2008) | 1 line
Updated MSVC project files for the SCUMM engine - removed smush/chunk.*
........
r34530 | lordhoto | 2008-09-14 20:19:22 +0200 (Sun, 14 Sep 2008) | 2 lines
Committed patch by [md5] from bug tracker item #2100790 "GUI:Clicking "Load" when no games are added triggers a crash".
........
r34531 | thebluegr | 2008-09-14 20:30:08 +0200 (Sun, 14 Sep 2008) | 1 line
Slight cleanup of centerText()
........
r34532 | lordhoto | 2008-09-14 20:59:43 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix for bug #2089275: "GUI: Returning to launcher may trigger an error".
........
r34533 | lordhoto | 2008-09-14 21:05:05 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix potentional bug in Screen::setResolution.
........
r34534 | lordhoto | 2008-09-14 21:16:08 +0200 (Sun, 14 Sep 2008) | 2 lines
Fix for bug #2090879 "GUI: Launcher 'Load' dialog should preserve save slot index".
........
r34535 | lordhoto | 2008-09-14 21:48:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Added autosave support in Kyra.
........
r34536 | lordhoto | 2008-09-14 22:01:01 +0200 (Sun, 14 Sep 2008) | 2 lines
Changed message when trying to open the load dialog for games not supporting direct loading.
........
r34537 | lordhoto | 2008-09-14 22:42:50 +0200 (Sun, 14 Sep 2008) | 2 lines
Added ScummVM logo to GMM.
........
r34538 | lordhoto | 2008-09-14 22:52:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Minor improvement for GMM layout.
........
r34539 | lordhoto | 2008-09-14 23:00:24 +0200 (Sun, 14 Sep 2008) | 3 lines
- Added thumbnail support to launcher load dialog.
- Adopted KYRA to support displaying thumbnails in load dialog (SCUMM engine has yet to follow)
........
r34540 | lordhoto | 2008-09-14 23:13:40 +0200 (Sun, 14 Sep 2008) | 2 lines
Added thumbnail support for launcher to SCUMM engine.
........
r34541 | fingolfin | 2008-09-14 23:26:59 +0200 (Sun, 14 Sep 2008) | 1 line
Fixed a typo & clarified a comment
........
r34542 | fingolfin | 2008-09-14 23:32:45 +0200 (Sun, 14 Sep 2008) | 1 line
Compilation fix for NDS
........
r34543 | lordhoto | 2008-09-14 23:34:49 +0200 (Sun, 14 Sep 2008) | 2 lines
Little cleanup.
........
r34544 | fingolfin | 2008-09-14 23:39:45 +0200 (Sun, 14 Sep 2008) | 1 line
Changed VPATH to vpath, to allow building NDS port in parallel to another port (for the records, this patch went to Neil in January, and he didn't complain)
........
r34545 | lordhoto | 2008-09-14 23:41:27 +0200 (Sun, 14 Sep 2008) | 2 lines
Cleanup.
........
r34546 | fingolfin | 2008-09-15 00:12:59 +0200 (Mon, 15 Sep 2008) | 1 line
Another NDS compilation fix, plus a warning fix
........
r34547 | fingolfin | 2008-09-15 00:15:13 +0200 (Mon, 15 Sep 2008) | 1 line
NDS: Replaced -I- by modern -iquote
........
r34548 | fingolfin | 2008-09-15 00:24:35 +0200 (Mon, 15 Sep 2008) | 1 line
DS: Removed legacy GCC 2.x build code (NDS/DevKitPro uses GCC 3 or newer anyway); thinned down INCLUDES some more; added a FIXME to the elf->bin rule
........
r34549 | wjpalenstijn | 2008-09-15 00:28:53 +0200 (Mon, 15 Sep 2008) | 6 lines
Big patch changing semantics of ReadStream::eos():
eos() now only returns true _after_ trying to read past the end of the stream.
This has a large potential for regressions. Please test!
........
r34550 | fingolfin | 2008-09-15 00:44:49 +0200 (Mon, 15 Sep 2008) | 1 line
DS: Some more compile fixes (prope solution would of course be to overload ::openForReading & ::openForWriting)
........
r34551 | lordhoto | 2008-09-15 01:14:38 +0200 (Mon, 15 Sep 2008) | 2 lines
Fixed regression introduced with latest stream changes (it seems compressed savefiles ioFailed never returned true when only eos was set).
........
r34552 | wjpalenstijn | 2008-09-15 08:51:15 +0200 (Mon, 15 Sep 2008) | 1 line
fix listSaveGames
........
r34553 | wjpalenstijn | 2008-09-15 08:52:00 +0200 (Mon, 15 Sep 2008) | 1 line
replace ioFailed by err
........
r34554 | thebluegr | 2008-09-15 11:17:18 +0200 (Mon, 15 Sep 2008) | 1 line
Proper check for eos(), after the latest changes to OSystem
........
r34555 | fingolfin | 2008-09-15 12:05:36 +0200 (Mon, 15 Sep 2008) | 1 line
Fix SubReadStream by initing _eos to false in the constructor (spotted thanks to our unit tests)
........
r34556 | fingolfin | 2008-09-15 14:37:18 +0200 (Mon, 15 Sep 2008) | 1 line
Corrected and shortened some file opening related warnings
........
r34557 | Kirben | 2008-09-15 14:37:24 +0200 (Mon, 15 Sep 2008) | 1 line
Replace ioFailed by err.
........
r34558 | thebluegr | 2008-09-15 15:37:28 +0200 (Mon, 15 Sep 2008) | 2 lines
Rewrote the very confusing centerText() function into something that makes more sense, and matches the way that the original printed text on screen (in most cases)
Fixes bugs #2102657 - "DRASCULA: Crash when talking to the piano player" and #2111820 - "DRASCULA: Dialog texts too long"
........
r34559 | thebluegr | 2008-09-15 15:45:10 +0200 (Mon, 15 Sep 2008) | 1 line
Fixed the phrase told by the protagonist when he talks to the blind man the second time
........
r34560 | thebluegr | 2008-09-15 16:17:51 +0200 (Mon, 15 Sep 2008) | 1 line
Remove a workaround in textFitsCentered(). The blind man's dialog is a bit better placed now
........
r34561 | thebluegr | 2008-09-15 16:35:11 +0200 (Mon, 15 Sep 2008) | 1 line
Show the blind man's dialog text at a bit better place
........
r34562 | wjpalenstijn | 2008-09-15 21:19:30 +0200 (Mon, 15 Sep 2008) | 1 line
fix eos() behaviour for CompressedInSaveFile
........
r34563 | wjpalenstijn | 2008-09-15 21:34:06 +0200 (Mon, 15 Sep 2008) | 1 line
also check for premature end-of-stream when loading
........
r34566 | fingolfin | 2008-09-15 23:55:50 +0200 (Mon, 15 Sep 2008) | 1 line
Turned compressed savefile wrapper into a generic stream wrapper
........
r34567 | fingolfin | 2008-09-16 00:37:45 +0200 (Tue, 16 Sep 2008) | 1 line
Fixed compiler warnings
........
r34568 | fingolfin | 2008-09-16 00:43:20 +0200 (Tue, 16 Sep 2008) | 1 line
DS: Backported 0.12 changes to trunk
........
r34569 | thebluegr | 2008-09-16 09:16:26 +0200 (Tue, 16 Sep 2008) | 2 lines
- Fixed centerText() to print text at the correct height
- Removed some duplicate code
........
r34571 | thebluegr | 2008-09-16 10:10:08 +0200 (Tue, 16 Sep 2008) | 1 line
Added a workaround to skip the silence in the beginning and end of file 3.als. Fixes bug #2111815 - "DRASCULA: Voice delayed"
........
r34572 | thebluegr | 2008-09-16 10:12:13 +0200 (Tue, 16 Sep 2008) | 1 line
Assign _lang to the appropriate enum values
........
r34573 | thebluegr | 2008-09-16 10:24:42 +0200 (Tue, 16 Sep 2008) | 1 line
Removed the confirmation speech when a game is saved - it's "99.als" instead of "s99.als", but the main problem is that it's not translated in the English version and it's in Spanish (plus it's creepy and annoying...)
........
r34574 | thebluegr | 2008-09-16 12:44:07 +0200 (Tue, 16 Sep 2008) | 1 line
Cleaned up and fixed the cutscene with Von Braun's story. Fixes bugs #2111804 - "DRASCULA: Cut scene bugs" and #2059648 - "DRASCULA: VonBraun's song"
........
r34575 | thebluegr | 2008-09-16 12:53:57 +0200 (Tue, 16 Sep 2008) | 1 line
Fixed some glitches in the last part of Von Braun's story
........
r34576 | fingolfin | 2008-09-16 13:42:21 +0200 (Tue, 16 Sep 2008) | 1 line
Modified uncompress in common/zlib.h to return a bool, so that we don't have to #include the real zlib.h; fixed PSP backend to not run uncompress inside an assert (which would cause it to not be invoked when turning off asserts)
........
r34577 | thebluegr | 2008-09-16 13:49:40 +0200 (Tue, 16 Sep 2008) | 3 lines
- Moved some includes away from drascula.h
- Moved grr() to talk.cpp
- Removed the unnecessary parameter length from isTalkFinished()
........
r34578 | fingolfin | 2008-09-16 13:50:10 +0200 (Tue, 16 Sep 2008) | 1 line
Merged common/gzip-stream.* and common/zlib.*
........
r34579 | lordhoto | 2008-09-16 13:54:37 +0200 (Tue, 16 Sep 2008) | 2 lines
Removed assert leftover.
........
r34580 | fingolfin | 2008-09-16 13:57:45 +0200 (Tue, 16 Sep 2008) | 1 line
Fix sign warnings in unit tests
........
r34581 | lordhoto | 2008-09-16 16:10:55 +0200 (Tue, 16 Sep 2008) | 6 lines
Added "querySaveMetaInfos" to MetaEngine.
-> Allows easy addition of save state specific infos like playtime, save date atc.
-> Removed MetaEngine::loadThumbnailFromSlot, superseded by meta infos
-> Changed SCUMM / KYRA to implement the newly added functionallity
-> Removed hack in KYRAs listSavefiles, which is now handled via meta infos
........
r34582 | lordhoto | 2008-09-16 16:22:51 +0200 (Tue, 16 Sep 2008) | 2 lines
Cleanup.
........
r34583 | lordhoto | 2008-09-16 16:56:02 +0200 (Tue, 16 Sep 2008) | 2 lines
Added support for SCUMM savestates date/time and playtime info in the launcher load dialog.
........
r34584 | lordhoto | 2008-09-16 16:59:52 +0200 (Tue, 16 Sep 2008) | 2 lines
Added whitespace in playtime textfield.
........
r34585 | fingolfin | 2008-09-16 22:12:25 +0200 (Tue, 16 Sep 2008) | 1 line
Removed tons of unused 'length' variables, to silence compiler warnings
........
r34586 | fingolfin | 2008-09-17 18:31:25 +0200 (Wed, 17 Sep 2008) | 1 line
adding Info.plist to svn:ignore
........
r34587 | fingolfin | 2008-09-17 18:38:01 +0200 (Wed, 17 Sep 2008) | 1 line
DS: Removing some dead code; merged (parts of) std_cwd into GBAMPSaveFileManager::listSavefiles
........
r34588 | fingolfin | 2008-09-17 18:50:19 +0200 (Wed, 17 Sep 2008) | 1 line
Adding *.dSYM (generated by gcc on OSX these days) to svn:ignore
........
r34589 | fingolfin | 2008-09-17 19:31:29 +0200 (Wed, 17 Sep 2008) | 1 line
Moved base/game.* to engines/game.*
........
r34590 | lordhoto | 2008-09-17 19:46:55 +0200 (Wed, 17 Sep 2008) | 2 lines
Fixed bug in SaveLoadChooser reflowLayout, which prevented widgets from being properly hidden.
........
r34592 | fingolfin | 2008-09-17 20:16:06 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2112604: Update for the man page
........
r34595 | fingolfin | 2008-09-17 20:26:44 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2043093 (again - new patch): OS/2 patches for posix-fs
........
r34596 | fingolfin | 2008-09-17 20:56:13 +0200 (Wed, 17 Sep 2008) | 1 line
Patch #2060517: SCUMM: engine sets incorrect talkspeed value
........
r34597 | fingolfin | 2008-09-17 20:56:54 +0200 (Wed, 17 Sep 2008) | 1 line
Added some noteworthy improvements due to Chris Page & GSoC 2008
........
r34598 | fingolfin | 2008-09-17 20:59:09 +0200 (Wed, 17 Sep 2008) | 1 line
Simplified & fixed SearchManager
........
r34599 | fingolfin | 2008-09-18 10:19:00 +0200 (Thu, 18 Sep 2008) | 1 line
Added 'native' implementations for FSDirectory::matchPattern & SearchSet::getAllNames (untested)
........
r34602 | thebluegr | 2008-09-19 12:25:40 +0200 (Fri, 19 Sep 2008) | 1 line
Updated MSVC project files with the latest changes (moved base/game.* to engines/game.*)
........
r34603 | thebluegr | 2008-09-19 15:58:09 +0200 (Fri, 19 Sep 2008) | 1 line
Changed tinsel's volume range (0-127) to match ScummVM's (0-255)
........
svn-id: r34606
Diffstat (limited to 'common')
39 files changed, 2368 insertions, 1254 deletions
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index 522b24163e..1b0db4755a 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -82,12 +82,12 @@ static void upgradeTargetIfNecessary(const Common::ADParams ¶ms) { if (params.obsoleteList == 0) return; - const char *gameid = ConfMan.get("gameid").c_str(); + String gameid = ConfMan.get("gameid"); for (const Common::ADObsoleteGameID *o = params.obsoleteList; o->from; ++o) { - if (!scumm_stricmp(gameid, o->from)) { + if (gameid.equalsIgnoreCase(o->from)) { gameid = o->to; - ConfMan.set("gameid", o->to); + ConfMan.set("gameid", gameid); if (o->platform != Common::kPlatformUnknown) ConfMan.set("platform", Common::getPlatformCode(o->platform)); diff --git a/common/advancedDetector.h b/common/advancedDetector.h index 40f5823d1b..b72b9fbfc4 100644 --- a/common/advancedDetector.h +++ b/common/advancedDetector.h @@ -28,8 +28,6 @@ #include "common/fs.h" #include "common/error.h" -#include "base/game.h" // For PlainGameDescriptor and GameList - #include "engines/metaengine.h" namespace Common { diff --git a/common/archive.cpp b/common/archive.cpp new file mode 100644 index 0000000000..7e17fdca32 --- /dev/null +++ b/common/archive.cpp @@ -0,0 +1,344 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/archive.h" +#include "common/fs.h" +#include "common/util.h" + +namespace Common { + + +int Archive::matchPattern(StringList &list, const String &pattern) { + // Get all "names" (TODO: "files" ?) + StringList allNames; + getAllNames(allNames); + + int matches = 0; + + // need to match lowercase key + String lowercasePattern = pattern; + lowercasePattern.toLowercase(); + + StringList::iterator it = allNames.begin(); + for ( ; it != allNames.end(); it++) { + if (it->matchString(lowercasePattern)) { + list.push_back(*it); + matches++; + } + } + + return matches; +} + + +FSDirectory::FSDirectory(const FilesystemNode &node, int depth) + : _node(node), _cached(false), _depth(depth) { +} + +FSDirectory::FSDirectory(const String &name, int depth) + : _node(name), _cached(false), _depth(depth) { +} + +FSDirectory::~FSDirectory() { +} + +FilesystemNode FSDirectory::getFSNode() const { + return _node; +} + +FilesystemNode FSDirectory::lookupCache(NodeCache &cache, const String &name) { + // make caching as lazy as possible + if (!name.empty()) { + if (!_cached) { + cacheDirectoryRecursive(_node, _depth, ""); + _cached = true; + } + + if (cache.contains(name)) + return cache[name]; + } + + return FilesystemNode(); +} + +bool FSDirectory::hasFile(const String &name) { + if (name.empty() || !_node.isDirectory()) { + return false; + } + + FilesystemNode node = lookupCache(_fileCache, name); + return node.exists(); +} + +SeekableReadStream *FSDirectory::openFile(const String &name) { + if (name.empty() || !_node.isDirectory()) { + return 0; + } + + FilesystemNode node = lookupCache(_fileCache, name); + + if (!node.exists()) { + warning("FSDirectory::openFile: FilesystemNode does not exist"); + return 0; + } else if (node.isDirectory()) { + warning("FSDirectory::openFile: FilesystemNode is a directory"); + return 0; + } + + SeekableReadStream *stream = node.openForReading(); + if (!stream) { + warning("FSDirectory::openFile: Can't create stream for file '%s'", name.c_str()); + } + + return stream; +} + +FSDirectory *FSDirectory::getSubDirectory(const String &name) { + if (name.empty() || !_node.isDirectory()) { + return 0; + } + + FilesystemNode node = lookupCache(_subDirCache, name); + return new FSDirectory(node); +} + +void FSDirectory::cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix) { + if (depth <= 0) { + return; + } + + FSList list; + node.getChildren(list, FilesystemNode::kListAll, false); + + FSList::iterator it = list.begin(); + for ( ; it != list.end(); it++) { + String name = prefix + (*it).getName(); + + // don't touch name as it might be used for warning messages + String lowercaseName = name; + lowercaseName.toLowercase(); + + // since the hashmap is case insensitive, we need to check for clashes when caching + if ((*it).isDirectory()) { + if (_subDirCache.contains(lowercaseName)) { + warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring sub-directory '%s'", name.c_str()); + } else { + cacheDirectoryRecursive(*it, depth - 1, lowercaseName + "/"); + _subDirCache[lowercaseName] = *it; + } + } else { + if (_fileCache.contains(lowercaseName)) { + warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'", name.c_str()); + } else { + _fileCache[lowercaseName] = *it; + } + } + } + +} + +int FSDirectory::matchPattern(StringList &list, const String &pattern) { + if (!_node.isDirectory()) + return 0; + + // Cache dir data + if (!_cached) { + cacheDirectoryRecursive(_node, _depth, ""); + _cached = true; + } + + // Small optimization: Ensure the StringList has to grow at most once + list.reserve(list.size() + _fileCache.size()); + + // Add all filenames from our cache + NodeCache::iterator it = _fileCache.begin(); + for ( ; it != _fileCache.end(); it++) { + if (it->_key.matchString(pattern)) + list.push_back(it->_key); + } + + return _fileCache.size(); +} + +int FSDirectory::getAllNames(StringList &list) { + if (!_node.isDirectory()) + return 0; + + // Cache dir data + if (!_cached) { + cacheDirectoryRecursive(_node, _depth, ""); + _cached = true; + } + + // Small optimization: Ensure the StringList has to grow at most once + list.reserve(list.size() + _fileCache.size()); + + // Add all filenames from our cache + NodeCache::iterator it = _fileCache.begin(); + for ( ; it != _fileCache.end(); it++) { + list.push_back((*it)._key); + } + + return _fileCache.size(); +} + + + +SearchSet::ArchiveList::iterator SearchSet::find(const String &name) const { + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._name == name) { + break; + } + } + return it; +} + +/* + Keep the nodes sorted according to descending priorities. + In case two or node nodes have the same priority, insertion + order prevails. +*/ +void SearchSet::insert(const Node &node) { + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._priority < node._priority) { + break; + } + } + _list.insert(it, node); +} + +void SearchSet::add(const String& name, ArchivePtr archive, uint priority) { + if (find(name) == _list.end()) { + Node node = { priority, name, archive }; + insert(node); + } else { + warning("SearchSet::add: archive '%s' already present", name.c_str()); + } + +} + +void SearchSet::remove(const String& name) { + ArchiveList::iterator it = find(name); + if (it != _list.end()) { + _list.erase(it); + } +} + +bool SearchSet::hasArchive(const String &name) const { + return (find(name) != _list.end()); +} + +void SearchSet::clear() { + _list.clear(); +} + +void SearchSet::setPriority(const String& name, uint priority) { + ArchiveList::iterator it = find(name); + if (it == _list.end()) { + warning("SearchSet::setPriority: archive '%s' is not present", name.c_str()); + return; + } + + if (priority == (*it)._priority) { + return; + } + + Node node(*it); + _list.erase(it); + node._priority = priority; + insert(node); +} + +bool SearchSet::hasFile(const String &name) { + if (name.empty()) { + return false; + } + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._arc->hasFile(name)) { + return true; + } + } + + return false; +} + +int SearchSet::matchPattern(StringList &list, const String &pattern) { + int matches = 0; + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + matches += (*it)._arc->matchPattern(list, pattern); + } + + return matches; +} + +int SearchSet::getAllNames(StringList &list) { + int matches = 0; + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + matches += (*it)._arc->getAllNames(list); + } + + return matches; +} + +SeekableReadStream *SearchSet::openFile(const String &name) { + if (name.empty()) { + return 0; + } + + ArchiveList::iterator it = _list.begin(); + for ( ; it != _list.end(); it++) { + if ((*it)._arc->hasFile(name)) { + return (*it)._arc->openFile(name); + } + } + + return 0; +} + + +DECLARE_SINGLETON(SearchManager); + +void SearchManager::addArchive(const String &name, ArchivePtr archive) { + add(name, archive); +} + +void SearchManager::addDirectory(const String &name, const String &directory) { + addDirectoryRecursive(name, 1); +} + +void SearchManager::addDirectoryRecursive(const String &name, const String &directory, int depth) { + add(name, SharedPtr<FSDirectory>(new FSDirectory(directory, depth))); +} + + +} // namespace Common diff --git a/common/archive.h b/common/archive.h new file mode 100644 index 0000000000..89ea6a5ce2 --- /dev/null +++ b/common/archive.h @@ -0,0 +1,231 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef COMMON_ARCHIVES_H +#define COMMON_ARCHIVES_H + +#include "common/fs.h" +#include "common/str.h" +#include "common/hash-str.h" +#include "common/list.h" +#include "common/ptr.h" +#include "common/singleton.h" +#include "common/stream.h" + +namespace Common { + +/** + * FilePtr is a convenient way to keep track of a SeekableReadStream without + * having to worry about releasing its memory. + */ +typedef SharedPtr<SeekableReadStream> FilePtr; + +/** + * Archive allows searches of (file)names into an arbitrary container. + * It also supports opening a file and returning an usable input stream. + */ +class Archive { +public: + virtual ~Archive() { } + + /** + * Check if a name is present in the Archive. Patterns are not allowed, + * as this is meant to be a quick File::exists() replacement. + */ + virtual bool hasFile(const String &name) = 0; + + /** + * Add all the names present in the Archive which match pattern to + * list. Returned names can be used as parameters to openFile. + * Must not remove elements from the list. + * + * @return the number of names added to list + */ + virtual int matchPattern(StringList &list, const String &pattern); + + /** + * Add all the names present in the Archive to list. Returned + * names can be used as parameters to openFile. + * Must not remove elements from the list. + * + * @return the number of names added to list + */ + virtual int getAllNames(StringList &list) = 0; + + /** + * Create a stream bound to a file in the archive. + * @return the newly created input stream + */ + virtual SeekableReadStream *openFile(const String &name) = 0; +}; + + +typedef SharedPtr<Archive> ArchivePtr; + + +/** + * FSDirectory models a directory tree from the filesystem and allows users + * to access it through the Archive interface. FSDirectory can represent a + * single directory, or a tree with specified depth, rooted in a 'base' + * directory. + * Searching is case-insensitive, as the main intended goal is supporting + * retrieval of game data. First case-insensitive match is returned when + * searching, thus making FSDirectory heavily dependant on the underlying + * FilesystemNode implementation. + */ +class FSDirectory : public Archive { + FilesystemNode _node; + + // Caches are case insensitive, clashes are dealt with when creating + // Key is stored in lowercase. + typedef HashMap<String, FilesystemNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache; + NodeCache _fileCache, _subDirCache; + + // look for a match + FilesystemNode lookupCache(NodeCache &cache, const String &name); + + // cache management + void cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix); + bool _cached; + int _depth; + +public: + /** + * Create a FSDirectory representing a tree with the specified depth. Will result in an + * unbound FSDirectory if name is not found on the filesystem or is not a directory. + */ + FSDirectory(const String &name, int depth = 1); + + /** + * Create a FSDirectory representing a tree with the specified depth. Will result in an + * unbound FSDirectory if node does not exist or is not a directory. + */ + FSDirectory(const FilesystemNode &node, int depth = 1); + + virtual ~FSDirectory(); + + /** + * This return the underlying FSNode of the FSDirectory. + */ + FilesystemNode getFSNode() const; + + /** + * Create a new FSDirectory pointing to a sub directory of the instance. + * @return a new FSDirectory instance + */ + FSDirectory *getSubDirectory(const String &name); + + virtual bool hasFile(const String &name); + virtual int matchPattern(StringList &list, const String &pattern); + virtual int getAllNames(StringList &list); + virtual SeekableReadStream *openFile(const String &name); +}; + + +/** + * SearchSet enables access to a group of Archives through the Archive interface. + * Its intended usage is a situation in which there are no name clashes among names in the + * contained Archives, hence the simplistic policy of always looking for the first + * match. SearchSet *DOES* guarantee that searches are performed in *DESCENDING* + * priority order. In case of conflicting priorities, insertion order prevails. + */ +class SearchSet : public Archive { + struct Node { + uint _priority; + String _name; + ArchivePtr _arc; + }; + typedef List<Node> ArchiveList; + ArchiveList _list; + + ArchiveList::iterator find(const String &name) const; + + // Add an archive keeping the list sorted by ascending priorities. + void insert(const Node& node); + +public: + /** + * Add a new archive to the searchable set. + */ + void add(const String& name, ArchivePtr archive, uint priority = 0); + + /** + * Remove an archive from the searchable set. + */ + void remove(const String& name); + + /** + * Check if a given archive name is already present. + */ + bool hasArchive(const String &name) const; + + /** + * Empties the searchable set. + */ + void clear(); + + /** + * Change the order of searches. + */ + void setPriority(const String& name, uint priority); + + virtual bool hasFile(const String &name); + virtual int matchPattern(StringList &list, const String &pattern); + virtual int getAllNames(StringList &list); + + /** + * Implements openFile from Archive base class. The current policy is + * opening the first file encountered that matches the name. + */ + virtual SeekableReadStream *openFile(const String &name); +}; + + +class SearchManager : public Singleton<SearchManager>, public SearchSet { +public: + /** + * Add an existing Archive. This is meant to support searching in system-specific + * archives, namely the MACOSX/IPHONE bundles. + */ + void addArchive(const String &name, ArchivePtr archive); + + /** + * Create and add a FSDirectory by name + */ + void addDirectory(const String &name, const String &directory); + + /** + * Create and add a FSDirectory and its subdirectories by name + */ + void addDirectoryRecursive(const String &name, const String &directory, int depth = 4); + +}; + +/** Shortcut for accessing the search manager. */ +#define SearchMan Common::SearchManager::instance() + +} // namespace Common + +#endif diff --git a/common/array.h b/common/array.h index 854ce5b91d..693c024d11 100644 --- a/common/array.h +++ b/common/array.h @@ -35,7 +35,7 @@ class Array { protected: uint _capacity; uint _size; - T *_data; + T *_storage; public: typedef T *iterator; @@ -44,41 +44,41 @@ public: typedef T value_type; public: - Array() : _capacity(0), _size(0), _data(0) {} - Array(const Array<T> &array) : _capacity(0), _size(0), _data(0) { + Array() : _capacity(0), _size(0), _storage(0) {} + Array(const Array<T> &array) : _capacity(0), _size(0), _storage(0) { _size = array._size; _capacity = _size + 32; - _data = new T[_capacity]; - copy(array._data, array._data + _size, _data); + _storage = new T[_capacity]; + copy(array._storage, array._storage + _size, _storage); } ~Array() { - delete[] _data; + delete[] _storage; } void push_back(const T &element) { ensureCapacity(_size + 1); - _data[_size++] = element; + _storage[_size++] = element; } void push_back(const Array<T> &array) { ensureCapacity(_size + array._size); - copy(array._data, array._data + array._size, _data + _size); + copy(array._storage, array._storage + array._size, _storage + _size); _size += array._size; } void insert_at(int idx, const T &element) { assert(idx >= 0 && (uint)idx <= _size); ensureCapacity(_size + 1); - copy_backward(_data + idx, _data + _size, _data + _size + 1); - _data[idx] = element; + copy_backward(_storage + idx, _storage + _size, _storage + _size + 1); + _storage[idx] = element; _size++; } T remove_at(int idx) { assert(idx >= 0 && (uint)idx < _size); - T tmp = _data[idx]; - copy(_data + idx + 1, _data + _size, _data + idx); + T tmp = _storage[idx]; + copy(_storage + idx + 1, _storage + _size, _storage + idx); _size--; return tmp; } @@ -87,23 +87,23 @@ public: T& operator[](int idx) { assert(idx >= 0 && (uint)idx < _size); - return _data[idx]; + return _storage[idx]; } const T& operator[](int idx) const { assert(idx >= 0 && (uint)idx < _size); - return _data[idx]; + return _storage[idx]; } Array<T>& operator=(const Array<T> &array) { if (this == &array) return *this; - delete[] _data; + delete[] _storage; _size = array._size; _capacity = _size + 32; - _data = new T[_capacity]; - copy(array._data, array._data + _size, _data); + _storage = new T[_capacity]; + copy(array._storage, array._storage + _size, _storage); return *this; } @@ -113,8 +113,8 @@ public: } void clear() { - delete[] _data; - _data = 0; + delete[] _storage; + _storage = 0; _size = 0; _capacity = 0; } @@ -125,33 +125,33 @@ public: iterator begin() { - return _data; + return _storage; } iterator end() { - return _data + _size; + return _storage + _size; } const_iterator begin() const { - return _data; + return _storage; } const_iterator end() const { - return _data + _size; + return _storage + _size; } void reserve(uint newCapacity) { if (newCapacity <= _capacity) return; - T *old_data = _data; + T *old_storage = _storage; _capacity = newCapacity; - _data = new T[newCapacity]; + _storage = new T[newCapacity]; - if (old_data) { + if (old_storage) { // Copy old data - copy(old_data, old_data + _size, _data); - delete[] old_data; + copy(old_storage, old_storage + _size, _storage); + delete[] old_storage; } } @@ -159,14 +159,14 @@ public: if (newSize == _size) return; - T *old_data = _data; + T *old_storage = _storage; _capacity = newSize; - _data = new T[newSize]; - if (old_data) { + _storage = new T[newSize]; + if (old_storage) { // Copy old data int cnt = (_size < newSize ? _size : newSize); - copy(old_data, old_data + cnt, _data); - delete[] old_data; + copy(old_storage, old_storage + cnt, _storage); + delete[] old_storage; } _size = newSize; } diff --git a/common/config-file.cpp b/common/config-file.cpp index 9f54c9ddde..c3764a02da 100644 --- a/common/config-file.cpp +++ b/common/config-file.cpp @@ -77,7 +77,6 @@ bool ConfigFile::loadFromSaveFile(const char *filename) { } bool ConfigFile::loadFromStream(SeekableReadStream &stream) { - char buf[MAXLINELEN]; Section section; KeyValue kv; String comment; @@ -86,18 +85,21 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { // TODO: Detect if a section occurs multiple times (or likewise, if // a key occurs multiple times inside one section). - while (!stream.eos()) { + while (!stream.eos() && !stream.ioFailed()) { lineno++; - if (!stream.readLine(buf, MAXLINELEN)) - break; - if (buf[0] == '#') { + // Read a line + String line = stream.readLine(); + + if (line.size() == 0) { + // Do nothing + } else if (line[0] == '#') { // Accumulate comments here. Once we encounter either the start // of a new section, or a key-value-pair, we associate the value // of the 'comment' variable with that entity. - comment += buf; + comment += line; comment += "\n"; - } else if (buf[0] == '(') { + } else if (line[0] == '(') { // HACK: The following is a hack added by Kirben to support the // "map.ini" used in the HE SCUMM game "SPY Fox in Hold the Mustard". // @@ -105,11 +107,11 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { // but the current design of this class doesn't allow to do that // in a nice fashion (a "isMustard" parameter is *not* a nice // solution). - comment += buf; + comment += line; comment += "\n"; - } else if (buf[0] == '[') { + } else if (line[0] == '[') { // It's a new section which begins here. - char *p = buf + 1; + const char *p = line.c_str() + 1; // Get the section name, and check whether it's valid (that // is, verify that it only consists of alphanumerics, // dashes and underscores). @@ -121,23 +123,25 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { else if (*p != ']') error("ConfigFile::loadFromStream: Invalid character '%c' occured in section name in line %d", *p, lineno); - *p = 0; - // Previous section is finished now, store it. if (!section.name.empty()) _sections.push_back(section); - section.name = buf + 1; + section.name = String(line.c_str() + 1, p); section.keys.clear(); section.comment = comment; comment.clear(); assert(isValidName(section.name)); } else { - // Skip leading & trailing whitespaces - char *t = rtrim(ltrim(buf)); - - // Skip empty lines + // This line should be a line with a 'key=value' pair, or an empty one. + + // Skip leading whitespaces + const char *t = line.c_str(); + while (isspace(*t)) + t++; + + // Skip empty lines / lines with only whitespace if (*t == 0) continue; @@ -146,14 +150,20 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) { error("ConfigFile::loadFromStream: Key/value pair found outside a section in line %d", lineno); } - // Split string at '=' into 'key' and 'value'. - char *p = strchr(t, '='); + // Split string at '=' into 'key' and 'value'. First, find the "=" delimeter. + const char *p = strchr(t, '='); if (!p) - error("ConfigFile::loadFromStream: Junk found in line line %d: '%s'", lineno, t); - *p = 0; + error("Config file buggy: Junk found in line line %d: '%s'", lineno, t); + + // Extract the key/value pair + kv.key = String(t, p); + kv.value = String(p + 1); + + // Trim of spaces + kv.key.trim(); + kv.value.trim(); - kv.key = rtrim(t); - kv.value = ltrim(p + 1); + // Store comment kv.comment = comment; comment.clear(); @@ -225,7 +235,7 @@ bool ConfigFile::saveToStream(WriteStream &stream) { void ConfigFile::removeSection(const String §ion) { assert(isValidName(section)); for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { _sections.erase(i); return; } @@ -318,7 +328,7 @@ const ConfigFile::SectionKeyList ConfigFile::getKeys(const String §ion) cons ConfigFile::Section *ConfigFile::getSection(const String §ion) { for (List<Section>::iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { return &(*i); } } @@ -327,7 +337,7 @@ ConfigFile::Section *ConfigFile::getSection(const String §ion) { const ConfigFile::Section *ConfigFile::getSection(const String §ion) const { for (List<Section>::const_iterator i = _sections.begin(); i != _sections.end(); ++i) { - if (!scumm_stricmp(section.c_str(), i->name.c_str())) { + if (section.equalsIgnoreCase(i->name)) { return &(*i); } } @@ -340,7 +350,7 @@ bool ConfigFile::Section::hasKey(const String &key) const { const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const { for (List<KeyValue>::const_iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { return &(*i); } } @@ -349,7 +359,7 @@ const ConfigFile::KeyValue* ConfigFile::Section::getKey(const String &key) const void ConfigFile::Section::setKey(const String &key, const String &value) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { i->value = value; return; } @@ -363,7 +373,7 @@ void ConfigFile::Section::setKey(const String &key, const String &value) { void ConfigFile::Section::removeKey(const String &key) { for (List<KeyValue>::iterator i = keys.begin(); i != keys.end(); ++i) { - if (!scumm_stricmp(key.c_str(), i->key.c_str())) { + if (key.equalsIgnoreCase(i->key)) { keys.erase(i); return; } diff --git a/common/config-manager.cpp b/common/config-manager.cpp index 138fcc201f..b741757cc5 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -103,13 +103,7 @@ void ConfigManager::loadFromStream(SeekableReadStream &stream) { lineno++; // Read a line - String line; - while (line.lastChar() != '\n') { - char buf[256]; - if (!stream.readLine_NEW(buf, 256)) - break; - line += buf; - } + String line = stream.readLine(); if (line.size() == 0) { // Do nothing @@ -118,6 +112,7 @@ void ConfigManager::loadFromStream(SeekableReadStream &stream) { // of a new domain, or a key-value-pair, we associate the value // of the 'comment' variable with that entity. comment += line; + comment += "\n"; } else if (line[0] == '[') { // It's a new domain which begins here. const char *p = line.c_str() + 1; diff --git a/common/events.h b/common/events.h index d0cb740692..f01282765a 100644 --- a/common/events.h +++ b/common/events.h @@ -27,6 +27,7 @@ #define COMMON_EVENTS_H #include "common/keyboard.h" +#include "common/queue.h" #include "common/rect.h" #include "common/system.h" #include "common/noncopyable.h" @@ -58,6 +59,9 @@ enum EventType { EVENT_MBUTTONDOWN = 13, EVENT_MBUTTONUP = 14, + EVENT_MAINMENU = 15, + EVENT_RTL = 16, + EVENT_QUIT = 10, EVENT_SCREEN_CHANGED = 11, /** @@ -142,6 +146,11 @@ public: */ virtual bool pollEvent(Common::Event &event) = 0; + /** + * Pushes a "fake" event of the specified type into the event queue + */ + virtual void pushEvent(Common::Event event) = 0; + /** Register random source so it can be serialized in game test purposes **/ virtual void registerRandomSource(Common::RandomSource &rnd, const char *name) = 0; @@ -166,6 +175,17 @@ public: */ virtual int shouldQuit() const = 0; + /** + * Should we return to the launcher? + */ + virtual int shouldRTL() const = 0; + + /** + * Reset the "return to launcher" flag (as returned shouldRTL()) to false. + * Used when we have returned to the launcher. + */ + virtual void resetRTL() = 0; + // Optional: check whether a given key is currently pressed ???? //virtual bool isKeyPressed(int keycode) = 0; @@ -173,6 +193,9 @@ public: // TODO: Consider removing OSystem::getScreenChangeID and // replacing it by a generic getScreenChangeID method here +protected: + + Common::Queue<Common::Event> artificialEventQueue; }; } // End of namespace Common diff --git a/common/file.cpp b/common/file.cpp index fb837b9499..cf396a32cd 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -23,254 +23,51 @@ * */ +#include "common/archive.h" #include "common/file.h" #include "common/fs.h" -#include "common/hashmap.h" #include "common/util.h" -#include "common/hash-str.h" -#include <errno.h> - -#if defined(MACOSX) || defined(IPHONE) -#include "CoreFoundation/CoreFoundation.h" -#endif - -#ifdef __PLAYSTATION2__ - // for those replaced fopen/fread/etc functions - typedef unsigned long uint64; - typedef signed long int64; - #include "backends/platform/ps2/fileio.h" - - #define fopen(a, b) ps2_fopen(a, b) - #define fclose(a) ps2_fclose(a) - #define fseek(a, b, c) ps2_fseek(a, b, c) - #define ftell(a) ps2_ftell(a) - #define feof(a) ps2_feof(a) - #define fread(a, b, c, d) ps2_fread(a, b, c, d) - #define fwrite(a, b, c, d) ps2_fwrite(a, b, c, d) - - //#define fprintf ps2_fprintf // used in common/util.cpp - //#define fflush(a) ps2_fflush(a) // used in common/util.cpp - - //#define fgetc(a) ps2_fgetc(a) // not used - //#define fgets(a, b, c) ps2_fgets(a, b, c) // not used - //#define fputc(a, b) ps2_fputc(a, b) // not used - //#define fputs(a, b) ps2_fputs(a, b) // not used - - //#define fsize(a) ps2_fsize(a) // not used -- and it is not a standard function either -#endif - -#ifdef __DS__ - - // These functions replease the standard library functions of the same name. - // As this header is included after the standard one, I have the chance to #define - // all of these to my own code. - // - // A #define is the only way, as redefinig the functions would cause linker errors. - - // These functions need to be #undef'ed, as their original definition - // in devkitarm is done with #includes (ugh!) - #undef feof - #undef clearerr - //#undef getc - //#undef ferror - - #include "backends/fs/ds/ds-fs.h" - - - //void std_fprintf(FILE* handle, const char* fmt, ...); // used in common/util.cpp - //void std_fflush(FILE* handle); // used in common/util.cpp - - //char* std_fgets(char* str, int size, FILE* file); // not used - //int std_getc(FILE* handle); // not used - //char* std_getcwd(char* dir, int dunno); // not used - //void std_cwd(char* dir); // not used - //int std_ferror(FILE* handle); // not used - - // Only functions used in the ScummVM source have been defined here! - #define fopen(name, mode) DS::std_fopen(name, mode) - #define fclose(handle) DS::std_fclose(handle) - #define fread(ptr, size, items, file) DS::std_fread(ptr, size, items, file) - #define fwrite(ptr, size, items, file) DS::std_fwrite(ptr, size, items, file) - #define feof(handle) DS::std_feof(handle) - #define ftell(handle) DS::std_ftell(handle) - #define fseek(handle, offset, whence) DS::std_fseek(handle, offset, whence) - #define clearerr(handle) DS::std_clearerr(handle) - - //#define printf(fmt, ...) consolePrintf(fmt, ##__VA_ARGS__) - - //#define fprintf(file, fmt, ...) { char str[128]; sprintf(str, fmt, ##__VA_ARGS__); DS::std_fwrite(str, strlen(str), 1, file); } - //#define fflush(file) DS::std_fflush(file) // used in common/util.cpp - - //#define fgets(str, size, file) DS::std_fgets(str, size, file) // not used - //#define getc(handle) DS::std_getc(handle) // not used - //#define getcwd(dir, dunno) DS::std_getcwd(dir, dunno) // not used - #define ferror(handle) DS::std_ferror(handle) - -#endif - -#ifdef __SYMBIAN32__ - #undef feof - #undef clearerr - - #define FILE void - - FILE* symbian_fopen(const char* name, const char* mode); - void symbian_fclose(FILE* handle); - size_t symbian_fread(const void* ptr, size_t size, size_t numItems, FILE* handle); - size_t symbian_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle); - bool symbian_feof(FILE* handle); - long int symbian_ftell(FILE* handle); - int symbian_fseek(FILE* handle, long int offset, int whence); - void symbian_clearerr(FILE* handle); - - // Only functions used in the ScummVM source have been defined here! - #define fopen(name, mode) symbian_fopen(name, mode) - #define fclose(handle) symbian_fclose(handle) - #define fread(ptr, size, items, file) symbian_fread(ptr, size, items, file) - #define fwrite(ptr, size, items, file) symbian_fwrite(ptr, size, items, file) - #define feof(handle) symbian_feof(handle) - #define ftell(handle) symbian_ftell(handle) - #define fseek(handle, offset, whence) symbian_fseek(handle, offset, whence) - #define clearerr(handle) symbian_clearerr(handle) -#endif +#include "common/system.h" namespace Common { -typedef HashMap<String, int> StringIntMap; - -// The following two objects could be turned into static members of class -// File. However, then we would be forced to #include hashmap in file.h -// which seems to be a high price just for a simple beautification... -static StringIntMap *_defaultDirectories; -static StringMap *_filesMap; - -static FILE *fopenNoCase(const String &filename, const String &directory, const char *mode) { - FILE *file; - String dirBuf(directory); - String fileBuf(filename); - -#if !defined(__GP32__) && !defined(PALMOS_MODE) - // Add a trailing slash, if necessary. - if (!dirBuf.empty()) { - const char c = dirBuf.lastChar(); - if (c != ':' && c != '/' && c != '\\') - dirBuf += '/'; - } -#endif - - // Append the filename to the path string - String pathBuf(dirBuf); - pathBuf += fileBuf; - - // - // Try to open the file normally - // - file = fopen(pathBuf.c_str(), mode); - - // - // Try again, with file name converted to upper case - // - if (!file) { - fileBuf.toUppercase(); - pathBuf = dirBuf + fileBuf; - file = fopen(pathBuf.c_str(), mode); - } - - // - // Try again, with file name converted to lower case - // - if (!file) { - fileBuf.toLowercase(); - pathBuf = dirBuf + fileBuf; - file = fopen(pathBuf.c_str(), mode); - } - - // - // Try again, with file name capitalized - // - if (!file) { - fileBuf.toLowercase(); - fileBuf.setChar(toupper(fileBuf[0]),0); - pathBuf = dirBuf + fileBuf; - file = fopen(pathBuf.c_str(), mode); - } - -#ifdef __amigaos4__ - // - // Work around for possibility that someone uses AmigaOS "newlib" build with SmartFileSystem (blocksize 512 bytes), leading - // to buffer size being only 512 bytes. "Clib2" sets the buffer size to 8KB, resulting smooth movie playback. This forces the buffer - // to be enough also when using "newlib" compile on SFS. - // - if (file) { - setvbuf(file, NULL, _IOFBF, 8192); - } -#endif +static Common::SearchSet *s_searchSet = 0; - return file; -} void File::addDefaultDirectory(const String &directory) { FilesystemNode dir(directory); addDefaultDirectoryRecursive(dir, 1); } -void File::addDefaultDirectoryRecursive(const String &directory, int level, const String &prefix) { +void File::addDefaultDirectoryRecursive(const String &directory, int level) { FilesystemNode dir(directory); - addDefaultDirectoryRecursive(dir, level, prefix); + addDefaultDirectoryRecursive(dir, level); } void File::addDefaultDirectory(const FilesystemNode &directory) { addDefaultDirectoryRecursive(directory, 1); } -void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level, const String &prefix) { - if (level <= 0) +void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level) { + if (level <= 0 || !dir.exists() || !dir.isDirectory()) return; - FSList fslist; - if (!dir.getChildren(fslist, FilesystemNode::kListAll)) { - // Failed listing the contents of this node, so it is either not a - // directory, or just doesn't exist at all. - return; + if (!s_searchSet) { + s_searchSet = new Common::SearchSet(); + g_system->addSysArchivesToSearchSet(*s_searchSet); } - if (!_defaultDirectories) - _defaultDirectories = new StringIntMap; - - // Do not add directories multiple times, unless this time they are added - // with a bigger depth. - const String &directory(dir.getPath()); - if (_defaultDirectories->contains(directory) && (*_defaultDirectories)[directory] >= level) - return; - (*_defaultDirectories)[directory] = level; - - if (!_filesMap) - _filesMap = new StringMap; - - for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - if (file->isDirectory()) { - addDefaultDirectoryRecursive(file->getPath(), level - 1, prefix + file->getName() + "/"); - } else { - String lfn(prefix); - lfn += file->getName(); - lfn.toLowercase(); - if (!_filesMap->contains(lfn)) { - (*_filesMap)[lfn] = file->getPath(); - } - } - } + Common::ArchivePtr dataArchive(new Common::FSDirectory(dir, level)); + s_searchSet->add(dir.getPath(), dataArchive, 1); } void File::resetDefaultDirectories() { - delete _defaultDirectories; - delete _filesMap; - - _defaultDirectories = 0; - _filesMap = 0; + delete s_searchSet; + s_searchSet = 0; } File::File() - : _handle(0), _ioFailed(false) { + : _handle(0) { } File::~File() { @@ -285,51 +82,21 @@ bool File::open(const String &filename) { _name.clear(); clearIOFailed(); - String fname(filename); - fname.toLowercase(); - - if (_filesMap && _filesMap->contains(fname)) { - fname = (*_filesMap)[fname]; - debug(3, "Opening hashed: %s", fname.c_str()); - _handle = fopen(fname.c_str(), "rb"); - } else if (_filesMap && _filesMap->contains(fname + ".")) { + if (s_searchSet && s_searchSet->hasFile(filename)) { + debug(3, "Opening hashed: %s", filename.c_str()); + _handle = s_searchSet->openFile(filename); + } else if (s_searchSet && s_searchSet->hasFile(filename + ".")) { // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails" // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot) - fname = (*_filesMap)[fname + "."]; - debug(3, "Opening hashed: %s", fname.c_str()); - _handle = fopen(fname.c_str(), "rb"); + debug(3, "Opening hashed: %s.", filename.c_str()); + _handle = s_searchSet->openFile(filename); } else { - - if (_defaultDirectories) { - // Try all default directories - StringIntMap::const_iterator x(_defaultDirectories->begin()); - for (; _handle == NULL && x != _defaultDirectories->end(); ++x) { - _handle = fopenNoCase(filename, x->_key, "rb"); - } - } - // Last resort: try the current directory - if (_handle == NULL) - _handle = fopenNoCase(filename, "", "rb"); - - // Last last (really) resort: try looking inside the application bundle on Mac OS X for the lowercase file. -#if defined(MACOSX) || defined(IPHONE) - if (!_handle) { - CFStringRef cfFileName = CFStringCreateWithBytes(NULL, (const UInt8 *)filename.c_str(), filename.size(), kCFStringEncodingASCII, false); - CFURLRef fileUrl = CFBundleCopyResourceURL(CFBundleGetMainBundle(), cfFileName, NULL, NULL); - if (fileUrl) { - UInt8 buf[256]; - if (CFURLGetFileSystemRepresentation(fileUrl, false, (UInt8 *)buf, 256)) { - _handle = fopen((char *)buf, "rb"); - } - CFRelease(fileUrl); - } - CFRelease(cfFileName); - } -#endif - + FilesystemNode file(filename); + if (file.exists() && !file.isDirectory()) + _handle = file.openForReading(); } - + if (_handle == NULL) debug(2, "File %s not opened", filename.c_str()); else @@ -341,18 +108,12 @@ bool File::open(const String &filename) { bool File::open(const FilesystemNode &node) { if (!node.exists()) { - warning("File::open: Trying to open a FilesystemNode which does not exist"); + warning("File::open: FilesystemNode does not exist"); return false; } else if (node.isDirectory()) { - warning("File::open: Trying to open a FilesystemNode which is a directory"); + warning("File::open: FilesystemNode is a directory"); return false; - } /*else if (!node.isReadable() && mode == kFileReadMode) { - warning("File::open: Trying to open an unreadable FilesystemNode object for reading"); - return false; - } else if (!node.isWritable() && mode == kFileWriteMode) { - warning("File::open: Trying to open an unwritable FilesystemNode object for writing"); - return false; - }*/ + } String filename(node.getName()); @@ -363,7 +124,7 @@ bool File::open(const FilesystemNode &node) { clearIOFailed(); _name.clear(); - _handle = fopen(node.getPath().c_str(), "rb"); + _handle = node.openForReading(); if (_handle == NULL) debug(2, "File %s not found", filename.c_str()); @@ -374,39 +135,24 @@ bool File::open(const FilesystemNode &node) { } bool File::exists(const String &filename) { - // First try to find the file via a FilesystemNode (in case an absolute - // path was passed). This is only used to filter out directories. - FilesystemNode file(filename); - if (file.exists()) - return !file.isDirectory(); - - // See if the file is already mapped - if (_filesMap && _filesMap->contains(filename)) { - FilesystemNode file2((*_filesMap)[filename]); - - if (file2.exists()) - return !file2.isDirectory(); - } - - // Try all default directories - if (_defaultDirectories) { - StringIntMap::const_iterator i(_defaultDirectories->begin()); - for (; i != _defaultDirectories->end(); ++i) { - FilesystemNode file2(i->_key + filename); - - if(file2.exists()) - return !file2.isDirectory(); - } + if (s_searchSet && s_searchSet->hasFile(filename)) { + return true; + } else if (s_searchSet && s_searchSet->hasFile(filename + ".")) { + // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails" + // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot) + return true; + } else { + // Last resort: try the current directory + FilesystemNode file(filename); + if (file.exists() && !file.isDirectory()) + return true; } - - //Try opening the file inside the local directory as a last resort - File tmp; - return tmp.open(filename); + + return false; } void File::close() { - if (_handle) - fclose((FILE *)_handle); + delete _handle; _handle = NULL; } @@ -416,59 +162,47 @@ bool File::isOpen() const { bool File::ioFailed() const { // TODO/FIXME: Just use ferror() here? - return _ioFailed != 0; + return !_handle || _handle->ioFailed(); } void File::clearIOFailed() { - // TODO/FIXME: Just use clearerr() here? - _ioFailed = false; + if (_handle) + _handle->clearIOFailed(); } -bool File::eof() const { +bool File::err() const { assert(_handle); - - return feof((FILE *)_handle) != 0; + return _handle->err(); } -uint32 File::pos() const { +void File::clearErr() { assert(_handle); - - return ftell((FILE *)_handle); + _handle->clearErr(); } -uint32 File::size() const { +bool File::eos() const { assert(_handle); + return _handle->eos(); +} - uint32 oldPos = ftell((FILE *)_handle); - fseek((FILE *)_handle, 0, SEEK_END); - uint32 length = ftell((FILE *)_handle); - fseek((FILE *)_handle, oldPos, SEEK_SET); - - return length; +int32 File::pos() const { + assert(_handle); + return _handle->pos(); } -void File::seek(int32 offs, int whence) { +int32 File::size() const { assert(_handle); + return _handle->size(); +} - if (fseek((FILE *)_handle, offs, whence) != 0) - clearerr((FILE *)_handle); +bool File::seek(int32 offs, int whence) { + assert(_handle); + return _handle->seek(offs, whence); } uint32 File::read(void *ptr, uint32 len) { - byte *ptr2 = (byte *)ptr; - uint32 real_len; - assert(_handle); - - if (len == 0) - return 0; - - real_len = fread(ptr2, 1, len, (FILE *)_handle); - if (real_len < len) { - _ioFailed = true; - } - - return real_len; + return _handle->read(ptr, len); } @@ -483,32 +217,19 @@ bool DumpFile::open(const String &filename) { assert(!filename.empty()); assert(!_handle); - String fname(filename); - fname.toLowercase(); - - _handle = fopenNoCase(filename, "", "wb"); - - if (_handle == NULL) - debug(2, "Failed to open '%s' for writing", filename.c_str()); - - return _handle != NULL; + FilesystemNode node(filename); + return open(node); } bool DumpFile::open(const FilesystemNode &node) { assert(!_handle); if (node.isDirectory()) { - warning("File::open: Trying to open a FilesystemNode which is a directory"); - return false; - } /*else if (!node.isReadable() && mode == kFileReadMode) { - warning("File::open: Trying to open an unreadable FilesystemNode object for reading"); + warning("DumpFile::open: FilesystemNode is a directory"); return false; - } else if (!node.isWritable() && mode == kFileWriteMode) { - warning("File::open: Trying to open an unwritable FilesystemNode object for writing"); - return false; - }*/ + } - _handle = fopen(node.getPath().c_str(), "wb"); + _handle = node.openForWriting(); if (_handle == NULL) debug(2, "File %s not found", node.getName().c_str()); @@ -517,8 +238,7 @@ bool DumpFile::open(const FilesystemNode &node) { } void DumpFile::close() { - if (_handle) - fclose((FILE *)_handle); + delete _handle; _handle = NULL; } @@ -526,36 +246,24 @@ bool DumpFile::isOpen() const { return _handle != NULL; } -bool DumpFile::ioFailed() const { - assert(_handle); - return ferror((FILE *)_handle) != 0; -} - -void DumpFile::clearIOFailed() { +bool DumpFile::err() const { assert(_handle); - clearerr((FILE *)_handle); + return _handle->ioFailed(); } -bool DumpFile::eof() const { +void DumpFile::clearErr() { assert(_handle); - return feof((FILE *)_handle) != 0; + _handle->clearIOFailed(); } uint32 DumpFile::write(const void *ptr, uint32 len) { assert(_handle); - - if (len == 0) - return 0; - - return (uint32)fwrite(ptr, 1, len, (FILE *)_handle); + return _handle->write(ptr, len); } -void DumpFile::flush() { +bool DumpFile::flush() { assert(_handle); - // TODO: Should check the return value of fflush, and if it is non-zero, - // check errno and set an error flag. - fflush((FILE *)_handle); + return _handle->flush(); } - } // End of namespace Common diff --git a/common/file.h b/common/file.h index 3adeb6ff36..a2739f795f 100644 --- a/common/file.h +++ b/common/file.h @@ -31,20 +31,17 @@ #include "common/str.h" #include "common/stream.h" -class FilesystemNode; - namespace Common { +class FilesystemNode; + /** * TODO: vital to document this core class properly!!! For both users and implementors */ class File : public SeekableReadStream, public NonCopyable { protected: /** File handle to the actual file; 0 if no file is open. */ - void *_handle; - - /** Status flag which tells about recent I/O failures. */ - bool _ioFailed; + SeekableReadStream *_handle; /** The name of this file, for debugging. */ String _name; @@ -52,10 +49,10 @@ protected: public: static void addDefaultDirectory(const String &directory); - static void addDefaultDirectoryRecursive(const String &directory, int level = 4, const String &prefix = ""); + static void addDefaultDirectoryRecursive(const String &directory, int level = 4); static void addDefaultDirectory(const FilesystemNode &directory); - static void addDefaultDirectoryRecursive(const FilesystemNode &directory, int level = 4, const String &prefix = ""); + static void addDefaultDirectoryRecursive(const FilesystemNode &directory, int level = 4); static void resetDefaultDirectories(); @@ -93,18 +90,13 @@ public: bool ioFailed() const; void clearIOFailed(); - bool eos() const { return eof(); } - - /** - * Checks for end of file. - * - * @return: true if the end of file is reached, false otherwise. - */ - virtual bool eof() const; + bool err() const; + void clearErr(); + bool eos() const; - virtual uint32 pos() const; - virtual uint32 size() const; - void seek(int32 offs, int whence = SEEK_SET); + virtual int32 pos() const; + virtual int32 size() const; + bool seek(int32 offs, int whence = SEEK_SET); uint32 read(void *dataPtr, uint32 dataSize); }; @@ -118,7 +110,7 @@ public: class DumpFile : public WriteStream, public NonCopyable { protected: /** File handle to the actual file; 0 if no file is open. */ - void *_handle; + WriteStream *_handle; public: DumpFile(); @@ -136,24 +128,14 @@ public: */ bool isOpen() const; - - bool ioFailed() const; - void clearIOFailed(); - bool eos() const { return eof(); } - - /** - * Checks for end of file. - * - * @return: true if the end of file is reached, false otherwise. - */ - virtual bool eof() const; + bool err() const; + void clearErr(); virtual uint32 write(const void *dataPtr, uint32 dataSize); - virtual void flush(); + virtual bool flush(); }; - } // End of namespace Common #endif diff --git a/common/fs.cpp b/common/fs.cpp index 3f585c6038..4d31ac09fa 100644 --- a/common/fs.cpp +++ b/common/fs.cpp @@ -23,12 +23,11 @@ */ #include "common/util.h" -#include "common/file.h" #include "common/system.h" #include "backends/fs/abstract-fs.h" #include "backends/fs/fs-factory.h" -//namespace Common { +namespace Common { FilesystemNode::FilesystemNode() { } @@ -52,7 +51,7 @@ bool FilesystemNode::operator<(const FilesystemNode& node) const { if (isDirectory() != node.isDirectory()) return isDirectory(); - return scumm_stricmp(getDisplayName().c_str(), node.getDisplayName().c_str()) < 0; + return getDisplayName().compareToIgnoreCase(node.getDisplayName()) < 0; } bool FilesystemNode::exists() const { @@ -63,10 +62,10 @@ bool FilesystemNode::exists() const { } FilesystemNode FilesystemNode::getChild(const Common::String &n) const { - if (_realNode == 0) - return *this; + // If this node is invalid or not a directory, return an invalid node + if (_realNode == 0 || !_realNode->isDirectory()) + return FilesystemNode(); - assert(_realNode->isDirectory()); AbstractFilesystemNode *node = _realNode->getChild(n); return FilesystemNode(node); } @@ -155,7 +154,7 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h } else { Common::String filename = entry->getName(); filename.toUppercase(); - if (Common::matchString(filename.c_str(), pattern.c_str())) { + if (filename.matchString(pattern)) { results.push_back(*entry); if (!exhaustive) @@ -174,40 +173,31 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h return !results.empty(); } -Common::SeekableReadStream *FilesystemNode::openForReading() { +Common::SeekableReadStream *FilesystemNode::openForReading() const { if (_realNode == 0) return 0; -#if 0 - return _realNode->openForReading(); -#else - // FIXME: Until we support openForReading in AbstractFilesystemNode, - // we just use Common::File. - Common::File *confFile = new Common::File(); - assert(confFile); - if (!confFile->open(*this)) { - delete confFile; - confFile = 0; + + if (!_realNode->exists()) { + warning("FilesystemNode::openForReading: FilesystemNode does not exist"); + return false; + } else if (_realNode->isDirectory()) { + warning("FilesystemNode::openForReading: FilesystemNode is a directory"); + return false; } - return confFile; -#endif + + return _realNode->openForReading(); } -Common::WriteStream *FilesystemNode::openForWriting() { +Common::WriteStream *FilesystemNode::openForWriting() const { if (_realNode == 0) return 0; -#if 0 - return _realNode->openForWriting(); -#else - // FIXME: Until we support openForWriting in AbstractFilesystemNode, - // we just use Common::DumpFile. - Common::DumpFile *confFile = new Common::DumpFile(); - assert(confFile); - if (!confFile->open(*this)) { - delete confFile; - confFile = 0; + + if (_realNode->isDirectory()) { + warning("FilesystemNode::openForWriting: FilesystemNode is a directory"); + return 0; } - return confFile; -#endif + + return _realNode->openForWriting(); } -//} // End of namespace Common +} // End of namespace Common diff --git a/common/fs.h b/common/fs.h index 972e0d86af..c5f7ca6b4c 100644 --- a/common/fs.h +++ b/common/fs.h @@ -32,15 +32,10 @@ class AbstractFilesystemNode; namespace Common { - class SeekableReadStream; - class WriteStream; -} - -//namespace Common { class FilesystemNode; -//class SeekableReadStream; -//class WriteStream; +class SeekableReadStream; +class WriteStream; /** * List of multiple file system nodes. E.g. the contents of a given directory. @@ -107,17 +102,29 @@ public: virtual bool exists() const; /** - * Fetch a child node of this node, with the given name. Only valid for - * directory nodes (an assertion is triggered otherwise). - * If no child node with the given name exists, an invalid node is returned. + * Create a new node referring to a child node of the current node, which + * must be a directory node (otherwise an invalid node is returned). + * If a child matching the name exists, a normal node for it is returned. + * If no child with the name exists, a node for it is still returned, + * but exists() will return 'false' for it. This node can however be used + * to create a new file using the openForWriting() method. + * + * @todo If openForWriting() (or a hypothetical future mkdir() method) is used, + * this should affect what exists/isDirectory/isReadable/isWritable return + * for existing nodes. However, this is not the case for many existing + * FSNode implementations. Either fix those, or document that FSNodes + * can become 'stale'... + * + * @param name the name of a child of this directory + * @return the node referring to the child with the given name */ FilesystemNode getChild(const Common::String &name) const; /** - * Return a list of child nodes of this directory node. If called on a node + * Return a list of all child nodes of this directory node. If called on a node * that does not represent a directory, false is returned. * - * @return true if succesful, false otherwise (e.g. when the directory does not exist). + * @return true if successful, false otherwise (e.g. when the directory does not exist). */ virtual bool getChildren(FSList &fslist, ListMode mode = kListDirectoriesOnly, bool hidden = false) const; @@ -141,10 +148,11 @@ public: virtual Common::String getName() const; /** - * Return a string representation of the file which can be passed to fopen(), - * and is suitable for archiving (i.e. writing to the config file). - * This will usually be a 'path' (hence the name of the method), but can - * be anything that fulfills the above criterions. + * Return a string representation of the file which is suitable for + * archiving (i.e. writing to the config file). This will usually be a + * 'path' (hence the name of the method), but can be anything that meets + * the above criterions. What a 'path' is differs greatly from system to + * system anyway. * * @note Do not assume that this string contains (back)slashes or any * other kind of 'path separators'. @@ -222,7 +230,7 @@ public: * * @return pointer to the stream object, 0 in case of a failure */ - virtual Common::SeekableReadStream *openForReading(); + virtual Common::SeekableReadStream *openForReading() const; /** * Creates a WriteStream instance corresponding to the file @@ -231,9 +239,9 @@ public: * * @return pointer to the stream object, 0 in case of a failure */ - virtual Common::WriteStream *openForWriting(); + virtual Common::WriteStream *openForWriting() const; }; -//} // End of namespace Common +} // End of namespace Common #endif //COMMON_FS_H diff --git a/common/hash-str.h b/common/hash-str.h index f64b62daed..40557037e7 100644 --- a/common/hash-str.h +++ b/common/hash-str.h @@ -39,7 +39,7 @@ inline uint hashit_lower(const String &str) { return hashit_lower(str.c_str()); // FIXME: The following functors obviously are not consistently named struct CaseSensitiveString_EqualTo { - bool operator()(const String& x, const String& y) const { return strcmp(x.c_str(), y.c_str()) == 0; } + bool operator()(const String& x, const String& y) const { return x.equals(y); } }; struct CaseSensitiveString_Hash { @@ -48,7 +48,7 @@ struct CaseSensitiveString_Hash { struct IgnoreCase_EqualTo { - bool operator()(const String& x, const String& y) const { return scumm_stricmp(x.c_str(), y.c_str()) == 0; } + bool operator()(const String& x, const String& y) const { return x.equalsIgnoreCase(y); } }; struct IgnoreCase_Hash { diff --git a/common/hashmap.cpp b/common/hashmap.cpp index 4749234740..b8f2608901 100644 --- a/common/hashmap.cpp +++ b/common/hashmap.cpp @@ -24,70 +24,86 @@ */ // The hash map (associative array) implementation in this file is -// based on code by Andrew Y. Ng, 1996: - -/* - * Copyright (c) 1998-2003 Massachusetts Institute of Technology. - * This code was developed as part of the Haystack research project - * (http://haystack.lcs.mit.edu/). 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 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. - */ +// based on the PyDict implementation of CPython. The erase() method +// is based on example code in the Wikipedia article on Hash tables. #include "common/hashmap.h" namespace Common { -// const char *: +// Hash function for strings, taken from CPython. uint hashit(const char *p) { - uint hash = 0; + uint hash = *p << 7; byte c; - while ((c = *p++)) - hash = (hash * 31 + c); - return hash; + int size = 0; + while ((c = *p++)) { + hash = (1000003 * hash) ^ c; + size++; + } + return hash ^ size; } +// Like hashit, but converts every char to lowercase before hashing. uint hashit_lower(const char *p) { - uint hash = 0; + uint hash = tolower(*p) << 7; byte c; - while ((c = *p++)) - hash = (hash * 31 + tolower(c)); - return hash; + int size = 0; + while ((c = *p++)) { + hash = (1000003 * hash) ^ tolower(c); + size++; + } + return hash ^ size; } -// The following table is taken from the GNU ISO C++ Library's hashtable.h file. -static const uint primes[] = { - 53ul, 97ul, 193ul, 389ul, 769ul, - 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, - 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, - 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, - 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, - 1610612741ul, 3221225473ul, 4294967291ul -}; +#ifdef DEBUG_HASH_COLLISIONS +static double + g_collisions = 0, + g_lookups = 0, + g_collPerLook = 0, + g_capacity = 0, + g_size = 0; +static int g_max_capacity = 0, g_max_size = 0; +static int g_totalHashmaps = 0; +static int g_stats[4] = {0,0,0,0}; -uint nextTableSize(uint x) { - int i = 0; - while (x >= primes[i]) - i++; - return primes[i]; -} +void updateHashCollisionStats(int collisions, int lookups, int arrsize, int nele) { + g_collisions += collisions; + g_lookups += lookups; + if (lookups) + g_collPerLook += (double)collisions / (double)lookups; + g_capacity += arrsize; + g_size += nele; + g_totalHashmaps++; + + if (3*nele <= 2*8) + g_stats[0]++; + if (3*nele <= 2*16) + g_stats[1]++; + if (3*nele <= 2*32) + g_stats[2]++; + if (3*nele <= 2*64) + g_stats[3]++; + + g_max_capacity = MAX(g_max_capacity, arrsize); + g_max_size = MAX(g_max_size, nele); + fprintf(stdout, "%d hashmaps: colls %.1f; lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n", + g_totalHashmaps, + g_collisions / g_totalHashmaps, + g_lookups / g_totalHashmaps, + 100 * g_collPerLook / g_totalHashmaps, + g_size / g_totalHashmaps, g_max_size, + g_capacity / g_totalHashmaps, g_max_capacity); + fprintf(stdout, " %d less than %d; %d less than %d; %d less than %d; %d less than %d\n", + g_stats[0], 2*8/3, + g_stats[1],2*16/3, + g_stats[2],2*32/3, + g_stats[3],2*64/3); + + // TODO: + // * Should record the maximal size of the map during its lifetime, not that at its death + // * Should do some statistics: how many maps are less than 2/3*8, 2/3*16, 2/3*32, ... +} +#endif } // End of namespace Common diff --git a/common/hashmap.h b/common/hashmap.h index 69f367de97..81f5ee84b4 100644 --- a/common/hashmap.h +++ b/common/hashmap.h @@ -24,32 +24,8 @@ */ // The hash map (associative array) implementation in this file is -// based on code by Andrew Y. Ng, 1996: - -/* - * Copyright (c) 1998-2003 Massachusetts Institute of Technology. - * This code was developed as part of the Haystack research project - * (http://haystack.lcs.mit.edu/). 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 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. - */ +// based on the PyDict implementation of CPython. The erase() method +// is based on example code in the Wikipedia article on Hash tables. #ifndef COMMON_HASHMAP_H #define COMMON_HASHMAP_H @@ -74,11 +50,6 @@ namespace Common { -// The table sizes ideally are primes. We use a helper function to find -// suitable table sizes. -uint nextTableSize(uint x); - - // Enable the following #define if you want to check how many collisions the // code produces (many collisions indicate either a bad hash function, or a // hash table that is too small). @@ -113,9 +84,24 @@ public: Node(const Key &key) : _key(key), _value() {} }; + enum { + HASHMAP_PERTURB_SHIFT = 5, + HASHMAP_MIN_CAPACITY = 16, + + // The quotient of the next two constants controls how much the + // internal storage of the hashmap may fill up before being + // increased automatically. + // Note: the quotient of these two must be between and different + // from 0 and 1. + HASHMAP_LOADFACTOR_NUMERATOR = 2, + HASHMAP_LOADFACTOR_DENOMINATOR = 3, + + HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR + }; + #ifdef USE_HASHMAP_MEMORY_POOL - MemoryPool _nodePool; + FixedSizeMemoryPool<sizeof(Node), HASHMAP_MEMORYPOOL_SIZE> _nodePool; Node *allocNode(const Key &key) { void* mem = _nodePool.malloc(); @@ -136,8 +122,9 @@ public: } #endif - Node **_arr; // hashtable of size arrsize. - uint _arrsize, _nele; + Node **_storage; // hashtable of size arrsize. + uint _mask; /**< Capacity of the HashMap minus one; must be a power of two of minus one */ + uint _size; HashFunc _hash; EqualFunc _equal; @@ -152,7 +139,7 @@ public: void assign(const HM_t &map); int lookup(const Key &key) const; int lookupAndCreateIfMissing(const Key &key); - void expand_array(uint newsize); + void expandStorage(uint newCapacity); template<class T> friend class IteratorImpl; @@ -174,8 +161,8 @@ public: NodeType *deref() const { assert(_hashmap != 0); - assert(_idx < _hashmap->_arrsize); - Node *node = _hashmap->_arr[_idx]; + assert(_idx <= _hashmap->_mask); + Node *node = _hashmap->_storage[_idx]; assert(node != 0); return node; } @@ -195,8 +182,8 @@ public: assert(_hashmap); do { _idx++; - } while (_idx < _hashmap->_arrsize && _hashmap->_arr[_idx] == 0); - if (_idx >= _hashmap->_arrsize) + } while (_idx <= _hashmap->_mask && _hashmap->_storage[_idx] == 0); + if (_idx > _hashmap->_mask) _idx = (uint)-1; return *this; @@ -223,7 +210,7 @@ public: // Remove the previous content and ... clear(); - delete[] _arr; + delete[] _storage; // ... copy the new stuff. assign(map); return *this; @@ -242,12 +229,12 @@ public: void erase(const Key &key); - uint size() const { return _nele; } + uint size() const { return _size; } iterator begin() { // Find and return the _key non-empty entry - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr]) + for (uint ctr = 0; ctr <= _mask; ++ctr) { + if (_storage[ctr]) return iterator(ctr, this); } return end(); @@ -258,8 +245,8 @@ public: const_iterator begin() const { // Find and return the first non-empty entry - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr]) + for (uint ctr = 0; ctr <= _mask; ++ctr) { + if (_storage[ctr]) return const_iterator(ctr, this); } return end(); @@ -270,14 +257,14 @@ public: iterator find(const Key &key) { uint ctr = lookup(key); - if (_arr[ctr]) + if (_storage[ctr]) return iterator(ctr, this); return end(); } const_iterator find(const Key &key) const { uint ctr = lookup(key); - if (_arr[ctr]) + if (_storage[ctr]) return const_iterator(ctr, this); return end(); } @@ -285,7 +272,7 @@ public: // TODO: insert() method? bool empty() const { - return (_nele == 0); + return (_size == 0); } }; @@ -297,16 +284,13 @@ public: */ template<class Key, class Val, class HashFunc, class EqualFunc> HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() : -#ifdef USE_HASHMAP_MEMORY_POOL - _nodePool(sizeof(Node)), -#endif _defaultVal() { - _arrsize = nextTableSize(0); - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _mask = HASHMAP_MIN_CAPACITY - 1; + _storage = new Node *[HASHMAP_MIN_CAPACITY]; + assert(_storage != NULL); + memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *)); - _nele = 0; + _size = 0; #ifdef DEBUG_HASH_COLLISIONS _collisions = 0; @@ -321,9 +305,6 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap() : */ template<class Key, class Val, class HashFunc, class EqualFunc> HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) : -#ifdef USE_HASHMAP_MEMORY_POOL - _nodePool(sizeof(Node)), -#endif _defaultVal() { assign(map); } @@ -333,11 +314,15 @@ HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) : */ template<class Key, class Val, class HashFunc, class EqualFunc> HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() { - for (uint ctr = 0; ctr < _arrsize; ++ctr) - if (_arr[ctr] != NULL) - freeNode(_arr[ctr]); + for (uint ctr = 0; ctr <= _mask; ++ctr) + if (_storage[ctr] != NULL) + freeNode(_storage[ctr]); - delete[] _arr; + delete[] _storage; +#ifdef DEBUG_HASH_COLLISIONS + extern void updateHashCollisionStats(int, int, int, int); + updateHashCollisionStats(_collisions, _lookups, _mask+1, _size); +#endif } /** @@ -349,95 +334,102 @@ HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() { */ template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) { - _arrsize = map._arrsize; - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _mask = map._mask; + _storage = new Node *[_mask+1]; + assert(_storage != NULL); + memset(_storage, 0, (_mask+1) * sizeof(Node *)); // Simply clone the map given to us, one by one. - _nele = 0; - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (map._arr[ctr] != NULL) { - _arr[ctr] = allocNode(map._arr[ctr]->_key); - _arr[ctr]->_value = map._arr[ctr]->_value; - _nele++; + _size = 0; + for (uint ctr = 0; ctr <= _mask; ++ctr) { + if (map._storage[ctr] != NULL) { + _storage[ctr] = allocNode(map._storage[ctr]->_key); + _storage[ctr]->_value = map._storage[ctr]->_value; + _size++; } } // Perform a sanity check (to help track down hashmap corruption) - assert(_nele == map._nele); + assert(_size == map._size); } template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) { - for (uint ctr = 0; ctr < _arrsize; ++ctr) { - if (_arr[ctr] != NULL) { - freeNode(_arr[ctr]); - _arr[ctr] = NULL; + for (uint ctr = 0; ctr <= _mask; ++ctr) { + if (_storage[ctr] != NULL) { + freeNode(_storage[ctr]); + _storage[ctr] = NULL; } } - if (shrinkArray && _arrsize > nextTableSize(0)) { - delete[] _arr; +#ifdef USE_HASHMAP_MEMORY_POOL + _nodePool.freeUnusedPages(); +#endif + + if (shrinkArray && _mask >= HASHMAP_MIN_CAPACITY) { + delete[] _storage; - _arrsize = nextTableSize(0); - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _mask = HASHMAP_MIN_CAPACITY; + _storage = new Node *[HASHMAP_MIN_CAPACITY]; + assert(_storage != NULL); + memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *)); } - _nele = 0; + _size = 0; } template<class Key, class Val, class HashFunc, class EqualFunc> -void HashMap<Key, Val, HashFunc, EqualFunc>::expand_array(uint newsize) { - assert(newsize > _arrsize); - uint ctr, dex; +void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) { + assert(newCapacity > _mask+1); - const uint old_nele = _nele; - const uint old_arrsize = _arrsize; - Node **old_arr = _arr; + const uint old_size = _size; + const uint old_mask = _mask; + Node **old_storage = _storage; // allocate a new array - _nele = 0; - _arrsize = newsize; - _arr = new Node *[_arrsize]; - assert(_arr != NULL); - memset(_arr, 0, _arrsize * sizeof(Node *)); + _size = 0; + _mask = newCapacity - 1; + _storage = new Node *[newCapacity]; + assert(_storage != NULL); + memset(_storage, 0, newCapacity * sizeof(Node *)); // rehash all the old elements - for (ctr = 0; ctr < old_arrsize; ++ctr) { - if (old_arr[ctr] == NULL) + for (uint ctr = 0; ctr <= old_mask; ++ctr) { + if (old_storage[ctr] == NULL) continue; // Insert the element from the old table into the new table. // Since we know that no key exists twice in the old table, we // can do this slightly better than by calling lookup, since we // don't have to call _equal(). - dex = _hash(old_arr[ctr]->_key) % _arrsize; - while (_arr[dex] != NULL) { - dex = (dex + 1) % _arrsize; + const uint hash = _hash(old_storage[ctr]->_key); + uint idx = hash & _mask; + for (uint perturb = hash; _storage[idx] != NULL; perturb >>= HASHMAP_PERTURB_SHIFT) { + idx = (5 * idx + perturb + 1) & _mask; } - _arr[dex] = old_arr[ctr]; - _nele++; + _storage[idx] = old_storage[ctr]; + _size++; } // Perform a sanity check: Old number of elements should match the new one! // This check will fail if some previous operation corrupted this hashmap. - assert(_nele == old_nele); + assert(_size == old_size); - delete[] old_arr; + delete[] old_storage; return; } template<class Key, class Val, class HashFunc, class EqualFunc> int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const { - uint ctr = _hash(key) % _arrsize; + const uint hash = _hash(key); + uint ctr = hash & _mask; + for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { + if (_storage[ctr] == NULL || _equal(_storage[ctr]->_key, key)) + break; - while (_arr[ctr] != NULL && !_equal(_arr[ctr]->_key, key)) { - ctr = (ctr + 1) % _arrsize; + ctr = (5 * ctr + perturb + 1) & _mask; #ifdef DEBUG_HASH_COLLISIONS _collisions++; @@ -448,7 +440,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const { _lookups++; fprintf(stderr, "collisions %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n", _collisions, _lookups, ((double) _collisions / (double)_lookups), - (const void *)this, _arrsize, _nele); + (const void *)this, _mask+1, _size); #endif return ctr; @@ -458,13 +450,15 @@ template<class Key, class Val, class HashFunc, class EqualFunc> int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) { uint ctr = lookup(key); - if (_arr[ctr] == NULL) { - _arr[ctr] = allocNode(key); - _nele++; + if (_storage[ctr] == NULL) { + _storage[ctr] = allocNode(key); + _size++; - // Keep the load factor below 75%. - if (_nele > _arrsize * 75 / 100) { - expand_array(nextTableSize(_arrsize)); + // Keep the load factor below a certain threshold. + uint capacity = _mask + 1; + if (_size * HASHMAP_LOADFACTOR_DENOMINATOR > capacity * HASHMAP_LOADFACTOR_NUMERATOR) { + capacity = capacity < 500 ? (capacity * 4) : (capacity * 2); + expandStorage(capacity); ctr = lookup(key); } } @@ -476,7 +470,7 @@ int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key & template<class Key, class Val, class HashFunc, class EqualFunc> bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const { uint ctr = lookup(key); - return (_arr[ctr] != NULL); + return (_storage[ctr] != NULL); } template<class Key, class Val, class HashFunc, class EqualFunc> @@ -492,15 +486,15 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) co template<class Key, class Val, class HashFunc, class EqualFunc> Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) { uint ctr = lookupAndCreateIfMissing(key); - assert(_arr[ctr] != NULL); - return _arr[ctr]->_value; + assert(_storage[ctr] != NULL); + return _storage[ctr]->_value; } template<class Key, class Val, class HashFunc, class EqualFunc> const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const { uint ctr = lookup(key); - if (_arr[ctr] != NULL) - return _arr[ctr]->_value; + if (_storage[ctr] != NULL) + return _storage[ctr]->_value; else return _defaultVal; } @@ -508,38 +502,50 @@ const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) { uint ctr = lookupAndCreateIfMissing(key); - assert(_arr[ctr] != NULL); - _arr[ctr]->_value = val; + assert(_storage[ctr] != NULL); + _storage[ctr]->_value = val; } template<class Key, class Val, class HashFunc, class EqualFunc> void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) { // This is based on code in the Wikipedia article on Hash tables. - uint i = lookup(key); - if (_arr[i] == NULL) + + const uint hash = _hash(key); + uint i = hash & _mask; + uint perturb; + + for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { + if (_storage[i] == NULL || _equal(_storage[i]->_key, key)) + break; + + i = (5 * i + perturb + 1) & _mask; + } + + if (_storage[i] == NULL) return; // key wasn't present, so no work has to be done + // If we remove a key, we must check all subsequent keys and possibly // reinsert them. uint j = i; - freeNode(_arr[i]); - _arr[i] = NULL; - while (true) { + freeNode(_storage[i]); + _storage[i] = NULL; + for (perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) { // Look at the next table slot - j = (j + 1) % _arrsize; + j = (5 * j + perturb + 1) & _mask; // If the next slot is empty, we are done - if (_arr[j] == NULL) + if (_storage[j] == NULL) break; // Compute the slot where the content of the next slot should normally be, // assuming an empty table, and check whether we have to move it. - uint k = _hash(_arr[j]->_key) % _arrsize; + uint k = _hash(_storage[j]->_key) & _mask; if ((j > i && (k <= i || k > j)) || (j < i && (k <= i && k > j)) ) { - _arr[i] = _arr[j]; + _storage[i] = _storage[j]; i = j; } } - _arr[i] = NULL; - _nele--; + _storage[i] = NULL; + _size--; return; } diff --git a/common/iff_container.h b/common/iff_container.h index 9d477276fc..a70548abd4 100644 --- a/common/iff_container.h +++ b/common/iff_container.h @@ -162,7 +162,7 @@ public: void incBytesRead(uint32 inc) { bytesRead += inc; if (bytesRead > size) { - error("Chunk overead"); + error("Chunk overread"); } } @@ -172,19 +172,23 @@ public: bytesRead = 0; } + bool hasReadAll() const { + return (size - bytesRead) == 0; + } + void feed() { if (size % 2) { size++; } - while (!_input->eos() && !eos()) { + while (!hasReadAll()) { readByte(); } } // Common::ReadStream implementation - bool eos() const { - return (size - bytesRead) == 0; - } + bool eos() const { return _input->eos(); } + bool err() const { return _input->err(); } + void clearErr() { _input->clearErr(); } uint32 read(void *dataPtr, uint32 dataSize) { incBytesRead(dataSize); @@ -209,7 +213,7 @@ public: _chunk.feed(); _formChunk.incBytesRead(_chunk.size); - if (_formChunk.eos()) + if (_formChunk.hasReadAll()) return 0; _formChunk.incBytesRead(8); diff --git a/common/keyboard.h b/common/keyboard.h index 93579cbed6..9b6558dbff 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -182,7 +182,7 @@ enum KeyCode { }; /** - * List of certan special and some fake 'ascii' values used in keyboard events. + * List of certain special and some fake 'ascii' values used in keyboard events. * The values for the function keys listed here are based on what certain SCUMM * games expect in their scripts. * @todo Get rid of the function key values, and instead enforce that engines use diff --git a/common/list.h b/common/list.h index c4e7b47644..0372d217b7 100644 --- a/common/list.h +++ b/common/list.h @@ -209,6 +209,11 @@ public: ++i; } + void pop_front() { + iterator i = begin(); + i = erase(i); + } + List<t_T> &operator=(const List<t_T> &list) { if (this != &list) { diff --git a/common/md5.cpp b/common/md5.cpp index edce9d8e4e..4eeb3d9a39 100644 --- a/common/md5.cpp +++ b/common/md5.cpp @@ -29,6 +29,7 @@ */ #include "common/file.h" +#include "common/fs.h" #include "common/md5.h" #include "common/util.h" #include "common/endian.h" @@ -256,8 +257,16 @@ bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length) { warning("md5_file: using a directory FilesystemNode"); return false; } + + ReadStream *stream = file.openForReading(); + if (!stream) { + warning("md5_file: failed to open '%s'", file.getPath().c_str()); + return false; + } - return md5_file(file.getPath().c_str(), digest, length); + bool result = md5_file(*stream, digest, length); + delete stream; + return result; } bool md5_file(const char *name, uint8 digest[16], uint32 length) { diff --git a/common/md5.h b/common/md5.h index e7879dc6df..a8642b1322 100644 --- a/common/md5.h +++ b/common/md5.h @@ -26,11 +26,12 @@ #define COMMON_MD5_H #include "common/scummsys.h" -#include "common/fs.h" -#include "common/stream.h" namespace Common { +class FilesystemNode; +class ReadStream; + bool md5_file(const char *name, uint8 digest[16], uint32 length = 0); bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length = 0); bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length = 0); diff --git a/common/memorypool.cpp b/common/memorypool.cpp index f3dfb7975f..12307ba5d6 100644 --- a/common/memorypool.cpp +++ b/common/memorypool.cpp @@ -28,22 +28,6 @@ namespace Common { -static const size_t CHUNK_PAGE_SIZE = 32; - -void* MemoryPool::allocPage() { - void* result = ::malloc(CHUNK_PAGE_SIZE * _chunkSize); - _pages.push_back(result); - void* current = result; - for (size_t i = 1; i < CHUNK_PAGE_SIZE; ++i) { - void* next = ((char*)current + _chunkSize); - *(void**)current = next; - - current = next; - } - *(void**)current = NULL; - return result; -} - MemoryPool::MemoryPool(size_t chunkSize) { // You must at least fit the pointer in the node (technically unneeded considering the next rounding statement) _chunkSize = MAX(chunkSize, sizeof(void*)); @@ -52,38 +36,68 @@ MemoryPool::MemoryPool(size_t chunkSize) { _chunkSize = (_chunkSize + sizeof(void*) - 1) & (~(sizeof(void*) - 1)); _next = NULL; + + _chunksPerPage = 8; } MemoryPool::~MemoryPool() { - for (size_t i = 0; i<_pages.size(); ++i) - ::free(_pages[i]); + for (size_t i = 0; i < _pages.size(); ++i) + ::free(_pages[i].start); +} + +void MemoryPool::allocPage() { + Page page; + + // Allocate a new page + page.numChunks = _chunksPerPage; + page.start = ::malloc(page.numChunks * _chunkSize); + assert(page.start); + _pages.push_back(page); + + // Next time, we'll alocate a page twice as big as this one. + _chunksPerPage *= 2; + + // Add the page to the pool of free chunk + addPageToPool(page); +} + +void MemoryPool::addPageToPool(const Page &page) { + + // Add all chunks of the new page to the linked list (pool) of free chunks + void *current = page.start; + for (size_t i = 1; i < page.numChunks; ++i) { + void *next = ((char*)current + _chunkSize); + *(void **)current = next; + + current = next; + } + + // Last chunk points to the old _next + *(void**)current = _next; + + // From now on, the first free chunk is the first chunk of the new page + _next = page.start; } -void* MemoryPool::malloc() { -#if 1 - if (!_next) - _next = allocPage(); +void *MemoryPool::malloc() { + if (!_next) // No free chunks left? Allocate a new page + allocPage(); - void* result = _next; + assert(_next); + void *result = _next; _next = *(void**)result; return result; -#else - return ::malloc(_chunkSize); -#endif } void MemoryPool::free(void* ptr) { -#if 1 + // Add the chunk back to (the start of) the list of free chunks *(void**)ptr = _next; _next = ptr; -#else - ::free(ptr); -#endif } // Technically not compliant C++ to compare unrelated pointers. In practice... -bool MemoryPool::isPointerInPage(void* ptr, void* page) { - return (ptr >= page) && (ptr < (char*)page + CHUNK_PAGE_SIZE * _chunkSize); +bool MemoryPool::isPointerInPage(void *ptr, const Page &page) { + return (ptr >= page.start) && (ptr < (char*)page.start + page.numChunks * _chunkSize); } void MemoryPool::freeUnusedPages() { @@ -94,9 +108,10 @@ void MemoryPool::freeUnusedPages() { numberOfFreeChunksPerPage[i] = 0; } - void* iterator = _next; + // Compute for each page how many chunks in it are still in use. + void *iterator = _next; while (iterator) { - // This should be a binary search + // TODO: This should be a binary search (requiring us to keep _pages sorted) for (size_t i = 0; i < _pages.size(); ++i) { if (isPointerInPage(iterator, _pages[i])) { ++numberOfFreeChunksPerPage[i]; @@ -106,12 +121,32 @@ void MemoryPool::freeUnusedPages() { iterator = *(void**)iterator; } + // Free all pages which are not in use. + // TODO: Might want to reset _chunksPerPage here (e.g. to the largest + // _pages[i].numChunks value still in use). size_t freedPagesCount = 0; - for (size_t i = 0; i < _pages.size(); ++i) { - if (numberOfFreeChunksPerPage[i] == CHUNK_PAGE_SIZE) { - ::free(_pages[i]); - _pages[i] = NULL; // TODO : Remove NULL values + for (size_t i = 0; i < _pages.size(); ++i) { + if (numberOfFreeChunksPerPage[i] == _pages[i].numChunks) { + // Remove all chunks of this page from the list of free chunks + void **iter2 = &_next; + while (*iter2) { + if (isPointerInPage(*iter2, _pages[i])) + *iter2 = **(void***)iter2; + else + iter2 = *(void***)iter2; + } + ::free(_pages[i].start); ++freedPagesCount; + _pages[i].start = NULL; + } + } + + for (size_t i = 0; i < _pages.size(); ) { + if (_pages[i].start == NULL) { + _pages.remove_at(i); + // We just removed an entry, so we do not advance "i" + } else { + ++i; } } diff --git a/common/memorypool.h b/common/memorypool.h index fcbacabc5c..dd2e8f13a4 100644 --- a/common/memorypool.h +++ b/common/memorypool.h @@ -32,26 +32,57 @@ namespace Common { class MemoryPool { -private: +protected: MemoryPool(const MemoryPool&); MemoryPool& operator=(const MemoryPool&); + + struct Page { + void *start; + size_t numChunks; + }; size_t _chunkSize; - Array<void*> _pages; - void* _next; + Array<Page> _pages; + void *_next; + size_t _chunksPerPage; + + void allocPage(); + void addPageToPool(const Page &page); + bool isPointerInPage(void *ptr, const Page &page); - void* allocPage(); - bool isPointerInPage(void* ptr, void* page); public: MemoryPool(size_t chunkSize); ~MemoryPool(); - void* malloc(); - void free(void* ptr); + void *malloc(); + void free(void *ptr); void freeUnusedPages(); }; +template<size_t CHUNK_SIZE, size_t NUM_INTERNAL_CHUNKS = 32> +class FixedSizeMemoryPool : public MemoryPool { +private: + enum { + REAL_CHUNK_SIZE = (CHUNK_SIZE + sizeof(void*) - 1) & (~(sizeof(void*) - 1)) + }; + + byte _storage[NUM_INTERNAL_CHUNKS * REAL_CHUNK_SIZE]; +public: + FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) { + assert(REAL_CHUNK_SIZE == _chunkSize); + // Insert some static storage + Page internalPage = { _storage, NUM_INTERNAL_CHUNKS }; + addPageToPool(internalPage); + } +}; + +template<size_t CHUNK_SIZE> +class FixedSizeMemoryPool<CHUNK_SIZE,0> : public MemoryPool { +public: + FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {} +}; + } // End of namespace Common #endif diff --git a/common/module.mk b/common/module.mk index ed15bf75ea..e04af5270b 100644 --- a/common/module.mk +++ b/common/module.mk @@ -2,6 +2,7 @@ MODULE := common MODULE_OBJS := \ advancedDetector.o \ + archive.o \ config-file.o \ config-manager.o \ file.o \ diff --git a/common/ptr.h b/common/ptr.h index c6fcaa4f75..99bc82a2d3 100644 --- a/common/ptr.h +++ b/common/ptr.h @@ -218,8 +218,4 @@ bool operator!=(const Common::SharedPtr<T1> &l, const Common::SharedPtr<T2> &r) return l.get() != r.get(); } - #endif - - - diff --git a/common/queue.h b/common/queue.h new file mode 100644 index 0000000000..f1881345e8 --- /dev/null +++ b/common/queue.h @@ -0,0 +1,94 @@ +/* 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. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2008-rtl/common/stack.h $ + * $Id$ + */ + +#ifndef COMMON_QUEUE_H +#define COMMON_QUEUE_H + +#include "common/scummsys.h" +#include "common/list.h" + +namespace Common { + +/** + * Variable size Queue class, implemented using our List class. + */ +template<class T> +class Queue { +public: + typedef T value_type; + +public: + Queue<T>() : _impl() {} + Queue<T>(const Queue<T> &queue) : _impl(queue._impl) {} + + Queue<T> &operator=(const Queue<T> &queue) { + _impl = queue._impl; + return *this; + } + + bool empty() const { + return _impl.empty(); + } + + void clear() { + _impl.clear(); + } + + void push(const T &x) { + _impl.push_back(x); + } + + T &front() { + return *_impl.begin(); + } + + const T &front() const { + return *_impl.begin(); + } + + T &back() { + return *_impl.reverse_begin(); + } + + const T &back() const { + return *_impl.reverse_begin(); + } + + T pop() { + T tmp = front(); + _impl.pop_front(); + return tmp; + } + + int size() const { + return _impl.size(); + } + +private: + List<T> _impl; +}; + +} // End of namespace Common + +#endif diff --git a/common/str.cpp b/common/str.cpp index 5f8d4ffb7e..a415e376c9 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -34,28 +34,24 @@ const String String::emptyString; const char *String::emptyString = ""; #endif -static int computeCapacity(int len) { - // By default, for the capacity we use the nearest multiple of 32 - // that leaves at least 16 chars of extra space (in case the string - // grows a bit). - // Finally, we subtract 1 to compensate for the trailing zero byte. - len += 16; - return ((len + 32 - 1) & ~0x1F) - 1; +static uint32 computeCapacity(uint32 len) { + // By default, for the capacity we use the next multiple of 32 + return ((len + 32 - 1) & ~0x1F); } -String::String(const char *str) : _len(0), _str(_storage) { +String::String(const char *str) : _size(0), _str(_storage) { if (str == 0) { _storage[0] = 0; - _len = 0; + _size = 0; } else initWithCStr(str, strlen(str)); } -String::String(const char *str, uint32 len) : _len(0), _str(_storage) { +String::String(const char *str, uint32 len) : _size(0), _str(_storage) { initWithCStr(str, len); } -String::String(const char *beginP, const char *endP) : _len(0), _str(_storage) { +String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) { assert(endP >= beginP); initWithCStr(beginP, endP - beginP); } @@ -67,13 +63,13 @@ void String::initWithCStr(const char *str, uint32 len) { // for GCC 2.95.x compatibility (see also tracker item #1602879). _storage[0] = 0; - _len = len; + _size = len; if (len >= _builtinCapacity) { // Not enough internal storage, so allocate more - _extern._capacity = computeCapacity(len); + _extern._capacity = computeCapacity(len+1); _extern._refCount = 0; - _str = (char *)malloc(_extern._capacity+1); + _str = (char *)malloc(_extern._capacity); assert(_str != 0); } @@ -83,10 +79,10 @@ void String::initWithCStr(const char *str, uint32 len) { } String::String(const String &str) - : _len(str._len), _str(str.isStorageIntern() ? _storage : str._str) { + : _size(str._size), _str(str.isStorageIntern() ? _storage : str._str) { if (str.isStorageIntern()) { // String in internal storage: just copy it - memcpy(_storage, str._storage, _builtinCapacity); + memcpy(_storage, str._storage, sizeof(_storage)); } else { // String in external storage: use refcount mechanism str.incRefCount(); @@ -97,14 +93,14 @@ String::String(const String &str) } String::String(char c) -: _len(0), _str(_storage) { +: _size(0), _str(_storage) { _storage[0] = c; _storage[1] = 0; // TODO/FIXME: There is no reason for the following check -- we *do* // allow strings to contain 0 bytes! - _len = (c == 0) ? 0 : 1; + _size = (c == 0) ? 0 : 1; } String::~String() { @@ -112,16 +108,16 @@ String::~String() { } void String::makeUnique() { - ensureCapacity(_len, true); + ensureCapacity(_size, true); } /** - * Ensure that enough storage is available to store at least new_len + * Ensure that enough storage is available to store at least new_size * characters plus a null byte. In addition, if we currently share * the storage with another string, unshare it, so that we can safely * write to the storage. */ -void String::ensureCapacity(uint32 new_len, bool keep_old) { +void String::ensureCapacity(uint32 new_size, bool keep_old) { bool isShared; uint32 curCapacity, newCapacity; char *newStorage; @@ -129,7 +125,7 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) { if (isStorageIntern()) { isShared = false; - curCapacity = _builtinCapacity - 1; + curCapacity = _builtinCapacity; } else { isShared = (oldRefCount && *oldRefCount > 1); curCapacity = _extern._capacity; @@ -137,30 +133,30 @@ void String::ensureCapacity(uint32 new_len, bool keep_old) { // Special case: If there is enough space, and we do not share // the storage, then there is nothing to do. - if (!isShared && new_len <= curCapacity) + if (!isShared && new_size < curCapacity) return; - if (isShared && new_len <= _builtinCapacity - 1) { + if (isShared && new_size < _builtinCapacity) { // We share the storage, but there is enough internal storage: Use that. newStorage = _storage; - newCapacity = _builtinCapacity - 1; + newCapacity = _builtinCapacity; } else { // We need to allocate storage on the heap! // Compute a suitable new capacity limit - newCapacity = computeCapacity(new_len); + newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1)); // Allocate new storage - newStorage = (char *)malloc(newCapacity+1); + newStorage = (char *)malloc(newCapacity); assert(newStorage); } // Copy old data if needed, elsewise reset the new storage. if (keep_old) { - assert(_len <= newCapacity); - memcpy(newStorage, _str, _len + 1); + assert(_size < newCapacity); + memcpy(newStorage, _str, _size + 1); } else { - _len = 0; + _size = 0; newStorage[0] = 0; } @@ -210,7 +206,7 @@ void String::decRefCount(int *oldRefCount) { String& String::operator =(const char *str) { uint32 len = strlen(str); ensureCapacity(len, false); - _len = len; + _size = len; memmove(_str, str, len + 1); return *this; } @@ -221,16 +217,16 @@ String &String::operator =(const String &str) { if (str.isStorageIntern()) { decRefCount(_extern._refCount); - _len = str._len; + _size = str._size; _str = _storage; - memcpy(_str, str._str, _len + 1); + memcpy(_str, str._str, _size + 1); } else { str.incRefCount(); decRefCount(_extern._refCount); _extern._refCount = str._extern._refCount; _extern._capacity = str._extern._capacity; - _len = str._len; + _size = str._size; _str = str._str; } @@ -240,7 +236,7 @@ String &String::operator =(const String &str) { String& String::operator =(char c) { decRefCount(_extern._refCount); _str = _storage; - _len = 1; + _size = 1; _str[0] = c; _str[1] = 0; return *this; @@ -249,30 +245,30 @@ String& String::operator =(char c) { String &String::operator +=(const char *str) { int len = strlen(str); if (len > 0) { - ensureCapacity(_len + len, true); + ensureCapacity(_size + len, true); - memcpy(_str + _len, str, len + 1); - _len += len; + memcpy(_str + _size, str, len + 1); + _size += len; } return *this; } String &String::operator +=(const String &str) { - int len = str._len; + int len = str._size; if (len > 0) { - ensureCapacity(_len + len, true); + ensureCapacity(_size + len, true); - memcpy(_str + _len, str._str, len + 1); - _len += len; + memcpy(_str + _size, str._str, len + 1); + _size += len; } return *this; } String &String::operator +=(char c) { - ensureCapacity(_len + 1, true); + ensureCapacity(_size + 1, true); - _str[_len++] = c; - _str[_len] = 0; + _str[_size++] = c; + _str[_size] = 0; return *this; } @@ -293,10 +289,10 @@ bool String::hasPrefix(const char *x) const { bool String::hasSuffix(const char *x) const { assert(x != 0); // Compare x with the end of _str. - const uint32 x_len = strlen(x); - if (x_len > _len) + const uint32 x_size = strlen(x); + if (x_size > _size) return false; - const char *y = c_str() + _len - x_len; + const char *y = c_str() + _size - x_size; while (*x && *x == *y) { ++x; ++y; @@ -315,66 +311,74 @@ bool String::contains(char x) const { return strchr(c_str(), x) != NULL; } +bool String::matchString(const char *pat) const { + return Common::matchString(c_str(), pat); +} + +bool String::matchString(const String &pat) const { + return Common::matchString(c_str(), pat.c_str()); +} + void String::deleteLastChar() { - deleteChar(_len - 1); + deleteChar(_size - 1); } void String::deleteChar(uint32 p) { - assert(p < _len); + assert(p < _size); makeUnique(); - while (p++ < _len) + while (p++ < _size) _str[p-1] = _str[p]; - _len--; + _size--; } void String::clear() { decRefCount(_extern._refCount); - _len = 0; + _size = 0; _str = _storage; _storage[0] = 0; } void String::setChar(char c, uint32 p) { - assert(p <= _len); + assert(p <= _size); makeUnique(); _str[p] = c; } void String::insertChar(char c, uint32 p) { - assert(p <= _len); + assert(p <= _size); - ensureCapacity(_len + 1, true); - _len++; - for (uint32 i = _len; i > p; --i) + ensureCapacity(_size + 1, true); + _size++; + for (uint32 i = _size; i > p; --i) _str[i] = _str[i-1]; _str[p] = c; } void String::toLowercase() { makeUnique(); - for (uint32 i = 0; i < _len; ++i) + for (uint32 i = 0; i < _size; ++i) _str[i] = tolower(_str[i]); } void String::toUppercase() { makeUnique(); - for (uint32 i = 0; i < _len; ++i) + for (uint32 i = 0; i < _size; ++i) _str[i] = toupper(_str[i]); } void String::trim() { - if (_len == 0) + if (_size == 0) return; makeUnique(); // Trim trailing whitespace - while (_len >= 1 && isspace(_str[_len-1])) - _len--; - _str[_len] = 0; + while (_size >= 1 && isspace(_str[_size-1])) + _size--; + _str[_size] = 0; // Trim leading whitespace char *t = _str; @@ -382,8 +386,8 @@ void String::trim() { t++; if (t != _str) { - _len -= t - _str; - memmove(_str, t, _len + 1); + _size -= t - _str; + memmove(_str, t, _size + 1); } } @@ -524,4 +528,112 @@ char *trim(char *t) { return rtrim(ltrim(t)); } +Common::String lastPathComponent(const Common::String &path, const char sep) { + const char *str = path.c_str(); + const char *last = str + path.size(); + + // Skip over trailing slashes + while (last > str && *(last-1) == sep) + --last; + + // Path consisted of only slashes -> return empty string + if (last == str) + return Common::String(); + + // Now scan the whole component + const char *first = last - 1; + while (first >= str && *first != sep) + --first; + + if (*first == sep) + first++; + + return Common::String(first, last); +} + +Common::String normalizePath(const Common::String &path, const char sep) { + if (path.empty()) + return path; + + const char *cur = path.c_str(); + Common::String result; + + // If there is a leading slash, preserve that: + if (*cur == sep) { + result += sep; + while (*cur == sep) + ++cur; + } + + // Scan till the end of the String + while (*cur != 0) { + const char *start = cur; + + // Scan till the next path separator resp. the end of the string + while (*cur != sep && *cur != 0) + cur++; + + const Common::String component(start, cur); + + // Skip empty components and dot components, add all others + if (!component.empty() && component != ".") { + // Add a separator before the component, unless the result + // string already ends with one (which happens only if the + // path *starts* with a separator). + if (!result.empty() && result.lastChar() != sep) + result += sep; + + // Add the component + result += component; + } + + // Skip over separator chars + while (*cur == sep) + cur++; + } + + return result; +} + +bool matchString(const char *str, const char *pat) { + assert(str); + assert(pat); + + const char *p = 0; + const char *q = 0; + + for (;;) { + switch (*pat) { + case '*': + // Record pattern / string possition for backtracking + p = ++pat; + q = str; + // If pattern ended with * -> match + if (!*pat) + return true; + break; + + default: + if (*pat != *str) { + if (p) { + // No match, oops -> try to backtrack + pat = p; + str = ++q; + if (!*str) + return !*pat; + break; + } + else + return false; + } + // fallthrough + case '?': + if (!*str) + return !*pat; + pat++; + str++; + } + } +} + } // End of namespace Common diff --git a/common/str.h b/common/str.h index 3479fee8e4..20914c1f1f 100644 --- a/common/str.h +++ b/common/str.h @@ -61,7 +61,7 @@ protected: * a lot. Yes, we limit ourselves to strings shorter than 4GB -- * on purpose :-). */ - uint32 _len; + uint32 _size; /** * Pointer to the actual string storage. Either points to _storage, @@ -97,7 +97,7 @@ public: #endif /** Construct a new empty string. */ - String() : _len(0), _str(_storage) { _storage[0] = 0; } + String() : _size(0), _str(_storage) { _storage[0] = 0; } /** Construct a new string from the given NULL-terminated C string. */ String(const char *str); @@ -149,14 +149,38 @@ public: bool contains(const char *x) const; bool contains(char x) const; + /** + * Simple DOS-style pattern matching function (understands * and ? like used in DOS). + * Taken from exult/files/listfiles.cc + * + * Token meaning: + * "*": any character, any amount of times. + * "?": any character, only once. + * + * Example strings/patterns: + * String: monkey.s01 Pattern: monkey.s?? => true + * String: monkey.s101 Pattern: monkey.s?? => false + * String: monkey.s99 Pattern: monkey.s?1 => false + * String: monkey.s101 Pattern: monkey.s* => true + * String: monkey.s99 Pattern: monkey.s*1 => false + * + * @param str Text to be matched against the given pattern. + * @param pat Glob pattern. + * + * @return true if str matches the pattern, false otherwise. + */ + bool matchString(const char *pat) const; + bool matchString(const String &pat) const; + + inline const char *c_str() const { return _str; } - inline uint size() const { return _len; } + inline uint size() const { return _size; } - inline bool empty() const { return (_len == 0); } - char lastChar() const { return (_len > 0) ? _str[_len-1] : 0; } + inline bool empty() const { return (_size == 0); } + char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; } char operator [](int idx) const { - assert(_str && idx >= 0 && idx < (int)_len); + assert(_str && idx >= 0 && idx < (int)_size); return _str[idx]; } @@ -172,11 +196,19 @@ public: /** Set character c at position p. */ void insertChar(char c, uint32 p); + /** Clears the string, making it empty. */ void clear(); + /** Convert all characters in the string to lowercase. */ void toLowercase(); + + /** Convert all characters in the string to uppercase. */ void toUppercase(); + /** + * Removes trailing and leading whitespaces. Uses isspace() to decide + * what is whitespace and what not. + */ void trim(); uint hash() const; @@ -203,7 +235,7 @@ public: protected: void makeUnique(); - void ensureCapacity(uint32 new_len, bool keep_old); + void ensureCapacity(uint32 new_size, bool keep_old); void incRefCount() const; void decRefCount(int *oldRefCount); void initWithCStr(const char *str, uint32 len); @@ -218,7 +250,7 @@ String operator +(const String &x, const char *y); String operator +(const String &x, char y); String operator +(char x, const String &y); -// Some useful additional comparision operators for Strings +// Some useful additional comparison operators for Strings bool operator == (const char *x, const String &y); bool operator != (const char *x, const String &y); @@ -227,16 +259,67 @@ extern char *ltrim(char *t); extern char *rtrim(char *t); extern char *trim(char *t); + +/** + * Returns the last component of a given path. + * + * Examples: + * /foo/bar.txt would return 'bar.txt' + * /foo/bar/ would return 'bar' + * /foo/./bar// would return 'bar' + * + * @param path the path of which we want to know the last component + * @param sep character used to separate path components + * @return The last component of the path. + */ +Common::String lastPathComponent(const Common::String &path, const char sep); + +/** + * Normalize a gien path to a canonical form. In particular: + * - trailing separators are removed: /foo/bar/ -> /foo/bar + * - double separators (= empty components) are removed: /foo//bar -> /foo/bar + * - dot components are removed: /foo/./bar -> /foo/bar + * + * @todo remove double dot components: /foo/baz/../bar -> /foo/bar + * + * @param path the path to normalize + * @param sep the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff) + * @return the normalized path + */ +Common::String normalizePath(const Common::String &path, const char sep); + + +/** + * Simple DOS-style pattern matching function (understands * and ? like used in DOS). + * Taken from exult/files/listfiles.cc + * + * Token meaning: + * "*": any character, any amount of times. + * "?": any character, only once. + * + * Example strings/patterns: + * String: monkey.s01 Pattern: monkey.s?? => true + * String: monkey.s101 Pattern: monkey.s?? => false + * String: monkey.s99 Pattern: monkey.s?1 => false + * String: monkey.s101 Pattern: monkey.s* => true + * String: monkey.s99 Pattern: monkey.s*1 => false + * + * @param str Text to be matched against the given pattern. + * @param pat Glob pattern. + * + * @return true if str matches the pattern, false otherwise. + */ +bool matchString(const char *str, const char *pat); + + class StringList : public Array<String> { public: void push_back(const char *str) { - ensureCapacity(_size + 1); - _data[_size++] = str; + Array<String>::push_back(str); } void push_back(const String &str) { - ensureCapacity(_size + 1); - _data[_size++] = str; + Array<String>::push_back(str); } }; diff --git a/common/stream.cpp b/common/stream.cpp index e06cc28415..9bcc29550f 100644 --- a/common/stream.cpp +++ b/common/stream.cpp @@ -43,8 +43,10 @@ MemoryReadStream *ReadStream::readStream(uint32 dataSize) { uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) { // Read at most as many bytes as are still available... - if (dataSize > _size - _pos) + if (dataSize > _size - _pos) { dataSize = _size - _pos; + _eos = true; + } memcpy(dataPtr, _ptr, dataSize); if (_encbyte) { @@ -60,7 +62,7 @@ uint32 MemoryReadStream::read(void *dataPtr, uint32 dataSize) { return dataSize; } -void MemoryReadStream::seek(int32 offs, int whence) { +bool MemoryReadStream::seek(int32 offs, int whence) { // Pre-Condition assert(_pos <= _size); switch (whence) { @@ -81,12 +83,16 @@ void MemoryReadStream::seek(int32 offs, int whence) { } // Post-Condition assert(_pos <= _size); + + // Reset end-of-stream flag on a successful seek + _eos = false; + return true; // FIXME: STREAM REWRITE } #define LF 0x0A #define CR 0x0D -char *SeekableReadStream::readLine(char *buf, size_t bufSize) { +char *SeekableReadStream::readLine_OLD(char *buf, size_t bufSize) { assert(buf && bufSize > 0); char *p = buf; size_t len = 0; @@ -156,19 +162,27 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { // If end-of-file occurs before any characters are read, return NULL // and the buffer contents remain unchanged. - if (eos() || ioFailed()) { + if (eos() || err()) { return 0; } - // Loop as long as the stream has not ended, there is still free - // space in the buffer, and the line has not ended - while (!eos() && len + 1 < bufSize && c != LF) { + // Loop as long as there is still free space in the buffer, + // and the line has not ended + while (len + 1 < bufSize && c != LF) { c = readByte(); - - // If end-of-file occurs before any characters are read, return - // NULL and the buffer contents remain unchanged. If an error - /// occurs, return NULL and the buffer contents are indeterminate. - if (ioFailed() || (len == 0 && eos())) + + if (eos()) { + // If end-of-file occurs before any characters are read, return + // NULL and the buffer contents remain unchanged. + if (len == 0) + return 0; + + break; + } + + // If an error occurs, return NULL and the buffer contents + // are indeterminate. + if (err()) return 0; // Check for CR or CR/LF @@ -178,8 +192,18 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { if (c == CR) { // Look at the next char -- is it LF? If not, seek back c = readByte(); - if (c != LF && !eos()) + + if (err()) { + return 0; // error: the buffer contents are indeterminate + } + if (eos()) { + // The CR was the last character in the file. + // Reset the eos() flag since we successfully finished a line + clearErr(); + } else if (c != LF) { seek(-1, SEEK_CUR); + } + // Treat CR & CR/LF as plain LF c = LF; } @@ -188,25 +212,37 @@ char *SeekableReadStream::readLine_NEW(char *buf, size_t bufSize) { len++; } - // FIXME: - // This should fix a bug while using readLine with Common::File - // it seems that it sets the eos flag after an invalid read - // and at the same time the ioFailed flag - // the config file parser fails out of that reason for the new themes - if (eos()) { - clearIOFailed(); - } - // We always terminate the buffer if no error occured *p = 0; return buf; } +String SeekableReadStream::readLine() { + // Read a line + String line; + while (line.lastChar() != '\n') { + char buf[256]; + if (!readLine_NEW(buf, 256)) + break; + line += buf; + } + + if (line.lastChar() == '\n') + line.deleteLastChar(); + + return line; +} + + uint32 SubReadStream::read(void *dataPtr, uint32 dataSize) { - dataSize = MIN(dataSize, _end - _pos); + if (dataSize > _end - _pos) { + dataSize = _end - _pos; + _eos = true; + } dataSize = _parentStream->read(dataPtr, dataSize); + _eos |= _parentStream->eos(); _pos += dataSize; return dataSize; @@ -219,9 +255,10 @@ SeekableSubReadStream::SeekableSubReadStream(SeekableReadStream *parentStream, u assert(_begin <= _end); _pos = _begin; _parentStream->seek(_pos); + _eos = false; } -void SeekableSubReadStream::seek(int32 offset, int whence) { +bool SeekableSubReadStream::seek(int32 offset, int whence) { assert(_pos >= _begin); assert(_pos <= _end); @@ -239,7 +276,10 @@ void SeekableSubReadStream::seek(int32 offset, int whence) { assert(_pos >= _begin); assert(_pos <= _end); - _parentStream->seek(_pos); + bool ret = _parentStream->seek(_pos); + if (ret) _eos = false; // reset eos on successful seek + + return ret; } BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize, bool disposeParentStream) @@ -304,7 +344,7 @@ BufferedSeekableReadStream::BufferedSeekableReadStream(SeekableReadStream *paren _parentStream(parentStream) { } -void BufferedSeekableReadStream::seek(int32 offset, int whence) { +bool BufferedSeekableReadStream::seek(int32 offset, int whence) { // If it is a "local" seek, we may get away with "seeking" around // in the buffer only. // Note: We could try to handle SEEK_END and SEEK_SET, too, but @@ -319,6 +359,8 @@ void BufferedSeekableReadStream::seek(int32 offset, int whence) { _pos = _bufSize; _parentStream->seek(offset, whence); } + + return true; // FIXME: STREAM REWRITE } } // End of namespace Common diff --git a/common/stream.h b/common/stream.h index 01a946e685..02677e0dbb 100644 --- a/common/stream.h +++ b/common/stream.h @@ -41,19 +41,30 @@ public: virtual ~Stream() {} /** - * Returns true if any I/O failure occurred. - * This flag is never cleared automatically. In order to clear it, - * client code has to call clearIOFailed() explicitly. - * - * @todo Instead of returning a plain bool, maybe we should define - * a list of error codes which can be returned here. + * DEPRECATED: Use err() or eos() instead. + * Returns true if any I/O failure occurred or the end of the + * stream was reached while reading. */ - virtual bool ioFailed() const { return false; } + virtual bool ioFailed() const { return err(); } /** + * DEPRECATED: Don't use this unless you are still using ioFailed(). * Reset the I/O error status. */ - virtual void clearIOFailed() {} + virtual void clearIOFailed() { clearErr(); } + + /** + * Returns true if an I/O failure occurred. + * This flag is never cleared automatically. In order to clear it, + * client code has to call clearErr() explicitly. + */ + virtual bool err() const { return false; } + + /** + * Reset the I/O error status as returned by err(). + * For a ReadStream, also reset the end-of-stream status returned by eos(). + */ + virtual void clearErr() {} }; /** @@ -75,8 +86,10 @@ public: * Commit any buffered data to the underlying channel or * storage medium; unbuffered streams can use the default * implementation. + * + * @return true on success, false in case of a failure */ - virtual void flush() {} + virtual bool flush() { return true; } /** * Finalize and close this stream. To be called right before this @@ -85,7 +98,7 @@ public: * closing (and this flushing, if buffered) the stream. * * After this method has been called, no further writes may be - * peformed on the stream. Calling ioFailed() is allowed. + * performed on the stream. Calling err() is allowed. * * By default, this just flushes the stream. */ @@ -151,7 +164,9 @@ public: class ReadStream : virtual public Stream { public: /** - * Returns true if the end of the stream has been reached. + * Returns true if a read failed because the stream has been reached. + * This flag is cleared by clearErr(). + * For a SeekableReadStream, it is also cleared by a successful seek. */ virtual bool eos() const = 0; @@ -167,13 +182,19 @@ public: // The remaining methods all have default implementations; subclasses - // need not (and should not) overload them. + // in general should not overload them. /** - * Read am unsigned byte from the stream and return it. + * DEPRECATED + * Default implementation for backward compatibility + */ + virtual bool ioFailed() { return (eos() || err()); } + + /** + * Read an unsigned byte from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ byte readByte() { byte b = 0; @@ -185,7 +206,7 @@ public: * Read a signed byte from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ int8 readSByte() { int8 b = 0; @@ -198,7 +219,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ uint16 readUint16LE() { uint16 a = readByte(); @@ -211,7 +232,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ uint32 readUint32LE() { uint32 a = readUint16LE(); @@ -224,7 +245,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ uint16 readUint16BE() { uint16 b = readByte(); @@ -237,7 +258,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ uint32 readUint32BE() { uint32 b = readUint16BE(); @@ -250,7 +271,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ int16 readSint16LE() { return (int16)readUint16LE(); @@ -261,7 +282,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ int32 readSint32LE() { return (int32)readUint32LE(); @@ -272,7 +293,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ int16 readSint16BE() { return (int16)readUint16BE(); @@ -283,7 +304,7 @@ public: * from the stream and return it. * Performs no error checking. The return value is undefined * if a read error occurred (for which client code can check by - * calling ioFailed()). + * calling err() and eos() ). */ int32 readSint32BE() { return (int32)readUint32BE(); @@ -293,7 +314,9 @@ public: * Read the specified amount of data into a malloc'ed buffer * which then is wrapped into a MemoryReadStream. * The returned stream might contain less data than requested, - * if reading more failed. + * if reading more failed, because of an I/O error or because + * the end of the stream was reached. Which can be determined by + * calling err() and eos(). */ MemoryReadStream *readStream(uint32 dataSize); @@ -303,57 +326,89 @@ public: /** * Interface for a seekable & readable data stream. * - * @todo We really need better error handling here! - * Like seek should somehow indicate whether it failed. + * @todo Get rid of SEEK_SET, SEEK_CUR, or SEEK_END, use our own constants */ class SeekableReadStream : virtual public ReadStream { public: - virtual uint32 pos() const = 0; - virtual uint32 size() const = 0; - - virtual void seek(int32 offset, int whence = SEEK_SET) = 0; - - void skip(uint32 offset) { seek(offset, SEEK_CUR); } - /** - * Read one line of text from a CR or CR/LF terminated plain text file. - * This method is a rough analog of the (f)gets function. + * Obtains the current value of the stream position indicator of the + * stream. * - * @bug A main difference (and flaw) in this function is that there is no - * way to detect that a line exceeeds the length of the buffer. - * Code which needs this should use the new readLine_NEW() method instead. + * @return the current position indicator, or -1 if an error occurred. + */ + virtual int32 pos() const = 0; + + /** + * Obtains the total size of the stream, measured in bytes. + * If this value is unknown or can not be computed, -1 is returned. * - * @param buf the buffer to store into - * @param bufSize the size of the buffer - * @return a pointer to the read string, or NULL if an error occurred + * @return the size of the stream, or -1 if an error occurred + */ + virtual int32 size() const = 0; + + /** + * Sets the stream position indicator for the stream. The new position, + * measured in bytes, is obtained by adding offset bytes to the position + * specified by whence. If whence is set to SEEK_SET, SEEK_CUR, or + * SEEK_END, the offset is relative to the start of the file, the current + * position indicator, or end-of-file, respectively. A successful call + * to the seek() method clears the end-of-file indicator for the stream. * - * @note The line terminator (CR or CR/LF) is stripped and not inserted - * into the buffer. + * @param offset the relative offset in bytes + * @param whence the seek reference: SEEK_SET, SEEK_CUR, or SEEK_END + * @return true on success, false in case of a failure + */ + virtual bool seek(int32 offset, int whence = SEEK_SET) = 0; + + /** + * TODO: Get rid of this??? Or keep it and document it + * @return true on success, false in case of a failure + */ + virtual bool skip(uint32 offset) { return seek(offset, SEEK_CUR); } + + /** + * DEPRECATED: Do not use this method! Instead use readLine_NEW() or readline(). */ - virtual char *readLine(char *buf, size_t bufSize); + virtual char *readLine_OLD(char *buf, size_t bufSize); /** * Reads at most one less than the number of characters specified * by bufSize from the and stores them in the string buf. Reading - * stops when the end of a line is reached (CR, CR/LF or LF), at - * end-of-file or error. The newline, if any, is retained (CR and - * CR/LF are translated to LF = 0xA = '\n'). If any characters are - * read and there is no error, a `\0' character is appended to end - * the string. + * stops when the end of a line is reached (CR, CR/LF or LF), and + * at end-of-file or error. The newline, if any, is retained (CR + * and CR/LF are translated to LF = 0xA = '\n'). If any characters + * are read and there is no error, a `\0' character is appended + * to end the string. * * Upon successful completion, return a pointer to the string. If * end-of-file occurs before any characters are read, returns NULL * and the buffer contents remain unchanged. If an error occurs, * returns NULL and the buffer contents are indeterminate. * This method does not distinguish between end-of-file and error; - * callers muse use ioFailed() or eos() to determine which occurred. + * callers must use err() or eos() to determine which occurred. + * + * @note This methods is closely modeled after the standard fgets() + * function from stdio.h. * * @param buf the buffer to store into * @param bufSize the size of the buffer * @return a pointer to the read string, or NULL if an error occurred */ virtual char *readLine_NEW(char *s, size_t bufSize); + + + /** + * Reads a full line and returns it as a Common::String. Reading + * stops when the end of a line is reached (CR, CR/LF or LF), and + * at end-of-file or error. + * + * Upon successful completion, return a string with the content + * of the line, *without* the end of a line marker. This method + * does not indicate whether an error occured. Callers muse use + * ioFailed() or eos() to determine whether an exception occurred. + */ + virtual String readLine(); }; /** @@ -369,19 +424,23 @@ protected: bool _disposeParentStream; uint32 _pos; uint32 _end; + bool _eos; public: SubReadStream(ReadStream *parentStream, uint32 end, bool disposeParentStream = false) : _parentStream(parentStream), _disposeParentStream(disposeParentStream), _pos(0), - _end(end) { + _end(end), + _eos(false) { assert(parentStream); } ~SubReadStream() { if (_disposeParentStream) delete _parentStream; } - virtual bool eos() const { return _pos == _end; } + virtual bool eos() const { return _eos; } + virtual bool err() const { return _parentStream->err(); } + virtual void clearErr() { _eos = false; _parentStream->clearErr(); } virtual uint32 read(void *dataPtr, uint32 dataSize); }; @@ -397,10 +456,10 @@ protected: public: SeekableSubReadStream(SeekableReadStream *parentStream, uint32 begin, uint32 end, bool disposeParentStream = false); - virtual uint32 pos() const { return _pos - _begin; } - virtual uint32 size() const { return _end - _begin; } + virtual int32 pos() const { return _pos - _begin; } + virtual int32 size() const { return _end - _begin; } - virtual void seek(int32 offset, int whence = SEEK_SET); + virtual bool seek(int32 offset, int whence = SEEK_SET); }; /** @@ -453,6 +512,8 @@ public: virtual bool eos() const { return (_pos == _bufSize) && _parentStream->eos(); } virtual bool ioFailed() const { return _parentStream->ioFailed(); } virtual void clearIOFailed() { _parentStream->clearIOFailed(); } + virtual bool err() const { return _parentStream->err(); } + virtual void clearErr() { _parentStream->clearErr(); } virtual uint32 read(void *dataPtr, uint32 dataSize); }; @@ -467,10 +528,10 @@ protected: public: BufferedSeekableReadStream(SeekableReadStream *parentStream, uint32 bufSize, bool disposeParentStream = false); - virtual uint32 pos() const { return _parentStream->pos() - (_bufSize - _pos); } - virtual uint32 size() const { return _parentStream->size(); } + virtual int32 pos() const { return _parentStream->pos() - (_bufSize - _pos); } + virtual int32 size() const { return _parentStream->size(); } - virtual void seek(int32 offset, int whence = SEEK_SET); + virtual bool seek(int32 offset, int whence = SEEK_SET); }; @@ -487,6 +548,7 @@ private: uint32 _pos; byte _encbyte; bool _disposeMemory; + bool _eos; public: @@ -501,7 +563,8 @@ public: _size(dataSize), _pos(0), _encbyte(0), - _disposeMemory(disposeMemory) {} + _disposeMemory(disposeMemory), + _eos(false) {} ~MemoryReadStream() { if (_disposeMemory) @@ -512,11 +575,13 @@ public: uint32 read(void *dataPtr, uint32 dataSize); - bool eos() const { return _pos == _size; } - uint32 pos() const { return _pos; } - uint32 size() const { return _size; } + bool eos() const { return _eos; } + void clearErr() { _eos = false; } + + int32 pos() const { return _pos; } + int32 size() const { return _size; } - void seek(int32 offs, int whence = SEEK_SET); + bool seek(int32 offs, int whence = SEEK_SET); }; @@ -569,7 +634,6 @@ public: return dataSize; } - bool eos() const { return _pos == _bufSize; } uint32 pos() const { return _pos; } uint32 size() const { return _bufSize; } }; @@ -623,7 +687,6 @@ public: return dataSize; } - bool eos() const { return false; } uint32 pos() const { return _pos; } uint32 size() const { return _size; } diff --git a/common/system.cpp b/common/system.cpp index d0548cdd2d..d9bc027e91 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -115,7 +115,8 @@ Common::EventManager *OSystem::getEventManager() { void OSystem::clearScreen() { Graphics::Surface *screen = lockScreen(); - memset(screen->pixels, 0, screen->h * screen->pitch); + if (screen && screen->pixels) + memset(screen->pixels, 0, screen->h * screen->pitch); unlockScreen(); } @@ -125,10 +126,9 @@ FIXME: The config file loading code below needs to be cleaned up. Port specific variants should be pushed into the respective ports. Ideally, the default OSystem::openConfigFileForReading/Writing methods - should be removed completely. + should be removed completely. */ -#include "common/file.h" #ifdef __PLAYSTATION2__ #include "backends/platform/ps2/systemps2.h" @@ -163,7 +163,7 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem::openConfigFileForReading() { - FilesystemNode file(getDefaultConfigFileName()); + Common::FilesystemNode file(getDefaultConfigFileName()); return file.openForReading(); } @@ -171,7 +171,7 @@ Common::WriteStream *OSystem::openConfigFileForWriting() { #ifdef __DC__ return 0; #else - FilesystemNode file(getDefaultConfigFileName()); + Common::FilesystemNode file(getDefaultConfigFileName()); return file.openForWriting(); #endif } diff --git a/common/system.h b/common/system.h index 501d0802fd..cb9dbedad7 100644 --- a/common/system.h +++ b/common/system.h @@ -43,6 +43,7 @@ namespace Common { struct Event; class EventManager; class SaveFileManager; + class SearchSet; class TimerManager; class SeekableReadStream; class WriteStream; @@ -907,6 +908,18 @@ public: virtual FilesystemFactory *getFilesystemFactory() = 0; /** + * Add system specific Common::Archive objects to the given SearchSet. + * E.g. on Unix the dir corresponding to DATA_PATH (if set), or on + * Mac OS X the 'Resource' dir in the app bundle. + * + * @todo Come up with a better name. This one sucks. + * + * @param s the SearchSet to which the system specific dirs, if any, are added + * @param priority the priority with which those dirs are added + */ + virtual void addSysArchivesToSearchSet(Common::SearchSet &s, uint priority = 0) {} + + /** * Open the default config file for reading, by returning a suitable * ReadStream instance. It is the callers responsiblity to delete * the stream after use. diff --git a/common/unarj.cpp b/common/unarj.cpp index 9a7766a41f..244a296efb 100644 --- a/common/unarj.cpp +++ b/common/unarj.cpp @@ -23,28 +23,9 @@ * */ -// Heavily based on Unarj 2.65 - -/* UNARJ.C, UNARJ, R JUNG, 06/05/02 - * Main Extractor routine - * Copyright (c) 1991-2002 by ARJ Software, Inc. All rights reserved. - * - * This code may be freely used in programs that are NOT ARJ archivers - * (both compress and extract ARJ archives). - * - * If you wish to distribute a modified version of this program, you - * MUST indicate that it is a modified version both in the program and - * source code. - * - * We are holding the copyright on the source code, so please do not - * delete our name from the program files or from the documentation. - * - * We wish to give credit to Haruhiko Okumura for providing the - * basic ideas for ARJ and UNARJ in his program AR. Please note - * that UNARJ is significantly different from AR from an archive - * structural point of view. - * - */ +// +// This file is heavily based on the arj code available under the GPL +// from http://arj.sourceforge.net/ , version 3.10.22 . #include "common/scummsys.h" #include "common/util.h" @@ -52,18 +33,38 @@ namespace Common { +#define HEADER_ID 0xEA60 +#define HEADER_ID_HI 0xEA +#define HEADER_ID_LO 0x60 + +#define FIRST_HDR_SIZE 30 +#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + ARJ_FILENAME_MAX + ARJ_COMMENT_MAX) +#define CRC_MASK 0xFFFFFFFFL +#define HSLIMIT_ARJ 524288L + +#define CBIT 9 +#define PBIT 5 +#define TBIT 5 + +// +// Source for InitCRC, GetCRC: crc32.c +// + static uint32 CRCtable[256]; static void InitCRC(void) { const uint32 poly = 0xEDB88320; int i, j; - uint32 n; + uint32 r; for (i = 0; i < 256; i++) { - n = i; + r = i; for (j = 0; j < 8; j++) - n = (n & 1) ? ((n >> 1) ^ poly) : (n >> 1); - CRCtable[i] = n; + if (r & 1) + r = (r >> 1) ^ poly; + else + r >>= 1; + CRCtable[i] = r; } } @@ -124,41 +125,47 @@ void ArjFile::registerArchive(const String &filename) { debug(0, "ArjFile::registerArchive(%s): Located %d files", filename.c_str(), _headers.size()); } +// +// Source for findHeader and readHeader: arj_arcv.c +// + int32 ArjFile::findHeader(void) { - long arcpos, lastpos; - int c; + long end_pos, tmp_pos; + int id; byte header[HEADERSIZE_MAX]; uint32 crc; - uint16 headersize; + uint16 basic_hdr_size; - arcpos = _currArchive.pos(); + tmp_pos = _currArchive.pos(); _currArchive.seek(0L, SEEK_END); - lastpos = _currArchive.pos() - 2; - if (lastpos > MAXSFX) - lastpos = MAXSFX; - - for ( ; arcpos < lastpos; arcpos++) { - _currArchive.seek(arcpos, SEEK_SET); - c = _currArchive.readByte(); - while (arcpos < lastpos) { - if (c != HEADER_ID_LO) // low order first - c = _currArchive.readByte(); - else if ((c = _currArchive.readByte()) == HEADER_ID_HI) - break; - arcpos++; + end_pos = _currArchive.pos() - 2; + if (end_pos >= tmp_pos + HSLIMIT_ARJ) + end_pos = tmp_pos + HSLIMIT_ARJ; + + while (tmp_pos < end_pos) { + _currArchive.seek(tmp_pos, SEEK_SET); + id = _currArchive.readByte(); + while (tmp_pos < end_pos) { + if (id == HEADER_ID_LO) + if ((id = _currArchive.readByte()) == HEADER_ID_HI) + break; + else + id = _currArchive.readByte(); + tmp_pos++; } - if (arcpos >= lastpos) - break; - if ((headersize = _currArchive.readUint16LE()) <= HEADERSIZE_MAX) { - _currArchive.read(header, headersize); - crc = GetCRC(header, headersize); + if (tmp_pos >= end_pos) + return -1; + if ((basic_hdr_size = _currArchive.readUint16LE()) <= HEADERSIZE_MAX) { + _currArchive.read(header, basic_hdr_size); + crc = GetCRC(header, basic_hdr_size); if (crc == _currArchive.readUint32LE()) { - _currArchive.seek(arcpos, SEEK_SET); - return arcpos; + _currArchive.seek(tmp_pos, SEEK_SET); + return tmp_pos; } } + tmp_pos++; } - return -1; // could not find a valid header + return -1; } ArjHeader *ArjFile::readHeader() { @@ -166,6 +173,7 @@ ArjHeader *ArjFile::readHeader() { ArjHeader *head; byte headData[HEADERSIZE_MAX]; + // Strictly check the header ID header.id = _currArchive.readUint16LE(); if (header.id != HEADER_ID) { warning("ArjFile::readHeader(): Bad header ID (%x)", header.id); @@ -199,7 +207,7 @@ ArjHeader *ArjFile::readHeader() { header.flags = readS.readByte(); header.method = readS.readByte(); header.fileType = readS.readByte(); - (void)readS.readByte(); + (void)readS.readByte(); // password_modifier header.timeStamp = readS.readUint32LE(); header.compSize = readS.readSint32LE(); header.origSize = readS.readSint32LE(); @@ -208,20 +216,20 @@ ArjHeader *ArjFile::readHeader() { header.fileMode = readS.readUint16LE(); header.hostData = readS.readUint16LE(); + // static int check_file_size() if (header.origSize < 0 || header.compSize < 0) { warning("ArjFile::readHeader(): Wrong file size"); return NULL; } - strncpy(header.filename, (const char *)&headData[header.firstHdrSize], FNAME_MAX); + strncpy(header.filename, (const char *)&headData[header.firstHdrSize], ARJ_FILENAME_MAX); - strncpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], COMMENT_MAX); + strncpy(header.comment, (const char *)&headData[header.firstHdrSize + strlen(header.filename) + 1], ARJ_COMMENT_MAX); - /* if extheadersize == 0 then no CRC */ - /* otherwise read extheader data and read 4 bytes for CRC */ - - while ((header.extHeaderSize = _currArchive.readUint16LE()) != 0) - _currArchive.seek((long)(header.extHeaderSize + 4), SEEK_CUR); + // Process extended headers, if any + uint16 extHeaderSize; + while ((extHeaderSize = _currArchive.readUint16LE()) != 0) + _currArchive.seek((long)(extHeaderSize + 4), SEEK_CUR); header.pos = _currArchive.pos(); @@ -320,53 +328,70 @@ bool ArjFile::eos() { return _uncompressed->eos(); } -uint32 ArjFile::pos() { +int32 ArjFile::pos() { return _uncompressed->pos(); } -uint32 ArjFile::size() { +int32 ArjFile::size() { return _uncompressed->size(); } -void ArjFile::seek(int32 offset, int whence) { - _uncompressed->seek(offset, whence); +bool ArjFile::seek(int32 offset, int whence) { + return _uncompressed->seek(offset, whence); } +// +// Source for init_getbits: arj_file.c (decode_start_stub) +// + void ArjFile::init_getbits() { _bitbuf = 0; - _subbitbuf = 0; + _bytebuf = 0; _bitcount = 0; - fillbuf(2 * CHAR_BIT); + fillbuf(ARJ_CHAR_BIT * 2); } -void ArjFile::fillbuf(int n) { // Shift bitbuf n bits left, read n bits - _bitbuf = (_bitbuf << n) & 0xFFFF; /* lose the first n bits */ - while (n > _bitcount) { - _bitbuf |= _subbitbuf << (n -= _bitcount); - if (_compsize != 0) { +// +// Source for fillbuf, getbits: decode.c +// + +void ArjFile::fillbuf(int n) { + while (_bitcount < n) { + _bitbuf = (_bitbuf << _bitcount) | (_bytebuf >> (8 - _bitcount)); + n -= _bitcount; + if (_compsize > 0) { _compsize--; - _subbitbuf = _compressed->readByte(); - } else - _subbitbuf = 0; - _bitcount = CHAR_BIT; + _bytebuf = _compressed->readByte(); + } else { + _bytebuf = 0; + } + _bitcount = 8; } - _bitbuf |= _subbitbuf >> (_bitcount -= n); + _bitcount -= n; + _bitbuf = ( _bitbuf << n) | (_bytebuf >> (8-n)); + _bytebuf <<= n; } +// Reads a series of bits into the input buffer */ uint16 ArjFile::getbits(int n) { - uint16 x; + uint16 rc; - x = _bitbuf >> (2 * CHAR_BIT - n); + rc = _bitbuf >> (ARJ_CODE_BIT - n); fillbuf(n); - return x; + return rc; } -/* Huffman decode routines */ +// +// Huffman decode routines +// Source: decode.c +// +// Creates a table for decoding void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, int tablesize) { - uint16 count[17], weight[17], start[18], *p; + uint16 count[17], weight[17], start[18]; + uint16 *p; uint i, k, len, ch, jutbits, avail, nextcode, mask; for (i = 1; i <= 16; i++) @@ -415,7 +440,8 @@ void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, while (i != 0) { if (*p == 0) { _right[avail] = _left[avail] = 0; - *p = avail++; + *p = avail; + avail++; } if (k & mask) p = &_right[*p]; @@ -430,6 +456,7 @@ void ArjFile::make_table(int nchar, byte *bitlen, int tablebits, uint16 *table, } } +// Reads length of data pending void ArjFile::read_pt_len(int nn, int nbit, int i_special) { int i, n; int16 c; @@ -445,9 +472,9 @@ void ArjFile::read_pt_len(int nn, int nbit, int i_special) { } else { i = 0; while (i < n) { - c = _bitbuf >> (13); + c = _bitbuf >> 13; if (c == 7) { - mask = 1 << (12); + mask = 1 << 12; while (mask & _bitbuf) { mask >>= 1; c++; @@ -463,10 +490,11 @@ void ArjFile::read_pt_len(int nn, int nbit, int i_special) { } while (i < nn) _pt_len[i++] = 0; - make_table(nn, _pt_len, 8, _pt_table, PTABLESIZE); // replaced sizeof + make_table(nn, _pt_len, 8, _pt_table, ARJ_PTABLESIZE); } } +// Reads a character table void ArjFile::read_c_len() { int16 i, c, n; uint16 mask; @@ -474,82 +502,87 @@ void ArjFile::read_c_len() { n = getbits(CBIT); if (n == 0) { c = getbits(CBIT); - for (i = 0; i < NC; i++) + for (i = 0; i < ARJ_NC; i++) _c_len[i] = 0; - for (i = 0; i < CTABLESIZE; i++) + for (i = 0; i < ARJ_CTABLESIZE; i++) _c_table[i] = c; } else { i = 0; while (i < n) { c = _pt_table[_bitbuf >> (8)]; - if (c >= NT) { - mask = 1 << (7); + if (c >= ARJ_NT) { + mask = 1 << 7; do { if (_bitbuf & mask) c = _right[c]; else c = _left[c]; mask >>= 1; - } while (c >= NT); + } while (c >= ARJ_NT); } fillbuf((int)(_pt_len[c])); if (c <= 2) { if (c == 0) c = 1; - else if (c == 1) - c = getbits(4) + 3; - else - c = getbits(CBIT) + 20; + else if (c == 1) { + c = getbits(4); + c += 3; + } else { + c = getbits(CBIT); + c += 20; + } while (--c >= 0) _c_len[i++] = 0; } else _c_len[i++] = (byte)(c - 2); } - while (i < NC) + while (i < ARJ_NC) _c_len[i++] = 0; - make_table(NC, _c_len, 12, _c_table, CTABLESIZE); // replaced sizeof + make_table(ARJ_NC, _c_len, 12, _c_table, ARJ_CTABLESIZE); } } +// Decodes a single character uint16 ArjFile::decode_c() { uint16 j, mask; if (_blocksize == 0) { - _blocksize = getbits(16); - read_pt_len(NT, TBIT, 3); + _blocksize = getbits(ARJ_CODE_BIT); + read_pt_len(ARJ_NT, TBIT, 3); read_c_len(); - read_pt_len(NP, PBIT, -1); + read_pt_len(ARJ_NP, PBIT, -1); } _blocksize--; j = _c_table[_bitbuf >> 4]; - if (j >= NC) { - mask = 1 << (3); + if (j >= ARJ_NC) { + mask = 1 << 3; do { if (_bitbuf & mask) j = _right[j]; else j = _left[j]; mask >>= 1; - } while (j >= NC); + } while (j >= ARJ_NC); } fillbuf((int)(_c_len[j])); return j; } +// Decodes a control character uint16 ArjFile::decode_p() { uint16 j, mask; - j = _pt_table[_bitbuf >> (8)]; - if (j >= NP) { - mask = 1 << (7); + j = _pt_table[_bitbuf >> 8]; + if (j >= ARJ_NP) { + mask = 1 << 7; do { if (_bitbuf & mask) j = _right[j]; else j = _left[j]; mask >>= 1; - } while (j >= NP); + } while (j >= ARJ_NP); } fillbuf((int)(_pt_len[j])); if (j != 0) { @@ -559,63 +592,59 @@ uint16 ArjFile::decode_p() { return j; } +// Initializes memory for decoding void ArjFile::decode_start() { _blocksize = 0; init_getbits(); } +// Decodes the entire file void ArjFile::decode() { int16 i; - int16 j; - int16 c; int16 r; + int16 c; + int16 j; int32 count; decode_start(); - count = 0; + count = _origsize; r = 0; - while (count < _origsize) { + while (count > 0) { if ((c = decode_c()) <= ARJ_UCHAR_MAX) { - _text[r] = (byte) c; - count++; - if (++r >= DDICSIZ) { + _ntext[r] = (byte) c; + count--; + if (++r >= ARJ_DICSIZ) { r = 0; - _outstream->write(_text, DDICSIZ); + _outstream->write(_ntext, ARJ_DICSIZ); } } else { - j = c - (ARJ_UCHAR_MAX + 1 - THRESHOLD); - count += j; - i = decode_p(); - if ((i = r - i - 1) < 0) - i += DDICSIZ; - if (r > i && r < DDICSIZ - MAXMATCH - 1) { + j = c - (ARJ_UCHAR_MAX + 1 - ARJ_THRESHOLD); + count -= j; + i = r - decode_p() - 1; + if (i < 0) + i += ARJ_DICSIZ; + if (r > i && r < ARJ_DICSIZ - ARJ_MAXMATCH - 1) { while (--j >= 0) - _text[r++] = _text[i++]; + _ntext[r++] = _ntext[i++]; } else { while (--j >= 0) { - _text[r] = _text[i]; - if (++r >= DDICSIZ) { + _ntext[r] = _ntext[i]; + if (++r >= ARJ_DICSIZ) { r = 0; - _outstream->write(_text, DDICSIZ); + _outstream->write(_ntext, ARJ_DICSIZ); } - if (++i >= DDICSIZ) + if (++i >= ARJ_DICSIZ) i = 0; } } } } - if (r != 0) - _outstream->write(_text, r); + if (r > 0) + _outstream->write(_ntext, r); } -/* Macros */ - -#define BFIL {_getbuf|=_bitbuf>>_getlen;fillbuf(CODE_BIT-_getlen);_getlen=CODE_BIT;} -#define GETBIT(c) {if(_getlen<=0)BFIL c=(_getbuf&0x8000)!=0;_getbuf<<=1;_getlen--;} -#define BPUL(l) {_getbuf<<=l;_getlen-=l;} -#define GETBITS(c,l) {if(_getlen<l)BFIL c=(uint16)_getbuf>>(CODE_BIT-l);BPUL(l)} - +// Backward pointer decoding int16 ArjFile::decode_ptr() { int16 c = 0; int16 width; @@ -623,20 +652,21 @@ int16 ArjFile::decode_ptr() { int16 pwr; plus = 0; - pwr = 1 << (STRTP); - for (width = (STRTP); width < (STOPP); width++) { - GETBIT(c); + pwr = 1 << 9; + for (width = 9; width < 13; width++) { + c = getbits(1); if (c == 0) break; plus += pwr; pwr <<= 1; } if (width != 0) - GETBITS(c, width); + c = getbits(width); c += plus; return c; } +// Reference length decoding int16 ArjFile::decode_len() { int16 c = 0; int16 width; @@ -644,62 +674,60 @@ int16 ArjFile::decode_len() { int16 pwr; plus = 0; - pwr = 1 << (STRTL); - for (width = (STRTL); width < (STOPL); width++) { - GETBIT(c); + pwr = 1; + for (width = 0; width < 7; width++) { + c = getbits(1); if (c == 0) break; plus += pwr; pwr <<= 1; } if (width != 0) - GETBITS(c, width); + c = getbits(width); c += plus; return c; } +// Decodes the entire file, using method 4 void ArjFile::decode_f() { int16 i; int16 j; int16 c; int16 r; - int16 pos1; - int32 count; + uint32 ncount; init_getbits(); + ncount = 0; _getlen = _getbuf = 0; - count = 0; r = 0; - while (count < _origsize) { + while (ncount < (uint32)_origsize) { c = decode_len(); if (c == 0) { - GETBITS(c, CHAR_BIT); - _text[r] = (byte)c; - count++; - if (++r >= DDICSIZ) { + ncount++; + _ntext[r] = (byte)getbits(8); + if (++r >= ARJ_FDICSIZ) { r = 0; - _outstream->write(_text, DDICSIZ); + _outstream->write(_ntext, ARJ_FDICSIZ); } } else { - j = c - 1 + THRESHOLD; - count += j; - pos1 = decode_ptr(); - if ((i = r - pos1 - 1) < 0) - i += DDICSIZ; + j = c - 1 + ARJ_THRESHOLD; + ncount += j; + if ((i = r - decode_ptr() - 1) < 0) + i += ARJ_FDICSIZ; while (j-- > 0) { - _text[r] = _text[i]; - if (++r >= DDICSIZ) { + _ntext[r] = _ntext[i]; + if (++r >= ARJ_FDICSIZ) { r = 0; - _outstream->write(_text, DDICSIZ); + _outstream->write(_ntext, ARJ_FDICSIZ); } - if (++i >= DDICSIZ) + if (++i >= ARJ_FDICSIZ) i = 0; } } } if (r != 0) - _outstream->write(_text, r); + _outstream->write(_ntext, r); } diff --git a/common/unarj.h b/common/unarj.h index c8965968f6..52e0d13948 100644 --- a/common/unarj.h +++ b/common/unarj.h @@ -31,46 +31,31 @@ namespace Common { -#define HEADER_ID 0xEA60 -#define HEADER_ID_HI 0xEA -#define HEADER_ID_LO 0x60 -#define FIRST_HDR_SIZE 30 -#define FIRST_HDR_SIZE_V 34 -#define COMMENT_MAX 2048 -#define FNAME_MAX 512 -#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX) -#define CRC_MASK 0xFFFFFFFFL -#define MAXSFX 25000L - -#define CODE_BIT 16 -#define CHAR_BIT 8 -#define ARJ_UCHAR_MAX 255 // UCHAR_MAX is defined in limits.h in MSVC -#define THRESHOLD 3 -#define DDICSIZ 26624 -#define MAXDICBIT 16 -#define MATCHBIT 8 -#define MAXMATCH 256 -#define NC (ARJ_UCHAR_MAX + MAXMATCH + 2 - THRESHOLD) -#define NP (MAXDICBIT + 1) -#define CBIT 9 -#define NT (CODE_BIT + 3) -#define PBIT 5 -#define TBIT 5 - -#if NT > NP -#define NPT NT +#define ARJ_UCHAR_MAX 255 +#define ARJ_CHAR_BIT 8 + +#define ARJ_COMMENT_MAX 2048 +#define ARJ_FILENAME_MAX 512 + +#define ARJ_CODE_BIT 16 +#define ARJ_THRESHOLD 3 +#define ARJ_DICSIZ 26624 +#define ARJ_FDICSIZ ARJ_DICSIZ +#define ARJ_MAXDICBIT 16 +#define ARJ_MAXMATCH 256 +#define ARJ_NC (ARJ_UCHAR_MAX + ARJ_MAXMATCH + 2 - ARJ_THRESHOLD) +#define ARJ_NP (ARJ_MAXDICBIT + 1) +#define ARJ_NT (ARJ_CODE_BIT + 3) + +#if ARJ_NT > ARJ_NP +#define ARJ_NPT ARJ_NT #else -#define NPT NP +#define ARJ_NPT ARJ_NP #endif -#define CTABLESIZE 4096 -#define PTABLESIZE 256 +#define ARJ_CTABLESIZE 4096 +#define ARJ_PTABLESIZE 256 -#define STRTP 9 -#define STOPP 13 - -#define STRTL 0 -#define STOPL 7 struct ArjHeader { int32 pos; @@ -92,9 +77,8 @@ struct ArjHeader { uint16 entryPos; uint16 fileMode; uint16 hostData; - char filename[FNAME_MAX]; - char comment[COMMENT_MAX]; - uint16 extHeaderSize; + char filename[ARJ_FILENAME_MAX]; + char comment[ARJ_COMMENT_MAX]; uint32 headerCrc; }; @@ -115,9 +99,9 @@ public: uint32 read(void *dataPtr, uint32 dataSize); bool eos(); - uint32 pos(); - uint32 size(); - void seek(int32 offset, int whence = SEEK_SET); + int32 pos(); + int32 size(); + bool seek(int32 offset, int whence = SEEK_SET); bool isOpen() { return _isOpen; } private: @@ -143,6 +127,7 @@ private: void decode_f(); uint16 _bitbuf; + uint16 _bytebuf; int32 _compsize; int32 _origsize; byte _subbitbuf; @@ -163,18 +148,18 @@ private: int16 decode_len(void); private: - byte _text[DDICSIZ]; + byte _ntext[ARJ_FDICSIZ]; int16 _getlen; int16 _getbuf; - uint16 _left[2 * NC - 1]; - uint16 _right[2 * NC - 1]; - byte _c_len[NC]; - byte _pt_len[NPT]; + uint16 _left[2 * ARJ_NC - 1]; + uint16 _right[2 * ARJ_NC - 1]; + byte _c_len[ARJ_NC]; + byte _pt_len[ARJ_NPT]; - uint16 _c_table[CTABLESIZE]; - uint16 _pt_table[PTABLESIZE]; + uint16 _c_table[ARJ_CTABLESIZE]; + uint16 _pt_table[ARJ_PTABLESIZE]; uint16 _blocksize; diff --git a/common/unzip.h b/common/unzip.h index 2d888fe5b1..43faaf4a74 100644 --- a/common/unzip.h +++ b/common/unzip.h @@ -65,9 +65,12 @@ #ifndef _unz_H #define _unz_H +#ifdef USE_ZLIB + #include "common/scummsys.h" +#include "common/archive.h" +#include "common/stream.h" -#ifdef USE_ZLIB #ifdef __cplusplus extern "C" { @@ -302,6 +305,49 @@ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, } #endif -#endif + +class ZipArchive : Common::Archive { + unzFile _zipFile; + +public: + ZipArchive(const Common::String &name) { + _zipFile = unzOpen(name.c_str()); + } + ~ZipArchive() { + unzClose(_zipFile); + } + + virtual bool hasFile(const Common::String &name) { + return (_zipFile && unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK); + } + + virtual int getAllNames(Common::StringList &list) { + // TODO + return 0; + } + + virtual Common::SeekableReadStream *openFile(const Common::String &name) { + if (!_zipFile) + return 0; + + unzLocateFile(_zipFile, name.c_str(), 2); + + unz_file_info fileInfo; + unzOpenCurrentFile(_zipFile); + unzGetCurrentFileInfo(_zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0); + byte *buffer = (byte *)calloc(fileInfo.uncompressed_size+1, 1); + assert(buffer); + unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size); + unzCloseCurrentFile(_zipFile); + return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, true); + + // FIXME: instead of reading all into a memory stream, we could + // instead create a new ZipStream class. But then we have to be + // careful to handle the case where the client code opens multiple + // files in the archive and tries to use them indepenendtly. + } +}; + +#endif // USE_ZLIB #endif /* _unz_H */ diff --git a/common/util.cpp b/common/util.cpp index 6f0fdcb233..f68d253ec3 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -63,39 +63,6 @@ extern bool isSmartphone(void); namespace Common { -bool matchString(const char *str, const char *pat) { - const char *p = 0; - const char *q = 0; - - for (;;) { - switch (*pat) { - case '*': - p = ++pat; - q = str; - break; - - default: - if (*pat != *str) { - if (p) { - pat = p; - str = ++q; - if (!*str) - return !*pat; - break; - } - else - return false; - } - // fallthrough - case '?': - if (!*str) - return !*pat; - pat++; - str++; - } - } -} - StringTokenizer::StringTokenizer(const String &str, const String &delimiters) : _str(str), _delimiters(delimiters) { reset(); } @@ -237,10 +204,9 @@ Language parseLanguage(const String &str) { if (str.empty()) return UNK_LANG; - const char *s = str.c_str(); const LanguageDescription *l = g_languages; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s)) + if (str.equalsIgnoreCase(l->code)) return l->id; } @@ -278,6 +244,7 @@ const PlatformDescription g_platforms[] = { {"c64", "c64", "c64", "Commodore 64", kPlatformC64}, {"pc", "dos", "ibm", "DOS", kPlatformPC}, {"pc98", "pc98", "pc98", "PC-98", kPlatformPC98}, + {"wii", "wii", "wii", "Nintendo Wii", kPlatformWii}, // The 'official' spelling seems to be "FM-TOWNS" (e.g. in the Indy4 demo). // However, on the net many variations can be seen, like "FMTOWNS", @@ -299,20 +266,18 @@ Platform parsePlatform(const String &str) { if (str.empty()) return kPlatformUnknown; - const char *s = str.c_str(); - // Handle some special case separately, for compatibility with old config // files. - if (!strcmp(s, "1")) + if (str == "1") return kPlatformAmiga; - else if (!strcmp(s, "2")) + else if (str == "2") return kPlatformAtariST; - else if (!strcmp(s, "3")) + else if (str == "3") return kPlatformMacintosh; const PlatformDescription *l = g_platforms; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s) || !scumm_stricmp(l->code2, s) || !scumm_stricmp(l->abbrev, s)) + if (str.equalsIgnoreCase(l->code) || str.equalsIgnoreCase(l->code2) || str.equalsIgnoreCase(l->abbrev)) return l->id; } @@ -364,10 +329,9 @@ RenderMode parseRenderMode(const String &str) { if (str.empty()) return kRenderDefault; - const char *s = str.c_str(); const RenderModeDescription *l = g_renderModes; for (; l->code; ++l) { - if (!scumm_stricmp(l->code, s)) + if (str.equalsIgnoreCase(l->code)) return l->id; } diff --git a/common/util.h b/common/util.h index c23513596c..32f07181c4 100644 --- a/common/util.h +++ b/common/util.h @@ -53,28 +53,6 @@ template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; } namespace Common { /** - * Simple DOS-style pattern matching function (understands * and ? like used in DOS). - * Taken from exult/files/listfiles.cc - * - * Token meaning: - * "*": any character, any amount of times. - * "?": any character, only once. - * - * Example strings/patterns: - * String: monkey.s?? Pattern: monkey.s01 => true - * String: monkey.s?? Pattern: monkey.s101 => false - * String: monkey.s?1 Pattern: monkey.s99 => false - * String: monkey.s* Pattern: monkey.s101 => true - * String: monkey.s*1 Pattern: monkey.s99 => false - * - * @param str Text to be matched against the given pattern. - * @param pat Glob pattern. - * - * @return true if str matches the pattern, false otherwise. - */ -bool matchString(const char *str, const char *pat); - -/** * A simple non-optimized string tokenizer. * * Example of use: @@ -210,6 +188,7 @@ enum Platform { kPlatformApple2GS, kPlatformPC98, + kPlatformWii, kPlatformUnknown = -1 }; diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index 44bf03336e..b93a5205be 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -61,7 +61,7 @@ bool XMLParser::parserError(const char *errorString, ...) { char lineStr[70]; _stream->seek(original_pos - 35, SEEK_SET); - _stream->readLine(lineStr, 70); + _stream->readLine_NEW(lineStr, 70); for (int i = 0; i < 70; ++i) if (lineStr[i] == '\n') @@ -106,15 +106,16 @@ bool XMLParser::parseActiveKey(bool closed) { key->layout = layout->children[key->name]; Common::StringMap localMap = key->values; + int keyCount = localMap.size(); for (Common::List<XMLKeyLayout::XMLKeyProperty>::const_iterator i = key->layout->properties.begin(); i != key->layout->properties.end(); ++i) { - if (localMap.contains(i->name)) - localMap.erase(i->name); - else if (i->required) + if (i->required && !localMap.contains(i->name)) return parserError("Missing required property '%s' inside key '%s'", i->name.c_str(), key->name.c_str()); + else if (localMap.contains(i->name)) + keyCount--; } - if (localMap.empty() == false) + if (keyCount > 0) return parserError("Unhandled property inside key '%s': '%s'", key->name.c_str(), localMap.begin()->_key.c_str()); } else { diff --git a/common/zlib.cpp b/common/zlib.cpp index 7e14a9e3ab..4ed233b4b0 100644 --- a/common/zlib.cpp +++ b/common/zlib.cpp @@ -8,37 +8,327 @@ * 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. * * $URL$ * $Id$ + * */ #include "common/zlib.h" +#include "common/util.h" #if defined(USE_ZLIB) + #ifdef __SYMBIAN32__ + #include <zlib\zlib.h> + #else + #include <zlib.h> + #endif -#ifdef __SYMBIAN32__ -#include <zlib\zlib.h> -#else -#include <zlib.h> + #if ZLIB_VERNUM < 0x1204 + #error Version 1.2.0.4 or newer of zlib is required for this code + #endif #endif + namespace Common { -int uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) { - return ::uncompress(dst, dstLen, src, srcLen); +#if defined(USE_ZLIB) + +bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen) { + return Z_OK == ::uncompress(dst, dstLen, src, srcLen); } -} // end of namespace Common +/** + * A simple wrapper class which can be used to wrap around an arbitrary + * other SeekableReadStream and will then provide on-the-fly decompression support. + * Assumes the compressed data to be in gzip format. + */ +class GZipReadStream : public Common::SeekableReadStream { +protected: + enum { + BUFSIZE = 16384 // 1 << MAX_WBITS + }; + + byte _buf[BUFSIZE]; + + Common::SeekableReadStream *_wrapped; + z_stream _stream; + int _zlibErr; + uint32 _pos; + uint32 _origSize; + bool _eos; + +public: + + GZipReadStream(Common::SeekableReadStream *w) : _wrapped(w) { + assert(w != 0); + + _stream.zalloc = Z_NULL; + _stream.zfree = Z_NULL; + _stream.opaque = Z_NULL; + + // Verify file header is correct + w->seek(0, SEEK_SET); + uint16 header = w->readUint16BE(); + assert(header == 0x1F8B || + ((header & 0x0F00) == 0x0800 && header % 31 == 0)); + + if (header == 0x1F8B) { + // Retrieve the original file size + w->seek(-4, SEEK_END); + _origSize = w->readUint32LE(); + } else { + // Original size not available in zlib format + _origSize = 0; + } + _pos = 0; + w->seek(0, SEEK_SET); + _eos = false; + + // Adding 32 to windowBits indicates to zlib that it is supposed to + // automatically detect whether gzip or zlib headers are used for + // the compressed file. This feature was added in zlib 1.2.0.4, + // released 10 August 2003. + // Note: This is *crucial* for savegame compatibility, do *not* remove! + _zlibErr = inflateInit2(&_stream, MAX_WBITS + 32); + if (_zlibErr != Z_OK) + return; + + // Setup input buffer + _stream.next_in = _buf; + _stream.avail_in = 0; + } + + ~GZipReadStream() { + inflateEnd(&_stream); + delete _wrapped; + } + + bool err() const { return (_zlibErr != Z_OK) && (_zlibErr != Z_STREAM_END); } + void clearErr() { + // only reset _eos; I/O errors are not recoverable + _eos = false; + } + + uint32 read(void *dataPtr, uint32 dataSize) { + _stream.next_out = (byte *)dataPtr; + _stream.avail_out = dataSize; + + // Keep going while we get no error + while (_zlibErr == Z_OK && _stream.avail_out) { + if (_stream.avail_in == 0 && !_wrapped->eos()) { + // If we are out of input data: Read more data, if available. + _stream.next_in = _buf; + _stream.avail_in = _wrapped->read(_buf, BUFSIZE); + } + _zlibErr = inflate(&_stream, Z_NO_FLUSH); + } + + // Update the position counter + _pos += dataSize - _stream.avail_out; + + if (_zlibErr == Z_STREAM_END && _stream.avail_out > 0) + _eos = true; + + return dataSize - _stream.avail_out; + } + + bool eos() const { + return _eos; + } + int32 pos() const { + return _pos; + } + int32 size() const { + return _origSize; + } + bool seek(int32 offset, int whence = SEEK_SET) { + int32 newPos = 0; + assert(whence != SEEK_END); // SEEK_END not supported + switch(whence) { + case SEEK_SET: + newPos = offset; + break; + case SEEK_CUR: + newPos = _pos + offset; + } + + assert(newPos >= 0); + + if ((uint32)newPos < _pos) { + // To search backward, we have to restart the whole decompression + // from the start of the file. A rather wasteful operation, best + // to avoid it. :/ +#if DEBUG + warning("Backward seeking in GZipReadStream detected"); +#endif + _pos = 0; + _wrapped->seek(0, SEEK_SET); + _zlibErr = inflateReset(&_stream); + if (_zlibErr != Z_OK) + return false; // FIXME: STREAM REWRITE + _stream.next_in = _buf; + _stream.avail_in = 0; + } + + offset = newPos - _pos; + + // Skip the given amount of data (very inefficient if one tries to skip + // huge amounts of data, but usually client code will only skip a few + // bytes, so this should be fine. + byte tmpBuf[1024]; + while (!err() && offset > 0) { + offset -= read(tmpBuf, MIN((int32)sizeof(tmpBuf), offset)); + } + + _eos = false; + return true; // FIXME: STREAM REWRITE + } +}; + +/** + * A simple wrapper class which can be used to wrap around an arbitrary + * other WriteStream and will then provide on-the-fly compression support. + * The compressed data is written in the gzip format. + */ +class GZipWriteStream : public Common::WriteStream { +protected: + enum { + BUFSIZE = 16384 // 1 << MAX_WBITS + }; + + byte _buf[BUFSIZE]; + Common::WriteStream *_wrapped; + z_stream _stream; + int _zlibErr; + + void processData(int flushType) { + // This function is called by both write() and finalize(). + while (_zlibErr == Z_OK && (_stream.avail_in || flushType == Z_FINISH)) { + if (_stream.avail_out == 0) { + if (_wrapped->write(_buf, BUFSIZE) != BUFSIZE) { + _zlibErr = Z_ERRNO; + break; + } + _stream.next_out = _buf; + _stream.avail_out = BUFSIZE; + } + _zlibErr = deflate(&_stream, flushType); + } + } + +public: + GZipWriteStream(Common::WriteStream *w) : _wrapped(w) { + assert(w != 0); + _stream.zalloc = Z_NULL; + _stream.zfree = Z_NULL; + _stream.opaque = Z_NULL; + + // Adding 16 to windowBits indicates to zlib that it is supposed to + // write gzip headers. This feature was added in zlib 1.2.0.4, + // released 10 August 2003. + // Note: This is *crucial* for savegame compatibility, do *not* remove! + _zlibErr = deflateInit2(&_stream, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + MAX_WBITS + 16, + 8, + Z_DEFAULT_STRATEGY); + assert(_zlibErr == Z_OK); + + _stream.next_out = _buf; + _stream.avail_out = BUFSIZE; + _stream.avail_in = 0; + _stream.next_in = 0; + } + + ~GZipWriteStream() { + finalize(); + deflateEnd(&_stream); + delete _wrapped; + } + + bool err() const { + // CHECKME: does Z_STREAM_END make sense here? + return (_zlibErr != Z_OK && _zlibErr != Z_STREAM_END) || _wrapped->err(); + } + + void clearErr() { + // Note: we don't reset the _zlibErr here, as it is not + // clear in general how + _wrapped->clearErr(); + } + + void finalize() { + if (_zlibErr != Z_OK) + return; + + // Process whatever remaining data there is. + processData(Z_FINISH); + // Since processData only writes out blocks of size BUFSIZE, + // we may have to flush some stragglers. + uint remainder = BUFSIZE - _stream.avail_out; + if (remainder > 0) { + if (_wrapped->write(_buf, remainder) != remainder) { + _zlibErr = Z_ERRNO; + } + } + + // Finalize the wrapped savefile, too + _wrapped->finalize(); + } + + uint32 write(const void *dataPtr, uint32 dataSize) { + if (err()) + return 0; + + // Hook in the new data ... + // Note: We need to make a const_cast here, as zlib is not aware + // of the const keyword. + _stream.next_in = const_cast<byte *>((const byte *)dataPtr); + _stream.avail_in = dataSize; + + // ... and flush it to disk + processData(Z_NO_FLUSH); + + return dataSize - _stream.avail_in; + } +}; + +#endif // USE_ZLIB + +Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped) { +#if defined(USE_ZLIB) + if (toBeWrapped) { + uint16 header = toBeWrapped->readUint16BE(); + bool isCompressed = (header == 0x1F8B || + ((header & 0x0F00) == 0x0800 && + header % 31 == 0)); + toBeWrapped->seek(-2, SEEK_CUR); + if (isCompressed) + return new GZipReadStream(toBeWrapped); + } #endif + return toBeWrapped; +} + +Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped) { +#if defined(USE_ZLIB) + if (toBeWrapped) + return new GZipWriteStream(toBeWrapped); +#endif + return toBeWrapped; +} + +} // End of namespace Common diff --git a/common/zlib.h b/common/zlib.h index 62e9f98c01..5fd13e842d 100644 --- a/common/zlib.h +++ b/common/zlib.h @@ -8,44 +8,65 @@ * 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. * * $URL$ * $Id$ + * */ -#include "common/scummsys.h" - -#if defined(USE_ZLIB) - #ifndef COMMON_ZLIB_H #define COMMON_ZLIB_H -#ifdef __SYMBIAN32__ -#include <zlib\zlib.h> -#else -#include <zlib.h> -#endif +#include "common/scummsys.h" +#include "common/stream.h" namespace Common { -enum { - ZLIB_OK = Z_OK -}; - -int uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen); +#if defined(USE_ZLIB) -} // end of namespace Common +/** + * Thin wrapper around zlib's uncompress() function. This wrapper makes + * it possible to uncompress data in engines without being forced to link + * them against zlib, thus simplifying the build system. + * + * @return true on success (i.e. Z_OK), false otherwise + */ +bool uncompress(byte *dst, unsigned long *dstLen, const byte *src, unsigned long srcLen); #endif -#endif +/** + * Take an arbitrary SeekableReadStream and wrap it in a custom stream which + * provides transparent on-the-fly decompression. Assumes the data it + * retrieves from the wrapped stream to be either uncompressed or in gzip + * format. In the former case, the original stream is returned unmodified + * (and in particular, not wrapped). + * + * It is safe to call this with a NULL parameter (in this case, NULL is + * returned). + */ +Common::SeekableReadStream *wrapCompressedReadStream(Common::SeekableReadStream *toBeWrapped); +/** + * Take an arbitrary WriteStream and wrap it in a custom stream which provides + * transparent on-the-fly compression. The compressed data is written in the + * gzip format, unless ZLIB support has been disabled, in which case the given + * stream is returned unmodified (and in particular, not wrapped). + * + * It is safe to call this with a NULL parameter (in this case, NULL is + * returned). + */ +Common::WriteStream *wrapCompressedWriteStream(Common::WriteStream *toBeWrapped); + +} // End of namespace Common + +#endif |