diff --git a/.gitignore b/.gitignore index 5673796..ecfc99b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ psp2/build_vita/* psp2/*.a sdl/gen_sdl sdl/build_sdl +sdl2/gen_sdl2 +sdl2/build_sdl2 diff --git a/sdl2/CHANGELOG.txt b/sdl2/CHANGELOG.txt new file mode 100644 index 0000000..7d7d2cc --- /dev/null +++ b/sdl2/CHANGELOG.txt @@ -0,0 +1,694 @@ +-------------------- +Genesis Plus History +-------------------- + +All recent changes were backported from the GX version (Gamecube/Wii port), maintained by Eke-Eke. +Please look at http://code.google.com/p/genplus-gx/ for more infos. + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.4 (21/06/2013) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* fixed access to read-only registers on Main-CPU side ("Batman Returns" platform level freeze) +* fixed & improved emulation of PRG-RAM write protection register ("Lunar Eternal Blue" japanese version freeze) +* improved SUB & MAIN-CPU synchronization ("Dracula Unleashed" freeze when using US Model 2 BIOS) +* improved CPU polling detection +* improved CDD emulation & added CD drive access time for SEEK command ("Panic!/Switch" intro missing scene) +* added missing reinitialization of MAIN-CPU PRG-RAM bank on reset +* added .OGG audio tracks support through LIBTREMOR + +[Core/Sound] +--------------- +* fixed YM2612 configurable DAC depth emulation +* improved Low-Pass filter +* added optional "MONO" output mode + +[Core/VDP] +--------------- +* fixed FIFO access timings when using invalid write code value ("Clue" menu) +* fixed DMA Copy with undocumented code value ("Fatal Labyrinth" end sequence) +* minor code fixes & optimizations + +[Core/CPU] +--------------- +* optimized 68k stack read/write functions +* fixed broken 68k address error emulation +* fixed 68k interrupt behavior (prevents interrupts from being executed multiple time when 68k is halted) +* fixed Z80 registers initial state, added proper initialization when using PBC (verified on real hardware by Charles McDonald) + +[Core/MD] +--------------- +* fixed SRAM incompatibilities between BIG ENDIAN & LITTLE ENDIAN platforms (note: this breaks old .srm files with LITTLE ENDIAN platform ports) +* added support for a few recently dumped unlicensed games +* added auto-detection of byte-swapped ROM files + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.3 (26/11/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +no win32/SDL port changes + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.2 (24/11/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added default TOC for Shadow of the Beast II (prevent hangs when audio tracks are missing) +* fixed CD-DA fader muting +* fixed PCM channels panning on reset +* fixed backup RAM file management when using disc swap with Mode 1 cartridge +* incremented CD drive read latency: fixes Space Adventure Cobra (freeze when opening coffin at 2nd morgue scene) +* improved CDD emulation accuracy: fixes Snatcher (freeze at the end of Act 2) & various CD player bugs +* improved MAIN-SUB memory map mirroring in SCD mode (verified on real hardware by Charles McDonald) +* implemented cycle-accurate "stopwatch" register emulation + +[Core/Sound] +--------------- +* fixed broken PSG noise frequency +* fixed incorrect Game Gear PSG stereo emulation +* implemented cycle-accurate Game Gear PSG stereo + +[Core/VDP] +--------------- +* fixed broken VDP DMA from SVP ROM latency (graphic errors in Virtua Racing) + +[Core/MD] +--------------- +* added Super Mario World 64 (unlicensed) cartridge hardware emulation + +[Core/Input] +--------------- +* added automatic detection for CD games with Justifier/Menacer support +* improved Justifier/Menacer emulation + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.1 (13/10/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added support for CUE files +* added CD-DA tracks emulation (needs CUE+BIN or ISO+WAV images) +* added CD fader emulation +* added CDD "Fast FW" & "Fast RW" commands emulation +* improved CDD TOC emulation (random freezes in Sonic CD, Switch/Panic, Final Fight CD and probably many others) +* improved PCM chip synchronization with SUB-CPU (missing speeches in Willy Beamish) +* fixed PCM chip emulation (random hangs in Snatcher, missing sound effects in Switch/Panic, Final Fight CD, Wonderdog...) +* fixed Word-RAM memory mode on soft-reset (missing logo gfx effects) +* fixed SUB-CPU access to unused areas when using PC-relative instructions (Final Fight CD first boss random crash) +* fixed CPU idle loop detection on memory mode register access (Pugsy CD first boss slowdown) +* fixed Mode 1 emulation (cartridge boot mode) + +[Core/Sound] +--------------- +* replaced FIR resampler by Blip Buffer for FM resampling +* modified SN76489 core for use of Blip Buffer +* improved PSG & FM chips synchronization using Blip Buffer +* added Game Gear PSG stereo support +* fixed SG-1000 specific PSG noise +* fixed YM2612 LFO AM waveform (California Games surfing event) +* fixed YM2612 phase precision +* minor optimizations to YM2612 core + +[Core/Game Gear] +--------------- +* added support for CJ Elephant Fugitive (recently released by SMS Power) +* added Game Gear extended screen option + +[Core/Genesis] +--------------- +* added support for a few recently dumped (but unreleased) games + +[Core/General] +--------------- +* improved ROM & CD image file loading +* various code cleanup + + +--------------------------------------------------------------------------------------------------------- +Genesis Plus GX 1.7.0 (01/07/2012) (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/SCD] +--------------- +* added Mega CD / Sega CD hardware emulation (incl. Sub 68K, CDD, CDC, PCM, GFX rotation/scaling, etc) +* added .ISO & .BIN CD image file support +* added 512K backup cartridge RAM support +* added savestate support for CD games + +NOTES: +~~~~~~ +* to play CD games, original BIOS ROM files are required in /genplus/bios/ directory: unzip & rename them to bios_CD_U.bin, bios_CD_E.bin, bios_CD_J.bin +* CD audio tracks (CD-DA) are not supported (yet) + +[Core/CPU] +--------------- +* modified 68k core for Mega CD / Sega CD support +* optimized 68k core using prebuild const tables + +[Core/VDP] +--------------- +* improved DMA accuracy +* improved accuracy of nametables register & VSRAM writes during HBLANK: fixes "The Adventures of Batman & Robin" (graphical issues during 2nd Boss fight). +* added support for 8-bit VRAM writes with undocumented code value (verified on real hardware by Nemesis) + +[Core/Sound] +--------------- +* improved synchronization between SN76489 & YM2162 cores. +* improved accuracy of SN76489 core timings. + +[Core/MD] +--------------- +* added support for some recently dumped unlicensed games. +* improved emulation of 32k bankswitch hardware used by a few unlicensed games. +* fixed behavior of Z80 banked reads from 68k RAM (verified on real hardware). +* fixed support for 128K Pro Action Replay ROM. + +[Core/MS] +--------------- +* added support for all recent korean ROM dumps by SMS Power. +* added emulation of korean multi-game mapper (4-Pak All Action) +* added pseudo-random RAM pattern initialization on Mark-III and Japanese Master System (fixes "Alibaba and 40 Thieves" & "Block Hole") +* added port $3E emulation & internal BOOTROM support (Master System & Game Gear only). + +[Core/General] +--------------- +* added an option to set VDP mode (PAL/NTSC) independently from console region. +* added an option to select original system master clock frequency (PAL/NTSC/AUTO), emulation will run at selected frequency when VSYNC is disabled. +* fixed 68k context loading/saving (Sol Deace). +* fixed C89 incompatibilities for better portability. +* removed use of "long int" type for portability on 64-bit platforms. +* moved savestate zlib compression out of emulation core (for ports that don't use it). +* various optimizations. + +[Gamecube/Wii] +--------------- +* removed ROM load device selection from Load Menu: default ROM device must now be configured in menu settings. +* added specific load buttons, browsers & saved paths for each systems, this also fixes slowdowns caused by screenshot loading when browsing from slow devices. +* added support for left/right buttons as page up/down keys in ROM browsers +* added right analog stick as default "return to menu" key for Gamecube controllers +* added alternate remappable menu key combo for Gamecube controllers +* added an option to disable VSYNC (emulator is synced with audio hardware instead of video). +* added an option to boot system from "BIOS", with or without cartridge. +* added Master System & Game Gear "BIOS" support (files should be named bios_U.sms, bios_J.sms, bios_E.sms & bios.gg and copied to /genplus/bios directory). +* replaced "Hard Reset" button by a Soft Reset for systems having a Reset button (Mega Drive / Genesis & Master System) +* State & SRAM files are now only compressed when saving to Gamecube Memory Cards +* various fixes & cleanup. +* compiled with devkitPPC r26 & libogc 1.8.11. + +[Gamecube] +---------- +* improved progressive mode support when component cable is detected (hold B during startup to switch menu video mode configuration) + + +--------------------------------------------------------------------------------------------------------- +[07/08/2011] version 1.6.0 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/Sound] +--------------- +* added YM2413 emulation in Master System compatibility mode. +* fixed SN76489 noise boost initialization. +* minor YM2612 core optimizations. + +[Core/VDP] +--------------- +* added accurate emulation of SG-1000, Master System (315-5124, 315-5246) & Game Gear VDP. +* added support for all TMS9918 rendering modes. +* improved Mega Drive VDP timings accuracy in Master System Compatibility mode. +* fixed color palette initialization. +* fixed shifted sprites rendering in Mode 4. +* modified pixel rendering support (pixel depth is now forced at compilation time). + +[Core/CPU] +--------------- +* optimized 68k core (rewrote 68k interrupt handling, removed multiple CPU types support & unused code) for 5~8% speed improvment + +[Core/IO] +--------------- +* added accurate emulation of Master System (315-5216, 315-5237, 315-5297) & Game Gear I/O controllers. +* added Terebi Oekaki tablet emulation. +* improved Mouse emulation (fixes mouse support in Cannon Fodder). +* improved Justifier emulation (fixes gun support in Lethal Enforcers 2). +* improved 6-Buttons control pad emulation (fixes Duke Nukem 3D) +* modified lightgun emulation to use common key inputs for all devices. +* 2-buttons controller is now picked by default for Master System games. + +[Core/MD] +--------------- +* added copy-protection hardware emulation for some new dumped games (Tiny Toon Adventures 3, Mighty Morphin Power Rangers & The Battle of Red Cliffs). +* added Game Toshokan in EEPROM database (verified on real cartridge). +* fixed Micro Machines 2 - Turbo Tournament EEPROM size (verified on real cartridge). +* modified SRAM banswitch hardware emulation to be more compatible with some hacks. + +[Core/MS] +--------------- +* added Cyborg Z to Korean mapper database. + +[Core/GG] +--------------- +* added 93C46 EEPROM emulation (Majors Pro Baseball, World Series Baseball & World Series Baseball 95). + +[Core/General] +--------------- +* added support for .mdx ROM format. +* added Game Gear & SG-1000 ROM support. +* added accurate emulation of SG-1000, Master System (I, II) & Game Gear hardware models for 100% compatibility. +* updated to new Genesis Plus license (see http://cgfm2.emuviews.com/) +* removed DOS port +* various code cleanup. + + +--------------------------------------------------------------------------------------------------------- +[31/03/2011] version 1.5.0 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/VDP] +--------------- +* added support for Master System compatibility mode (Z80 ports access mode), incl. Mode 5 rendering. +* added Mode 4 rendering for both Genesis & Master System modes. +* added alternate BG planes rendering functions (should be faster on PPC architectures). + +[Core/IO] +--------------- +* added support for Master System compatibility mode (Z80 ports access mode). +* added Master System peripherals emulation (Control Pad, Paddle, Sports Pad & Light Phaser). +* added XE-1AP (analog controller) emulation. +* added Activator emulation. + +[Core/Extra] +--------------- +* added support for all known Master System cartridge mappers. +* added copy-protection hardware emulation for a few MD unlicensed games: fixes 777 Casino (crash when talking to bunny girls). +(NB: most of those unlicensed games seem to have been already patched by ROM dumpers, main purpose is documenting them) +* added support for Top Shooter arcade board controller. (A=Shoot, B=Bet, C/RIGHT=Coins, START=Start, hold UP on startup to enter service mode) +* improved King of Fighters 98 mapper emulation (registers address decoding is now 100% accurate) +* fixed Game Genie when several codes affect same ROM address. +* fixed EEPROM types for Brian Lara Cricket & NBA Jam TE (verified on real cartridges) + +[Core/General] +--------------- +* added Master System compatibility mode emulation (automatically enabled when loading ROM file with .sms extension). +* improved savestate stability & compatibility (support for old 1.4.x savestates is preserved) +* various code cleanup & comments. + + +--------------------------------------------------------------------------------------------------------- +[04/12/2010] version 1.4.1 (Eke-Eke) +--------------------------------------------------------------------------------------------------------- + +[Core/Sound] +--------------- +* implemented Blargg's blip buffer in SN76489 core (all channels are now lineary interpolated) + +[Core/VDP] +--------------- +* improved 2-cell vscroll emulation accuracy, as verified on real hardware (Gynoug, Cutie Suzuki no Ringside Angel, Formula One, Kawasaki Superbike Challenge) +* improved VBLANK flag accuracy, as observed on real hardware. +* improved DMA operations accuracy, writes are now performed on a scanline basis: fixes Gaiares (flickering title screen). +* improved DMA Fill timing accuracy. +* fixed DMA with bad code values: fixes Williams Arcade Classics (corrupted gfx after soft reset). +* fixed horizontal resolution changes during HBLANK: fixes Bugs Bunny in Double Trouble (2nd stage). +* fixed Vertical Counter in interlace mode 1, as observed on real hardware. +* fixed horizontal border width, as observed on real hardware. +* various code improvments & optimizations. + +[Core/CPU] +--------------- +* fixed state of Z80 registers on reset (sound issues with Defender & Defender 2 in Williams Arcade Classics) +* implemented 68k undocumented flags behavior for DIVU/DIVS instructions (Bloodshot / Battle Frenzy) + +[Core/Extra] +--------------- +* improved emulation of copy-protection hardware found in some unlicensed cartridges (Mulan, Pocket Monsters II). +* enabled simultaneous use of multitap & J-CART (Super Skidmarks 6-player mode) +* improved savestate format: added DMA, SVP, cartridge mapping & internal registers state informations +* improved unlicensed ROM mappers emulation +* added Chinese Fighters III mapper support +* added Top Fighter mapper support +* fixed Barver Battle Saga mapper support +* fixed cartridge hardware soft-reset (Game Genie, SVP, ...) +* fixed Game Genie registers byte reads + + +---------------------------------------------------------------------------------------------------------------------------------------------------- +[06/30/10] version 1.4.0 (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +[Core/Sound] + +* completely rewrote sound processing/mixing: sound chips are now clocked with exact output framerate +to ensure 100% smooth video & audio playback, with no lag or skipping, while rendering an accurate number +of samples per frame and keeping PSG & FM chips in sync. +* improved PSG & FM chips synchronization with CPU execution (fixed point precision). +* improved YM2612 core general accuracy (SSG-EG, CSM mode,...) (based upon Nemesis recent tests on real hardware) +* improved YM2612 LFO emulation accuracy: fixes "Spider-Man & Venom : Separation Anxiety" (intro) +* fixed YM2612 bug with Timer B: fixes "Langrisser Hikari II"/"Der Langrisser II" (Sega logo) +* fixed YM2612 context saving/loading. +* fixed YM2612 state on reset. +* removed outdated & less accurate Gens YM2612 core +* added configurable YM2612 DAC resolution emulation. +* added configurable & faster FIR resampler (thanks to Blargg & AamirM), removed libsamplerate support. +* added configurable Low-Pass filtering +* added configurable 3-Band Equalizer (thanks to Neil C). +* added an option to boost SN76489 Noise Channel. +* adjusted SN76489 cut-off frequency. + + +[Core/VDP] + +* added support for CRAM writes during horizontal blanking (Striker, Zero the Kamikaze Squirrel,...) +* added support for 2-Cell vertical scrolling in Interlaced 2 mode +* added support for some undocumented mode register bits +* added proper emulation of HV Counter latch: fixes Sunset Riders intro +* added pixel-accurate emulation of mid-line display on/off (Nigel Mansell World Championship PAL, Ren & Stimpy's Invention PAL,...) +* improved FIFO timings accuracy: fixes Sol Deace intro +* improved sprite masking accuracy (thanks to Nemesis for his test program) +* improved sprites processing accuracy: fixes (un)masked sprites in Mickey Mania (3D level), Sonic 2 (VS mode). +* improved HBLANK flag timing accuracy: fixes Mega Turrican (Sky level) +* improved horizontal blanking & HINT/VINT occurence timing accuracy, as measured on real hardware. +* improved HCounter accuracy in 40-cell mode, as measured on real hardware. +* improved color accuracy in VDP highlight mode to match results observed on real hardware + + +[Core/CPU] + +* updated Z80 core to last version (fixes interrupt Mode 0 timing and some BIT instructions). +* fixed some Z80 instructions timing. +* improved Z80 interrupt accuracy +* improved 68k accuracy (initial Reset timing + auto-vectored interrupts handling). +* improved 68k timing accuracy for DIVU/DVIS (thanks to Jorge Cwik) & MULU/MULS instructions. +* improved Z80 & 68k cpu execution/synchronization accuracy by using Master Clock as common reference (now run exactly 3420 M-Cycles per line). +* modified Z80 & 68k cores to directly use external cycle count instead of intermediate counters. + + +[Core/Extra] + +* added Game Genie hardware emulation (Game Genie ROM is now fully supported). +* added Action Replay hardware emulation (Action replay ROM is now fully supported). +* added S&K "Lock-On" hardware emulation (you can "lock" any games to Sonic & Knuckles). +* added Cartridge "hot swap" feature. +* added missing EEPROM support in some games. +* added accurate TMSS emulation (VDP lock-out) +* fixed Realtec mapper emulation: fixes missing sound in Balloon Boy / Funny World. +* fixed lightgun auto-detection: fixes default cursor position in Lethal Enforcers II. +* lots of code cleanup, bugfixes & optimization. + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [12/14/08] version 1.3.0 (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* YM2612 bugfixes (MAME core): + .fixed EG Decay->Substain transition when SL & DR are minimals: fix tracks #3 and #9 in "Mega Turrican" + .fixed a bug in SSG-EG emulation code: fix Level 1 music in "Alisia Dragoon" + .modified SSG-EG Decay End Level: fix some sound effects (ChainSaw, Zap...) in "Beavis & Butthead" + .improved Detune overflow accuracy: fix very high frequency sounds in many games + .fixed registers 0x20-0x26 Reset state: fix intro music in "B.O.B" + .reverted incorrect fix with KEY ON: fix "Flamethrower" sound effect in "Alien 3" and many others +* adjusted HCounter values: fixes line flickering in "Sonic 3D" bonus stage +* adjusted VINT timing: fixes hang-up in "V.R Troopers" +* improved HBLANK flag accuracy: fixes line flickering in "Gouketsuji Ichizoku" +* fixed broken Z80 access to WRAM: fixes hang-up in "Mamono Hunter Youko" +* modified JCART emulation: fixes corrupted tracks logo in "Micro Machines 2" +* added Blargg's NTSC Filters support (NTSC video artifacts emulation) +* optimized VDP rendering core, rewrote 68k interface (memory handlers, cycle execution, interrupts): greatly improved emulation speed + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [08/26/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* YM2612(MAME): fixed LFO phase update for CH3 special mode: fix sound effects in Warlock & Aladdin (thanks to AamirM) +* YM2612(MAME): fixed EG attenuation level on "KEY ON": fix Ecco 2's splash sound +* YM2612(MAME): fixed SSG-EG emulation: fix Bubba'n Stix (Track 5) and many others +* YM2612(MAME): replaced sample interpolation with libsamplerate support, High Quality mode is now more accurate +* implemented cycle-accurate HINT timings: every timing sensitive games/demos are now *finally* working fine +* fixed a bug affecting CRAM/VSRAM DMA timings +* fixed Sprite Attribute Table address mask for VRAM writes +* improved accuracy of 68k access to Z80: fix music in Pacman 2 when entering PAUSE menu +* disabled "Address Error" emulation when UMK3 hack is loaded: fix game crashing after a round ends up +* added support for some more unlicensed games: Pocket Monster, King of Fighter 98, Soul Blade (credits to Haze) +* improved Menacer emulation: fix lightgun support in Body Count & T2: The Arcade Game +* added Konami Justifier emulation: fix lightgun support in Lethal Enforcers 1 & 2 +* added Sega Mouse emulation (Populous 2, Body Count, Shangai 2, Fun'n Games, ...) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [07/16/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* adjusted (again) HINT timings: fix Double Dragon 2 (game freezed), hopefully does not break anything else +* fixed broken EEPROM support for Codemaster games +* modified input update timings: fix Dungeons & Dragons * Warriors of the Eternal Sun (thanks to Notaz) +* added support for "Ultimate Mortal Kombat Trilogy" hack (max. size supported is 10MBytes) +* added (VERY) preliminar support for PICO roms (credits to Notaz for his documentation) +* improved YM2612 emulation (credits to Nemesis for his tests on real hardware): + .implemented phase overflow emulation: improved fix for special music instrument used in Comix Zone, Flashback, Ariel, Shaq Fu... + .improved SSG-EG emulation in MAME core (also based on additional code from Alone Coder) + .improved Timers emulation accuracy + .improved Enveloppe Generator accuracy + .fixed Channel 3 CSM mode emulation + .implemented sample interpolation in MAME core to emulate the chip at original frequency (HQ YM2612 mode, from gens) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [06/01/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* improved HCounter accuracy: fix graphic glitches in "Striker (Europe)" +* improved HINT timing accuracy: fix flickering in "Zero The Kamikaze Squirrel (USA)" +* improved rendering accuracy when backdrop color is modified during HBLANK (Road Rash I/II/III) +* fixed broken Game Genie support + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [04/19/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* modified VINT timings a little bit: fix lockup during Desert Strike's intro +* corrected 68k interrupts handling: fix graphic glitches in Darius II/Sagaia + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [04/06/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* updated SVP core: fix some perspective issues in Virtua Racing (thanks to Notaz) +* added internal SAT update during VRAM Fill: fix unmasked sprites during Battletech's intro +* fixed m68k core issues with gcc 4.2.3: fix Xperts, Lemmings 2, M1 Abrams Battle Tank +* forced YM2612 Enveloppe update: fix intro music in Batman&Robin (thanks to Aamir) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [03/01/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* added SVP emulation: Virtua Racing is now emulated (big thanks to Notaz and TascoDeluxe) +* fixed VDP registers behaviour when VDP Mode 4 is enabled: fix Bass Masters Classic Pro, Captain Planet & The Planeeters +* corrected a bug in DMA Fill operation: fix James Pond 3, Rockman World/Megaman Willy Wars (corrupted VRAM) +* corrected typo errors in CPU cycle counters update: fix optiom screen music in "College Slam" and probably others games. +* added preliminary support of undocumented YM2612 bug: fixes soundtracks of Shaq Fu, Spiderman, Comix Zone, Ariel and some others +* added support for mappers & copy protection devices used in many unlicensed/pirate cartridges (see cart_hw.c for details) +* rewrote memory handlers for better modularity and some (little) speedup +* reduced Savestate size + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [01/07/08] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* fixed interleaved rom detection: roms with .smd extension should now work fine +* fixed a recently introduced bug in VDP registers writes: fixes bad colors in Toy Story (intro) +* updated list of games using EEPROM: added Sports Talk Baseball (internal memory check fixed) and Brian Lara Cricket +* fixed VINT flag update when VINT is disabled: fixes NCAA College Football +* adjusted DMA timings in H32 mode: fixes flickering in Out of this World, Kawasaki Superbike Challenge & Formula One +* adjusted line rendering and HBLANK timings: fixes flickering in Nigel Mansell's World Championship Racing, Deadly Moves/Power Athlete +* fixed unmapped ROM reads through Z80 Bank: fixes Zombie High (Proto) +* added support for custom ROM/RAM mapping used by Game no Kanzume Otokuyou + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [12/28/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* many sourcecode cleanup and optimization +* completely rewrote EEPROM emulation: now support all known EEPROM types (24C01-24C65) and mappers (Sega, Acclaim, EA, Codemasters) +used in a few games (now use internal game database) as external RAM. This should at least fix save support in the following games: + . NBA Jam (alternate Acclaim mapper) + . College Slam, Frank Thomas Big Hurt Baseball (24C65 type) + . NHLPA Hockey 93, Rings of Power (EA mapper) + . Micro Machines serie, Brian Lara Cricket 96/Shane Warne Cricket (Codemasters mapper) +* external RAM is now initialized to 0xFF by default: fix Micromachines 2, Dino Dini Soccer +* fixed SRAM 16-bits memory handlers: fix some Sega Sports and EA Sports games (NFL95, NBA Action 95, NHL97, NHL98,...) +* modified WRITE_xxx & READ_xxx macros for better portability and faster memory access on BIG ENDIAN platform +* completely rewrote BIG ENDIAN support in render.c and vdp.c: rendering should be a little faster +* rewrote ROM bankswitch emulation (Super Street Fighter II): ROM access are faster, using memory pointers instead of reading ROM copy from ARAM +* fixed leftmost Window/PlaneA column render and implemented Window bug (as described by Charles Mc Donald) +* improved "Sprite Limit" and "Sprite Collision" detection accuracy +* modified RGB565 Color Palette to use the full available color range (0-31;0-63) +* implemented "cycle accurate" HV Interrupt timings: fix Sesame's Street Counting Cafe, Legend of Galahad (intro) +* improved VDP access timings accuracy (added FIFO emulation): fix Double Clutch +* improved DMA timings accuracy: fix Winter Olympics (E), Arch Rivals and probably more +* fixed HCounter again: Road Rash serie (I,II,III) don't need timing hacks anymore +* fixed VCounter in Interlaced 2 mode: fix Combat Cars "VS-Mode" +* improved Interlaced 2 mode (double resolution) rendering: Sonic 2, Combat Cars ("VS-Modes") look far better +* added TMSS BIOS support (optional) +* rewrote part of the YM2162 MAME's core: fixed internal FM timers handling, removed non-YM2612 emulation code and unused multiple cpu support +* implemented "cycle accurate" FM timers & sound samples rendering +* improved Z80 Interrupt timing accuracy: fix Sonic 3 music slowdowns +* updated Z80 & 68000 cores to last MAME versions +* improved Soft Reset emulation: X-Men 2 and Eternal Champions (random character selection) now work more like on real hardware. +* added full overscan emulation (vertical & horizontal borders) for "pixel perfect" aspect ratio (tested against a real genesis) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [07/20/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* corrected TeamPlayer support: fix multiplayer in Gauntlet 4 (Sept. version), Pengo and a lot of others +* added J-Cart support: enable multiplayer in Codemasters games (Pete Sampras, Micromachines games, Super Skidmarks) +* added serial EEPROM autodetection: fix games with bad SRAM informations in header (NBA Jam TE) +* added SVP faking: display 2D graphics in Virtua Racing (the game is however still unplayable) +* added support for more internal IO registers: fixe some unlicensed games (Wisdom Tree games...) +* added preliminary support for unmapped protection device: fix some unlicensed games with special built-in hardware (Squirell King, Lion King 2...) +* added "Soft Reset" combo (in game, use L+Z triggers): this should be like pressing the RESET button on a real Genesis and this is required + in some games to enable special features or even complete the game (ex: X-Men). + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [06/21/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* added Multitap support (EA 4-Way Play and Sega Teamplayer): allowed up to four players in games supporting those peripherals +* added partial Sega Menacer lightgun support (use Analog Stick): automatically set when detecting the 6-in-1 Menacer game + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [05/18/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* you can now switch between FM cores without reseting the game. FM registers value are automatically restored when switching. +* removed the previous VINT timings modification because it brokes some games (Rocket Knight, Thunderforce III,...) +* added automatic Timing configuration (VDP latency, VINT timing & alternate Line Timing) at game loading, based upon specific romname detection. +This means you can still modify some of these options afterwards but they are now automatically set/unset when loading a game which need +special timing fixes. These fixes are also automatically desactivated when the current game doesn't need them. +For information, games that are actually detected and need special timings to run properly are: + .Legend of Galahad & Road Rash series (single line not rendered properly) + .Sesame Street Counting Cafe (don't boot) + .Chaos Engine/Soldiers of Fortune (graphic glitches on scrolling) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [05/08/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* VINT timings are now a little more accurate: fixes Sesame's Street Counting Cafe +* SN76496 MAX_OUTPUT back to normal +* modified FB_WNOISE value in SN76496 core according to John Kortink's last informations +* added support for Maxim's PSG core, same as used in SMSPLUS (it becomes the default PSG core) +* updated FM core to the latest MAME version +* corrected DAC output level (fixes voices and some special FX being too low) +* added support for Gens YM2612 (FM) core (MAME's one still remains default FM core) +* added configurable preamplification for each sound cores (see Emulator Options) +* added some other configurable sound options (boost overall volume, FM improvment for Gens YM2612) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [04/11/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* corrected MAX_OUTPUT value in SN76496 core: fix PSG sound (SFX) volume + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [03/17/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + + * added an option to enable alternate line rendering timing (fix single line error in Road Rash series and Legend of Galahad's Intro) + * Color RAM update now always reset color 0 to border color (fix color glitches in Mortal Kombat,...) (thanks to Noop's for the idea) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [03/09/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* modified HV counter tables (fix graphic glitches in Skitchin's sky, Lotus 2 Recs, Panorama Cotton, Dashin Desperados & maybe more) +* completely rewrote DMA timings emulation so that it works for all games (no more cpu freezing) +* added all DMA tranfer rates handling for each three DMA modes and added dma busy flag emulation +* modified interrupts handling on VDP register #0 and #1 writes (fix Lemmings status bar) +* added VDP RAM write latency (fix Chaos Engine/Soldier of Fortune gfx glitches) +* modified FM timers handling a bit (fix Vectorman2 music) +* corrected Sprite Limit rendering (fix Sonic 1 & Micromachines 2 title screens) +* corrected IO Registers writes (fix Decap' Attack controls, no more need for alternate input) +* corrected 6 Buttons Pad emulation (fix 6buttons detection in Mortal Kombat 3, Comix Zone and other 6-buttons compatible games) +* modified sound mixing a bit according to Generator sourcecode (FM and PSG ratios seems more correct) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [02/07/07] (Eke-Eke) +---------------------------------------------------------------------------------------------------------------------------------------------------- + +* fixed fm timers (fix missing music in Castle of Illusion, Quackshot, Undead Line, Wonderboy in Monster Lair, Cal 50, Turbo Outrun, Thundeforce 4 and maybe more) +* added complete EEPROM emulation (save support now works fine in Wonderboy5, Megaman Willy Wars, NBA Jam...) (credits to Notaz, adapted from Picodrive code) +* added preliminar dma timing emulation (fix bottom screen in Legend of Galahad) (credits to Notaz, adapted from Picodrive code) +* hack: clear Vint pending after Hint (INT level 4) acknowledge (fix Fatal Rewind) +* hack: modify read_bus16 to return a random value (fake fetch) (fix Time Killers) +* modified cpu execution timings, with more correct hblank and interrupts timing (fix ISS Deluxe, Double Dragon 2 and certainly more) (Based on Gens code) +* modified busreq mechanism: better synchro between z80 & 68k (no need to dejitter anymore) (Based on Gens code) +* added sprite collision detection (fix Strider 2) +* modified dma fill operation for big endian platform (fix Contra Hardcorps gfx garbage) + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [05/25/03] (Charles MacDonald) +---------------------------------------------------------------------------------------------------------------------------------------------------- + + * Fixed a typo that made Z80 banked access to the VDP registers always fail. + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [05/17/03] (Charles MacDonald) +---------------------------------------------------------------------------------------------------------------------------------------------------- + + * Modified the rendering code to handle unaligned longword access to memory. + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [04/20/03] (Charles MacDonald) +---------------------------------------------------------------------------------------------------------------------------------------------------- + + * Modified 68000 emulator to prevent 'tas.b $mem' from writing data back + after a read (fixes Gargoyles). + * Fixed bug in 68000 emulator to swap order of words written for address + register indirect pre-decremented writes (fixes Jim Power graphics). + * Added support for 240-line displays (for Super Skidmarks). + * Rewrote part of the interrupt handling (fixes some raster effects). + * Removed sprite collision detection code (never really worked). + * Optimized sprite rendering inner loop. + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [04/13/03] (Charles MacDonald) +---------------------------------------------------------------------------------------------------------------------------------------------------- + * Finished up memory map for VDP DMA V-bus reads. + * Fixed handling of 68000 writes to I/O chip at even addresses. + * Fixed bit 7 handling of control register in I/O chip. + * Finished up Z80 memory map. + * Added code to handle Genesis hardware lock-ups. + * Removed some faulty code from the 68000 memory map handlers. + + +---------------------------------------------------------------------------------------------------------------------------------------------------- + [03/22/03] (Charles MacDonald) +---------------------------------------------------------------------------------------------------------------------------------------------------- + + * Completed implementation of Z80 banked memory handlers. + diff --git a/sdl2/Makefile b/sdl2/Makefile new file mode 100644 index 0000000..0c202e7 --- /dev/null +++ b/sdl2/Makefile @@ -0,0 +1,182 @@ + +# Makefile for genplus SDL2 +# +# (c) 1999, 2000, 2001, 2002, 2003 Charles MacDonald +# modified by Eke-Eke +# +# Defines : +# -DLSB_FIRST : for little endian systems. +# -DLOGERROR : enable message logging +# -DLOGVDP : enable VDP debug messages +# -DLOGSOUND : enable AUDIO debug messages +# -DLOG_SCD : enable SCD debug messages +# -DLOG_CDD : enable CDD debug messages +# -DLOG_CDC : enable CDC debug messages +# -DLOG_PCM : enable PCM debug messages +# -DLOGSOUND : enable AUDIO debug messages +# -D8BPP_RENDERING - configure for 8-bit pixels (RGB332) +# -D15BPP_RENDERING - configure for 15-bit pixels (RGB555) +# -D16BPP_RENDERING - configure for 16-bit pixels (RGB565) +# -D32BPP_RENDERING - configure for 32-bit pixels (RGB888) + +ifeq ($(OS),Windows_NT) +NAME = gen_sdl2.exe +else +NAME = gen_sdl2 +endif + +CC = gcc +CFLAGS = `sdl2-config --cflags` -march=i686 -O6 -fomit-frame-pointer -Wall -Wno-strict-aliasing -ansi -std=c99 -pedantic-errors +#-g -ggdb -pg +#-fomit-frame-pointer +#LDFLAGS = -pg +DEFINES = -DLSB_FIRST -DUSE_16BPP_RENDERING -DUSE_LIBTREMOR -DMAXROMSIZE=33554432 + +SRCDIR = ../core +INCLUDES = -I$(SRCDIR) -I$(SRCDIR)/z80 -I$(SRCDIR)/m68k -I$(SRCDIR)/sound -I$(SRCDIR)/input_hw -I$(SRCDIR)/cart_hw -I$(SRCDIR)/cart_hw/svp -I$(SRCDIR)/cd_hw -I$(SRCDIR)/ntsc -I$(SRCDIR)/tremor -I$(SRCDIR)/../sdl2 +LIBS = `sdl2-config --libs` -lz -lm + +OBJDIR = ./build_sdl2 + +OBJECTS = $(OBJDIR)/z80.o + +OBJECTS += $(OBJDIR)/m68kcpu.o \ + $(OBJDIR)/s68kcpu.o + +OBJECTS += $(OBJDIR)/genesis.o \ + $(OBJDIR)/vdp_ctrl.o \ + $(OBJDIR)/vdp_render.o \ + $(OBJDIR)/system.o \ + $(OBJDIR)/io_ctrl.o \ + $(OBJDIR)/mem68k.o \ + $(OBJDIR)/memz80.o \ + $(OBJDIR)/membnk.o \ + $(OBJDIR)/state.o \ + $(OBJDIR)/loadrom.o + +OBJECTS += $(OBJDIR)/input.o \ + $(OBJDIR)/gamepad.o \ + $(OBJDIR)/lightgun.o \ + $(OBJDIR)/mouse.o \ + $(OBJDIR)/activator.o \ + $(OBJDIR)/xe_1ap.o \ + $(OBJDIR)/teamplayer.o \ + $(OBJDIR)/paddle.o \ + $(OBJDIR)/sportspad.o \ + $(OBJDIR)/terebi_oekaki.o \ + $(OBJDIR)/graphic_board.o + +OBJECTS += $(OBJDIR)/sound.o \ + $(OBJDIR)/sn76489.o \ + $(OBJDIR)/ym2413.o \ + $(OBJDIR)/ym2612.o + +OBJECTS += $(OBJDIR)/blip_buf.o + +OBJECTS += $(OBJDIR)/eq.o + +OBJECTS += $(OBJDIR)/sram.o \ + $(OBJDIR)/svp.o \ + $(OBJDIR)/ssp16.o \ + $(OBJDIR)/ggenie.o \ + $(OBJDIR)/areplay.o \ + $(OBJDIR)/eeprom_93c.o \ + $(OBJDIR)/eeprom_i2c.o \ + $(OBJDIR)/eeprom_spi.o \ + $(OBJDIR)/md_cart.o \ + $(OBJDIR)/sms_cart.o + +OBJECTS += $(OBJDIR)/scd.o \ + $(OBJDIR)/cdd.o \ + $(OBJDIR)/cdc.o \ + $(OBJDIR)/gfx.o \ + $(OBJDIR)/pcm.o \ + $(OBJDIR)/cd_cart.o + +OBJECTS += $(OBJDIR)/sms_ntsc.o \ + $(OBJDIR)/md_ntsc.o + +OBJECTS += $(OBJDIR)/main.o \ + $(OBJDIR)/config.o \ + $(OBJDIR)/error.o \ + $(OBJDIR)/unzip.o \ + $(OBJDIR)/fileio.o + +OBJECTS += $(OBJDIR)/bitwise.o \ + $(OBJDIR)/block.o \ + $(OBJDIR)/codebook.o \ + $(OBJDIR)/floor0.o \ + $(OBJDIR)/floor1.o \ + $(OBJDIR)/framing.o \ + $(OBJDIR)/info.o \ + $(OBJDIR)/mapping0.o \ + $(OBJDIR)/mdct.o \ + $(OBJDIR)/registry.o \ + $(OBJDIR)/res012.o \ + $(OBJDIR)/sharedbook.o \ + $(OBJDIR)/synthesis.o \ + $(OBJDIR)/vorbisfile.o \ + $(OBJDIR)/window.o + +ifeq ($(OS),Windows_NT) +OBJECTS += $(OBJDIR)/icon.o +endif + +all: $(NAME) + +$(NAME): $(OBJDIR) $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@ + +$(OBJDIR) : + @[ -d $@ ] || mkdir -p $@ + +$(OBJDIR)/%.o : $(SRCDIR)/%.c $(SRCDIR)/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/sound/%.c $(SRCDIR)/sound/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/input_hw/%.c $(SRCDIR)/input_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/%.c $(SRCDIR)/cart_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cart_hw/svp/%.c $(SRCDIR)/cart_hw/svp/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/cd_hw/%.c $(SRCDIR)/cd_hw/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/z80/%.c $(SRCDIR)/z80/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/m68k/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/ntsc/%.c $(SRCDIR)/ntsc/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c $(SRCDIR)/tremor/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/tremor/%.c + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +$(OBJDIR)/%.o : $(SRCDIR)/../sdl2/%.c $(SRCDIR)/../sdl2/%.h + $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) $< -o $@ + +ifeq ($(OS),Windows_NT) +$(OBJDIR)/icon.o : + windres $(SRCDIR)/../sdl2/icon.rc $@ +endif + +pack : + strip $(NAME) + upx -9 $(NAME) + +clean: + rm -f $(OBJECTS) $(NAME) diff --git a/sdl2/README.txt b/sdl2/README.txt new file mode 100644 index 0000000..5bf6f7d --- /dev/null +++ b/sdl2/README.txt @@ -0,0 +1,146 @@ + +DISCLAIMER: + +THIS IS A VERY BASIC & UNSTABLE PORT WHICH ONLY PURPOSE +IS TO SHOW HOW TO USE GENESIS PLUS GX CORE & INTERFACE IT +WITH SDL2 IN PARTICULAR. BUILDS ARE NOT MEANT TO BE REALLY +USED FOR ANYTHING ELSE BUT EASIER CORE DEBUGGING ON WINDOWS. +PLEASE DO NOT DISTRIBUTE WIN32 BINARIES WITHOUT THIS NOTICE. +END USERS SHOULD PREFERABLY USE LIBRETRO PORT WITH RETROARCH. + +---------------------------------------------------------------------------- + Genesis Plus (SDL2 Port) +---------------------------------------------------------------------------- + + based on the original version 1.3 + by Charles Mac Donald + WWW: http://cgfm2.emuviews.com + + version 1.7.4 + backported from Genesis Plus GX + by Eke-Eke + WWW: http://code.google.com/p/genplus-gx + E-mail: ekeeke31@gmail.com + + + What's New + ---------- + + see CHANGELOG.txt + + + Features + --------- + + * accurate emulation of SG-1000, Mark-III, Master System (I & II), Game Gear, Genesis / Mega Drive, Sega / Mega CD hardware models (incl. backwards compatibility modes) + * NTSC (60Hz) & PAL (50Hz) video hardware emulation + * accurate CDD, CDC & GFX chip emulation (Sega/Mega CD) + * CD-DA fader emulation (Sega/Mega CD) + * Mode 1 cartridge support (Sega/Mega CD) + * highly accurate 68000 & Z80 CPU emulation + * highly accurate VDP emulation (all rendering modes, mid-line changes, undocumented registers,…) & timings (HBLANK, DMA, FIFO, HV interrupts,…) + * sample-accurate YM2612,YM2413, PSG, & PCM emulation (all sound chips are running at the original frequency) + * cycle-accurate chip synchronization (68000’s/Z80/YM2612/PSG/PCM) + * high-quality audio resampling using Blip Buffer + * basic hardware latency emulation (VDP/68k, Z80/68k) + * full overscan area emulation (horizontal & vertical color borders) + * optional Game Gear extended screen mode + * internal BOOT ROM support (Master System, Genesis / Mega Drive, Sega / Mega CD) + * optional TMSS hardware emulation (Genesis / Mega Drive) + * support for Blargg's software NTSC filters + * preliminary PICO emulation + * support for raw (.bin, .gen, .md, .sms, .gg & .sg) and interleaved (.smd & .mdx) ROM files + * support for CUE+BIN, ISO+OGG & ISO+WAV CD image files + * 2-buttons, 3-buttons & 6-buttons controllers emulation + * Sega Team Player & EA 4-Way Play multitaps emulation + * Sega Mouse emulation + * Sega Paddle Control & Sports Pad analog emulation + * Terebi Oekaki tablet emulation + * Sega Light Phaser, Menacer & Justifiers lightgun emulation + * Sega Activator & XE-1AP analog controller emulation + * SVP DSP (Virtua Racing) emulation + * J-Cart adapter (Micro Machines & Pete Sampras series, Super Skidmarks) emulation + * Backup RAM (max. 64KB), I2C (24Cxx), SPI (95xxx) & MicroWire (93C46) EEPROMs emulation + * Sega/Mega CD RAM cart (max. 512KB) emulation + * “official” ROM bankswitch hardware (Super Street Fighter 2) emulation + * “official” backup RAM bankswitch hardware (Phantasy Star 4, Legend of Thor, Sonic the Hedgehog 3) emulation + * support for all known unlicensed/pirate cartridges bankswitch & copy protection hardware + * emulation of all known Master System & Game Gear cartridge “mappers” (incl. unlicensed Korean ones) + * Game Genie & Action Replay hardware emulation + * Sonic & Knuckles “Lock-On” hardware emulation + * support for ROM image up to 10MB (Ultimate MK3 hack) + + + Usage + ----- + + The Windows version runs windowed in a 16-bit desktop with 48Hz sound using SDL but + without joystick support. + + + Controls + ----- + + Arrow Keys - Directional pad + A/Q,S,D,F - buttons A, B(1), C(2), START + W,X,C,V - buttons X, Y, Z, MODE if 6-buttons controller is enabled + Tab - Hard Reset + Esc - Exit program + + F2 - Toggle Fullscreen/Windowed mode + F4 - Toggle Audio (Turbo mode must be disabled first) + F6 - Toggle Turbo mode (Audio must be disabled first) + F7 - Load Savestate (game.gpz) + F8 - Save Savestate (game.gpz) + F9 - Toggle VDP mode: PAL(50hz)/NTSC(60hz) + F10 - Soft Reset + F11 - Toggle Border emulation + F12 - Toggle Player # (test only) + + + The mouse is used for lightguns, Sega Mouse, PICO & Terebi Oekaki tablet (automatically detected when loading supported game). + + A SRAM file (game.srm) is automatically saved on exit and loaded on startup. + + + Credits + -------- + + Core(s) improvements & additional features by Eke-Eke + + Original code by Charles MacDonald + + Original Z80 core by Juergen Buchmueller + + Original Musashi 68k core by Karl Stenerud + + Original YM2612/YM2413 cores by Jarek Burczynski & Tatsuyuki Satoh + + Original SN76489 core by Maxim + + Original SVP core by Notaz + + Blip Buffer & NTSC Video filter libraries by Shay Green (Blargg) + + 3-Band EQ implementation by Neil C + + TREMOR VORBIS decoding library by Xiph.org + + Zlib by Jean-Loup Gailly & Mark Adler + + + Aknowledgements + ---------------- + + The following emulator authors: Bart Trzynadlowski, Steve Snake, Stef, Notaz, AamirM + + The regular people at spritesmind.net and smspower.org. + + The MAME team for the CPU and sound chip emulators. + + Nemesis for the researches on the YM2612 and VDP. + + Tasco Deluxe for the documentation of Realtec mapper. + + Haze for the reverse-engineering of many unlicensed games protection. + diff --git a/sdl2/config.c b/sdl2/config.c new file mode 100644 index 0000000..99aa1e8 --- /dev/null +++ b/sdl2/config.c @@ -0,0 +1,55 @@ + +#include "osd.h" + +t_config config; + + +void set_config_defaults(void) +{ + int i; + + /* sound options */ + config.psg_preamp = 150; + config.fm_preamp = 100; + config.hq_fm = 1; + config.psgBoostNoise = 1; + config.filter = 1; + config.low_freq = 200; + config.high_freq = 8000; + config.lg = 1.0; + config.mg = 1.0; + config.hg = 1.0; + config.lp_range = 0x9999; /* 0.6 in 16.16 fixed point */ + config.dac_bits = 14; + config.ym2413 = 2; /* = AUTO (0 = always OFF, 1 = always ON) */ + config.mono = 0; + + /* system options */ + config.system = 0; /* = AUTO (or SYSTEM_SG, SYSTEM_MARKIII, SYSTEM_SMS, SYSTEM_SMS2, SYSTEM_GG, SYSTEM_MD) */ + config.region_detect = 0; /* = AUTO (1 = USA, 2 = EUROPE, 3 = JAPAN/NTSC, 4 = JAPAN/PAL) */ + config.vdp_mode = 0; /* = AUTO (1 = NTSC, 2 = PAL) */ + config.master_clock = 0; /* = AUTO (1 = NTSC, 2 = PAL) */ + config.force_dtack = 0; + config.addr_error = 1; + config.bios = 0; + config.lock_on = 0; /* = OFF (can be TYPE_SK, TYPE_GG & TYPE_AR) */ + config.ntsc = 0; + config.lcd = 0; /* 0.8 fixed point */ + + /* display options */ + config.overscan = 0; /* 3 = all borders (0 = no borders , 1 = vertical borders only, 2 = horizontal borders only) */ + config.gg_extra = 0; /* 1 = show extended Game Gear screen (256x192) */ + config.render = 0; /* 1 = double resolution output (only when interlaced mode 2 is enabled) */ + + /* controllers options */ + input.system[0] = SYSTEM_GAMEPAD; + input.system[1] = SYSTEM_GAMEPAD; + config.gun_cursor[0] = 1; + config.gun_cursor[1] = 1; + config.invert_mouse = 0; + for (i=0;i + +static int check_zip(char *filename); + +int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension) +{ + int size = 0; + + if(check_zip(filename)) + { + unz_file_info info; + int ret = 0; + char fname[256]; + + /* Attempt to open the archive */ + unzFile *fd = unzOpen(filename); + if (!fd) return 0; + + /* Go to first file in archive */ + ret = unzGoToFirstFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Get file informations and update filename */ + ret = unzGetCurrentFileInfo(fd, &info, fname, 256, NULL, 0, NULL, 0); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Compressed filename extension */ + if (extension) + { + strncpy(extension, &fname[strlen(fname) - 3], 3); + extension[3] = 0; + } + + /* Open the file for reading */ + ret = unzOpenCurrentFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Retrieve uncompressed file size */ + size = info.uncompressed_size; + if(size > maxsize) + { + size = maxsize; + } + + /* Read (decompress) the file */ + ret = unzReadCurrentFile(fd, buffer, size); + if(ret != size) + { + unzCloseCurrentFile(fd); + unzClose(fd); + return 0; + } + + /* Close the current file */ + ret = unzCloseCurrentFile(fd); + if(ret != UNZ_OK) + { + unzClose(fd); + return 0; + } + + /* Close the archive */ + ret = unzClose(fd); + if(ret != UNZ_OK) return 0; + } + else + { + /* Open file */ + gzFile gd = gzopen(filename, "rb"); + if (!gd) return 0; + + /* Read file data */ + size = gzread(gd, buffer, maxsize); + + /* filename extension */ + if (extension) + { + strncpy(extension, &filename[strlen(filename) - 3], 3); + extension[3] = 0; + } + + /* Close file */ + gzclose(gd); + } + + /* Return loaded ROM size */ + return size; +} + +/* + Verifies if a file is a ZIP archive or not. + Returns: 1= ZIP archive, 0= not a ZIP archive +*/ +static int check_zip(char *filename) +{ + uint8 buf[2]; + FILE *fd = fopen(filename, "rb"); + if(!fd) return (0); + fread(buf, 2, 1, fd); + fclose(fd); + if(memcmp(buf, "PK", 2) == 0) return (1); + return (0); +} diff --git a/sdl2/fileio.h b/sdl2/fileio.h new file mode 100644 index 0000000..30db2e0 --- /dev/null +++ b/sdl2/fileio.h @@ -0,0 +1,48 @@ +/* + * fileio.c + * + * Load a normal file, or ZIP/GZ archive. + * Returns loaded ROM size (zero if an error occured) + * + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald + * modified by Eke-Eke (Genesis Plus GX) + * + * Redistribution and use of this code or any derivative works are permitted + * provided that the following conditions are met: + * + * - Redistributions may not be sold, nor may they be used in a commercial + * product or activity. + * + * - Redistributions that are modified from the original source must include the + * complete source code, including the source code for all components used by a + * binary built from the modified sources. However, as a special exception, the + * source code distributed need not include anything that is normally distributed + * (in either source or binary form) with the major components (compiler, kernel, + * and so on) of the operating system on which the executable runs, unless that + * component itself accompanies the executable. + * + * - Redistributions must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************************/ + +#ifndef _FILEIO_H_ +#define _FILEIO_H_ + +/* Function prototypes */ +extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension); + +#endif /* _FILEIO_H_ */ diff --git a/sdl2/icon.rc b/sdl2/icon.rc new file mode 100644 index 0000000..0b47594 --- /dev/null +++ b/sdl2/icon.rc @@ -0,0 +1 @@ +MAINICON ICON "md.ico" diff --git a/sdl2/main.c b/sdl2/main.c new file mode 100644 index 0000000..c886fa0 --- /dev/null +++ b/sdl2/main.c @@ -0,0 +1,953 @@ +#ifdef __WIN32__ +#include +#else +#define MessageBox(owner, text, caption, type) printf("%s: %s\n", caption, text) +#endif + +#include "SDL.h" +#include "SDL_thread.h" + +#include "shared.h" +#include "sms_ntsc.h" +#include "md_ntsc.h" + +#define SOUND_FREQUENCY 48000 +#define SOUND_SAMPLES_SIZE 2048 + +#define VIDEO_WIDTH 320 +#define VIDEO_HEIGHT 240 + +int joynum = 0; + +int log_error = 0; +int debug_on = 0; +int turbo_mode = 0; +int use_sound = 1; +int fullscreen = 0; /* SDL_FULLSCREEN */ + +/* sound */ + +struct { + char* current_pos; + char* buffer; + int current_emulated_samples; +} sdl_sound; + + +static uint8 brm_format[0x40] = +{ + 0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x5f,0x00,0x00,0x00,0x00,0x40, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x53,0x45,0x47,0x41,0x5f,0x43,0x44,0x5f,0x52,0x4f,0x4d,0x00,0x01,0x00,0x00,0x00, + 0x52,0x41,0x4d,0x5f,0x43,0x41,0x52,0x54,0x52,0x49,0x44,0x47,0x45,0x5f,0x5f,0x5f +}; + + +static short soundframe[SOUND_SAMPLES_SIZE]; + +static void sdl_sound_callback(void *userdata, Uint8 *stream, int len) +{ + if(sdl_sound.current_emulated_samples < len) { + memset(stream, 0, len); + } + else { + memcpy(stream, sdl_sound.buffer, len); + /* loop to compensate desync */ + do { + sdl_sound.current_emulated_samples -= len; + } while(sdl_sound.current_emulated_samples > 2 * len); + memcpy(sdl_sound.buffer, + sdl_sound.current_pos - sdl_sound.current_emulated_samples, + sdl_sound.current_emulated_samples); + sdl_sound.current_pos = sdl_sound.buffer + sdl_sound.current_emulated_samples; + } +} + +static int sdl_sound_init() +{ + int n; + SDL_AudioSpec as_desired, as_obtained; + + if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + MessageBox(NULL, "SDL Audio initialization failed", "Error", 0); + return 0; + } + + as_desired.freq = SOUND_FREQUENCY; + as_desired.format = AUDIO_S16LSB; + as_desired.channels = 2; + as_desired.samples = SOUND_SAMPLES_SIZE; + as_desired.callback = sdl_sound_callback; + + if(SDL_OpenAudio(&as_desired, &as_obtained) == -1) { + MessageBox(NULL, "SDL Audio open failed", "Error", 0); + return 0; + } + + if(as_desired.samples != as_obtained.samples) { + MessageBox(NULL, "SDL Audio wrong setup", "Error", 0); + return 0; + } + + sdl_sound.current_emulated_samples = 0; + n = SOUND_SAMPLES_SIZE * 2 * sizeof(short) * 20; + sdl_sound.buffer = (char*)malloc(n); + if(!sdl_sound.buffer) { + MessageBox(NULL, "Can't allocate audio buffer", "Error", 0); + return 0; + } + memset(sdl_sound.buffer, 0, n); + sdl_sound.current_pos = sdl_sound.buffer; + return 1; +} + +static void sdl_sound_update(int enabled) +{ + int size = audio_update(soundframe) * 2; + + if (enabled) + { + int i; + short *out; + + SDL_LockAudio(); + out = (short*)sdl_sound.current_pos; + for(i = 0; i < size; i++) + { + *out++ = soundframe[i]; + } + sdl_sound.current_pos = (char*)out; + sdl_sound.current_emulated_samples += size * sizeof(short); + SDL_UnlockAudio(); + } +} + +static void sdl_sound_close() +{ + SDL_PauseAudio(1); + SDL_CloseAudio(); + if (sdl_sound.buffer) + free(sdl_sound.buffer); +} + +/* video */ +md_ntsc_t *md_ntsc; +sms_ntsc_t *sms_ntsc; + +struct { + SDL_Window* window; + SDL_Surface* surf_screen; + SDL_Surface* surf_bitmap; + SDL_Rect srect; + SDL_Rect drect; + Uint32 frames_rendered; +} sdl_video; + +static int sdl_video_init() +{ + if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + MessageBox(NULL, "SDL Video initialization failed", "Error", 0); + return 0; + } + sdl_video.window = SDL_CreateWindow("Genesis Plus GX", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, VIDEO_WIDTH, VIDEO_HEIGHT, 0); + sdl_video.surf_screen = SDL_GetWindowSurface(sdl_video.window); + sdl_video.surf_bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, 720, 576, 16, 0, 0, 0, 0); + sdl_video.frames_rendered = 0; + SDL_ShowCursor(0); + return 1; +} + +static void sdl_video_update() +{ + if (system_hw == SYSTEM_MCD) + { + system_frame_scd(0); + } + else if ((system_hw & SYSTEM_PBC) == SYSTEM_MD) + { + system_frame_gen(0); + } + else + { + system_frame_sms(0); + } + + /* viewport size changed */ + if(bitmap.viewport.changed & 1) + { + bitmap.viewport.changed &= ~1; + + /* source bitmap */ + sdl_video.srect.w = bitmap.viewport.w+2*bitmap.viewport.x; + sdl_video.srect.h = bitmap.viewport.h+2*bitmap.viewport.y; + sdl_video.srect.x = 0; + sdl_video.srect.y = 0; + if (sdl_video.srect.w > VIDEO_WIDTH) + { + sdl_video.srect.x = (sdl_video.srect.w - VIDEO_WIDTH) / 2; + sdl_video.srect.w = VIDEO_WIDTH; + } + if (sdl_video.srect.h > VIDEO_HEIGHT) + { + sdl_video.srect.y = (sdl_video.srect.h - VIDEO_HEIGHT) / 2; + sdl_video.srect.h = VIDEO_HEIGHT; + } + + /* destination bitmap */ + sdl_video.drect.w = sdl_video.srect.w; + sdl_video.drect.h = sdl_video.srect.h; + sdl_video.drect.x = (VIDEO_WIDTH - sdl_video.drect.w) / 2; + sdl_video.drect.y = (VIDEO_HEIGHT - sdl_video.drect.h) / 2; + + /* clear destination surface */ + SDL_FillRect(sdl_video.surf_screen, 0, 0); + +#if 0 + if (config.render && (interlaced || config.ntsc)) rect.h *= 2; + if (config.ntsc) rect.w = (reg[12]&1) ? MD_NTSC_OUT_WIDTH(rect.w) : SMS_NTSC_OUT_WIDTH(rect.w); + if (config.ntsc) + { + sms_ntsc = (sms_ntsc_t *)malloc(sizeof(sms_ntsc_t)); + md_ntsc = (md_ntsc_t *)malloc(sizeof(md_ntsc_t)); + + switch (config.ntsc) + { + case 1: + sms_ntsc_init(sms_ntsc, &sms_ntsc_composite); + md_ntsc_init(md_ntsc, &md_ntsc_composite); + break; + case 2: + sms_ntsc_init(sms_ntsc, &sms_ntsc_svideo); + md_ntsc_init(md_ntsc, &md_ntsc_svideo); + break; + case 3: + sms_ntsc_init(sms_ntsc, &sms_ntsc_rgb); + md_ntsc_init(md_ntsc, &md_ntsc_rgb); + break; + } + } + else + { + if (sms_ntsc) + { + free(sms_ntsc); + sms_ntsc = NULL; + } + + if (md_ntsc) + { + free(md_ntsc); + md_ntsc = NULL; + } + } +#endif + } + + SDL_BlitSurface(sdl_video.surf_bitmap, &sdl_video.srect, sdl_video.surf_screen, &sdl_video.drect); + SDL_UpdateWindowSurface(sdl_video.window); + + ++sdl_video.frames_rendered; +} + +static void sdl_video_close() +{ + if (sdl_video.surf_bitmap) + SDL_FreeSurface(sdl_video.surf_bitmap); + if (sdl_video.surf_screen) + SDL_FreeSurface(sdl_video.surf_screen); +} + +/* Timer Sync */ + +struct { + SDL_sem* sem_sync; + unsigned ticks; +} sdl_sync; + +static Uint32 sdl_sync_timer_callback(Uint32 interval, void *param) +{ + SDL_SemPost(sdl_sync.sem_sync); + sdl_sync.ticks++; + if (sdl_sync.ticks == (vdp_pal ? 50 : 20)) + { + SDL_Event event; + SDL_UserEvent userevent; + + userevent.type = SDL_USEREVENT; + userevent.code = vdp_pal ? (sdl_video.frames_rendered / 3) : sdl_video.frames_rendered; + userevent.data1 = NULL; + userevent.data2 = NULL; + sdl_sync.ticks = sdl_video.frames_rendered = 0; + + event.type = SDL_USEREVENT; + event.user = userevent; + + SDL_PushEvent(&event); + } + return interval; +} + +static int sdl_sync_init() +{ + if(SDL_InitSubSystem(SDL_INIT_TIMER|SDL_INIT_EVENTS) < 0) + { + MessageBox(NULL, "SDL Timer initialization failed", "Error", 0); + return 0; + } + + sdl_sync.sem_sync = SDL_CreateSemaphore(0); + sdl_sync.ticks = 0; + return 1; +} + +static void sdl_sync_close() +{ + if(sdl_sync.sem_sync) + SDL_DestroySemaphore(sdl_sync.sem_sync); +} + +static const uint16 vc_table[4][2] = +{ + /* NTSC, PAL */ + {0xDA , 0xF2}, /* Mode 4 (192 lines) */ + {0xEA , 0x102}, /* Mode 5 (224 lines) */ + {0xDA , 0xF2}, /* Mode 4 (192 lines) */ + {0x106, 0x10A} /* Mode 5 (240 lines) */ +}; + +static int sdl_control_update(SDL_Keycode keystate) +{ + switch (keystate) + { + case SDLK_TAB: + { + system_reset(); + break; + } + + case SDLK_F1: + { + if (SDL_ShowCursor(-1)) SDL_ShowCursor(0); + else SDL_ShowCursor(1); + break; + } + + case SDLK_F2: + { + fullscreen = (fullscreen ? 0 : SDL_WINDOW_FULLSCREEN); + SDL_SetWindowFullscreen(sdl_video.window, fullscreen); + break; + } + + case SDLK_F3: + { + if (config.bios == 0) config.bios = 3; + else if (config.bios == 3) config.bios = 1; + break; + } + + case SDLK_F4: + { + if (!turbo_mode) use_sound ^= 1; + break; + } + + case SDLK_F5: + { + log_error ^= 1; + break; + } + + case SDLK_F6: + { + if (!use_sound) + { + turbo_mode ^=1; + sdl_sync.ticks = 0; + } + break; + } + + case SDLK_F7: + { + FILE *f = fopen("game.gp0","rb"); + if (f) + { + uint8 buf[STATE_SIZE]; + fread(&buf, STATE_SIZE, 1, f); + state_load(buf); + fclose(f); + } + break; + } + + case SDLK_F8: + { + FILE *f = fopen("game.gp0","wb"); + if (f) + { + uint8 buf[STATE_SIZE]; + int len = state_save(buf); + fwrite(&buf, len, 1, f); + fclose(f); + } + break; + } + + case SDLK_F9: + { + config.region_detect = (config.region_detect + 1) % 5; + get_region(0); + + /* framerate has changed, reinitialize audio timings */ + audio_init(snd.sample_rate, 0); + + /* system with region BIOS should be reinitialized */ + if ((system_hw == SYSTEM_MCD) || ((system_hw & SYSTEM_SMS) && (config.bios & 1))) + { + system_init(); + system_reset(); + } + else + { + /* reinitialize I/O region register */ + if (system_hw == SYSTEM_MD) + { + io_reg[0x00] = 0x20 | region_code | (config.bios & 1); + } + else + { + io_reg[0x00] = 0x80 | (region_code >> 1); + } + + /* reinitialize VDP */ + if (vdp_pal) + { + status |= 1; + lines_per_frame = 313; + } + else + { + status &= ~1; + lines_per_frame = 262; + } + + /* reinitialize VC max value */ + switch (bitmap.viewport.h) + { + case 192: + vc_max = vc_table[0][vdp_pal]; + break; + case 224: + vc_max = vc_table[1][vdp_pal]; + break; + case 240: + vc_max = vc_table[3][vdp_pal]; + break; + } + } + break; + } + + case SDLK_F10: + { + gen_reset(0); + break; + } + + case SDLK_F11: + { + config.overscan = (config.overscan + 1) & 3; + if ((system_hw == SYSTEM_GG) && !config.gg_extra) + { + bitmap.viewport.x = (config.overscan & 2) ? 14 : -48; + } + else + { + bitmap.viewport.x = (config.overscan & 2) * 7; + } + bitmap.viewport.changed = 3; + break; + } + + case SDLK_F12: + { + joynum = (joynum + 1) % MAX_DEVICES; + while (input.dev[joynum] == NO_DEVICE) + { + joynum = (joynum + 1) % MAX_DEVICES; + } + break; + } + + case SDLK_ESCAPE: + { + return 0; + } + + default: + break; + } + + return 1; +} + +int sdl_input_update(void) +{ + const uint8 *keystate = SDL_GetKeyboardState(NULL); + + /* reset input */ + input.pad[joynum] = 0; + + switch (input.dev[joynum]) + { + case DEVICE_LIGHTGUN: + { + /* get mouse coordinates (absolute values) */ + int x,y; + int state = SDL_GetMouseState(&x,&y); + + /* X axis */ + input.analog[joynum][0] = x - (VIDEO_WIDTH-bitmap.viewport.w)/2; + + /* Y axis */ + input.analog[joynum][1] = y - (VIDEO_HEIGHT-bitmap.viewport.h)/2; + + /* TRIGGER, B, C (Menacer only), START (Menacer & Justifier only) */ + if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_A; + if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_B; + if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_C; + if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START; + break; + } + + case DEVICE_PADDLE: + { + /* get mouse (absolute values) */ + int x; + int state = SDL_GetMouseState(&x, NULL); + + /* Range is [0;256], 128 being middle position */ + input.analog[joynum][0] = x * 256 /VIDEO_WIDTH; + + /* Button I -> 0 0 0 0 0 0 0 I*/ + if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B; + + break; + } + + case DEVICE_SPORTSPAD: + { + /* get mouse (relative values) */ + int x,y; + int state = SDL_GetRelativeMouseState(&x,&y); + + /* Range is [0;256] */ + input.analog[joynum][0] = (unsigned char)(-x & 0xFF); + input.analog[joynum][1] = (unsigned char)(-y & 0xFF); + + /* Buttons I & II -> 0 0 0 0 0 0 II I*/ + if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B; + if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C; + + break; + } + + case DEVICE_MOUSE: + { + /* get mouse (relative values) */ + int x,y; + int state = SDL_GetRelativeMouseState(&x,&y); + + /* Sega Mouse range is [-256;+256] */ + input.analog[joynum][0] = x * 2; + input.analog[joynum][1] = y * 2; + + /* Vertical movement is upsidedown */ + if (!config.invert_mouse) + input.analog[joynum][1] = 0 - input.analog[joynum][1]; + + /* Start,Left,Right,Middle buttons -> 0 0 0 0 START MIDDLE RIGHT LEFT */ + if(state & SDL_BUTTON_LMASK) input.pad[joynum] |= INPUT_B; + if(state & SDL_BUTTON_RMASK) input.pad[joynum] |= INPUT_C; + if(state & SDL_BUTTON_MMASK) input.pad[joynum] |= INPUT_A; + if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START; + + break; + } + + case DEVICE_XE_1AP: + { + /* A,B,C,D,Select,START,E1,E2 buttons -> E1(?) E2(?) START SELECT(?) A B C D */ + if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_START; + if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_A; + if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C; + if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_Y; + if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_B; + if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_X; + if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_MODE; + if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_Z; + + /* Left Analog Stick (bidirectional) */ + if(keystate[SDL_SCANCODE_UP]) input.analog[joynum][1]-=2; + else if(keystate[SDL_SCANCODE_DOWN]) input.analog[joynum][1]+=2; + else input.analog[joynum][1] = 128; + if(keystate[SDL_SCANCODE_LEFT]) input.analog[joynum][0]-=2; + else if(keystate[SDL_SCANCODE_RIGHT]) input.analog[joynum][0]+=2; + else input.analog[joynum][0] = 128; + + /* Right Analog Stick (unidirectional) */ + if(keystate[SDL_SCANCODE_KP_8]) input.analog[joynum+1][0]-=2; + else if(keystate[SDL_SCANCODE_KP_2]) input.analog[joynum+1][0]+=2; + else if(keystate[SDL_SCANCODE_KP_4]) input.analog[joynum+1][0]-=2; + else if(keystate[SDL_SCANCODE_KP_6]) input.analog[joynum+1][0]+=2; + else input.analog[joynum+1][0] = 128; + + /* Limiters */ + if (input.analog[joynum][0] > 0xFF) input.analog[joynum][0] = 0xFF; + else if (input.analog[joynum][0] < 0) input.analog[joynum][0] = 0; + if (input.analog[joynum][1] > 0xFF) input.analog[joynum][1] = 0xFF; + else if (input.analog[joynum][1] < 0) input.analog[joynum][1] = 0; + if (input.analog[joynum+1][0] > 0xFF) input.analog[joynum+1][0] = 0xFF; + else if (input.analog[joynum+1][0] < 0) input.analog[joynum+1][0] = 0; + if (input.analog[joynum+1][1] > 0xFF) input.analog[joynum+1][1] = 0xFF; + else if (input.analog[joynum+1][1] < 0) input.analog[joynum+1][1] = 0; + + break; + } + + case DEVICE_PICO: + { + /* get mouse (absolute values) */ + int x,y; + int state = SDL_GetMouseState(&x,&y); + + /* Calculate X Y axis values */ + input.analog[0][0] = 0x3c + (x * (0x17c-0x03c+1)) / VIDEO_WIDTH; + input.analog[0][1] = 0x1fc + (y * (0x2f7-0x1fc+1)) / VIDEO_HEIGHT; + + /* Map mouse buttons to player #1 inputs */ + if(state & SDL_BUTTON_MMASK) pico_current = (pico_current + 1) & 7; + if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_PICO_RED; + if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_PICO_PEN; + + break; + } + + case DEVICE_TEREBI: + { + /* get mouse (absolute values) */ + int x,y; + int state = SDL_GetMouseState(&x,&y); + + /* Calculate X Y axis values */ + input.analog[0][0] = (x * 250) / VIDEO_WIDTH; + input.analog[0][1] = (y * 250) / VIDEO_HEIGHT; + + /* Map mouse buttons to player #1 inputs */ + if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_B; + + break; + } + + case DEVICE_GRAPHIC_BOARD: + { + /* get mouse (absolute values) */ + int x,y; + int state = SDL_GetMouseState(&x,&y); + + /* Calculate X Y axis values */ + input.analog[0][0] = (x * 255) / VIDEO_WIDTH; + input.analog[0][1] = (y * 255) / VIDEO_HEIGHT; + + /* Map mouse buttons to player #1 inputs */ + if(state & SDL_BUTTON_LMASK) input.pad[0] |= INPUT_GRAPHIC_PEN; + if(state & SDL_BUTTON_RMASK) input.pad[0] |= INPUT_GRAPHIC_MENU; + if(state & SDL_BUTTON_MMASK) input.pad[0] |= INPUT_GRAPHIC_DO; + + break; + } + + case DEVICE_ACTIVATOR: + { + if(keystate[SDL_SCANCODE_G]) input.pad[joynum] |= INPUT_ACTIVATOR_7L; + if(keystate[SDL_SCANCODE_H]) input.pad[joynum] |= INPUT_ACTIVATOR_7U; + if(keystate[SDL_SCANCODE_J]) input.pad[joynum] |= INPUT_ACTIVATOR_8L; + if(keystate[SDL_SCANCODE_K]) input.pad[joynum] |= INPUT_ACTIVATOR_8U; + } + + default: + { + if(keystate[SDL_SCANCODE_A]) input.pad[joynum] |= INPUT_A; + if(keystate[SDL_SCANCODE_S]) input.pad[joynum] |= INPUT_B; + if(keystate[SDL_SCANCODE_D]) input.pad[joynum] |= INPUT_C; + if(keystate[SDL_SCANCODE_F]) input.pad[joynum] |= INPUT_START; + if(keystate[SDL_SCANCODE_Z]) input.pad[joynum] |= INPUT_X; + if(keystate[SDL_SCANCODE_X]) input.pad[joynum] |= INPUT_Y; + if(keystate[SDL_SCANCODE_C]) input.pad[joynum] |= INPUT_Z; + if(keystate[SDL_SCANCODE_V]) input.pad[joynum] |= INPUT_MODE; + + if(keystate[SDL_SCANCODE_UP]) input.pad[joynum] |= INPUT_UP; + else + if(keystate[SDL_SCANCODE_DOWN]) input.pad[joynum] |= INPUT_DOWN; + if(keystate[SDL_SCANCODE_LEFT]) input.pad[joynum] |= INPUT_LEFT; + else + if(keystate[SDL_SCANCODE_RIGHT]) input.pad[joynum] |= INPUT_RIGHT; + + break; + } + } + return 1; +} + + +int main (int argc, char **argv) +{ + FILE *fp; + int running = 1; + + /* Print help if no game specified */ + if(argc < 2) + { + char caption[256]; + sprintf(caption, "Genesis Plus GX\\SDL\nusage: %s gamename\n", argv[0]); + MessageBox(NULL, caption, "Information", 0); + exit(1); + } + + /* set default config */ + error_init(); + set_config_defaults(); + + /* mark all BIOS as unloaded */ + system_bios = 0; + + /* Genesis BOOT ROM support (2KB max) */ + memset(boot_rom, 0xFF, 0x800); + fp = fopen(MD_BIOS, "rb"); + if (fp != NULL) + { + int i; + + /* read BOOT ROM */ + fread(boot_rom, 1, 0x800, fp); + fclose(fp); + + /* check BOOT ROM */ + if (!memcmp((char *)(boot_rom + 0x120),"GENESIS OS", 10)) + { + /* mark Genesis BIOS as loaded */ + system_bios = SYSTEM_MD; + } + + /* Byteswap ROM */ + for (i=0; i<0x800; i+=2) + { + uint8 temp = boot_rom[i]; + boot_rom[i] = boot_rom[i+1]; + boot_rom[i+1] = temp; + } + } + + /* initialize SDL */ + if(SDL_Init(0) < 0) + { + char caption[256]; + sprintf(caption, "SDL initialization failed"); + MessageBox(NULL, caption, "Error", 0); + exit(1); + } + sdl_video_init(); + if (use_sound) sdl_sound_init(); + sdl_sync_init(); + + /* initialize Genesis virtual system */ + SDL_LockSurface(sdl_video.surf_bitmap); + memset(&bitmap, 0, sizeof(t_bitmap)); + bitmap.width = 720; + bitmap.height = 576; +#if defined(USE_8BPP_RENDERING) + bitmap.pitch = (bitmap.width * 1); +#elif defined(USE_15BPP_RENDERING) + bitmap.pitch = (bitmap.width * 2); +#elif defined(USE_16BPP_RENDERING) + bitmap.pitch = (bitmap.width * 2); +#elif defined(USE_32BPP_RENDERING) + bitmap.pitch = (bitmap.width * 4); +#endif + bitmap.data = sdl_video.surf_bitmap->pixels; + SDL_UnlockSurface(sdl_video.surf_bitmap); + bitmap.viewport.changed = 3; + + /* Load game file */ + if(!load_rom(argv[1])) + { + char caption[256]; + sprintf(caption, "Error loading file `%s'.", argv[1]); + MessageBox(NULL, caption, "Error", 0); + exit(1); + } + + /* initialize system hardware */ + audio_init(SOUND_FREQUENCY, 0); + system_init(); + + /* Mega CD specific */ + if (system_hw == SYSTEM_MCD) + { + /* load internal backup RAM */ + fp = fopen("./scd.brm", "rb"); + if (fp!=NULL) + { + fread(scd.bram, 0x2000, 1, fp); + fclose(fp); + } + + /* check if internal backup RAM is formatted */ + if (memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20)) + { + /* clear internal backup RAM */ + memset(scd.bram, 0x00, 0x200); + + /* Internal Backup RAM size fields */ + brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = 0x00; + brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (sizeof(scd.bram) / 64) - 3; + + /* format internal backup RAM */ + memcpy(scd.bram + 0x2000 - 0x40, brm_format, 0x40); + } + + /* load cartridge backup RAM */ + if (scd.cartridge.id) + { + fp = fopen("./cart.brm", "rb"); + if (fp!=NULL) + { + fread(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp); + fclose(fp); + } + + /* check if cartridge backup RAM is formatted */ + if (memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20)) + { + /* clear cartridge backup RAM */ + memset(scd.cartridge.area, 0x00, scd.cartridge.mask + 1); + + /* Cartridge Backup RAM size fields */ + brm_format[0x10] = brm_format[0x12] = brm_format[0x14] = brm_format[0x16] = (((scd.cartridge.mask + 1) / 64) - 3) >> 8; + brm_format[0x11] = brm_format[0x13] = brm_format[0x15] = brm_format[0x17] = (((scd.cartridge.mask + 1) / 64) - 3) & 0xff; + + /* format cartridge backup RAM */ + memcpy(scd.cartridge.area + scd.cartridge.mask + 1 - sizeof(brm_format), brm_format, sizeof(brm_format)); + } + } + } + + if (sram.on) + { + /* load SRAM */ + fp = fopen("./game.srm", "rb"); + if (fp!=NULL) + { + fread(sram.sram,0x10000,1, fp); + fclose(fp); + } + } + + /* reset system hardware */ + system_reset(); + + if(use_sound) SDL_PauseAudio(0); + + /* 3 frames = 50 ms (60hz) or 60 ms (50hz) */ + if(sdl_sync.sem_sync) + SDL_AddTimer(vdp_pal ? 60 : 50, sdl_sync_timer_callback, NULL); + + /* emulation loop */ + while(running) + { + SDL_Event event; + if (SDL_PollEvent(&event)) + { + switch(event.type) + { + case SDL_USEREVENT: + { + char caption[100]; + sprintf(caption,"Genesis Plus GX - %d fps - %s", event.user.code, (rominfo.international[0] != 0x20) ? rominfo.international : rominfo.domestic); + SDL_SetWindowTitle(sdl_video.window, caption); + break; + } + + case SDL_QUIT: + { + running = 0; + break; + } + + case SDL_KEYDOWN: + { + running = sdl_control_update(event.key.keysym.sym); + break; + } + } + } + + sdl_video_update(); + sdl_sound_update(use_sound); + + if(!turbo_mode && sdl_sync.sem_sync && sdl_video.frames_rendered % 3 == 0) + { + SDL_SemWait(sdl_sync.sem_sync); + } + } + + if (system_hw == SYSTEM_MCD) + { + /* save internal backup RAM (if formatted) */ + if (!memcmp(scd.bram + 0x2000 - 0x20, brm_format + 0x20, 0x20)) + { + fp = fopen("./scd.brm", "wb"); + if (fp!=NULL) + { + fwrite(scd.bram, 0x2000, 1, fp); + fclose(fp); + } + } + + /* save cartridge backup RAM (if formatted) */ + if (scd.cartridge.id) + { + if (!memcmp(scd.cartridge.area + scd.cartridge.mask + 1 - 0x20, brm_format + 0x20, 0x20)) + { + fp = fopen("./cart.brm", "wb"); + if (fp!=NULL) + { + fwrite(scd.cartridge.area, scd.cartridge.mask + 1, 1, fp); + fclose(fp); + } + } + } + } + + if (sram.on) + { + /* save SRAM */ + fp = fopen("./game.srm", "wb"); + if (fp!=NULL) + { + fwrite(sram.sram,0x10000,1, fp); + fclose(fp); + } + } + + audio_shutdown(); + error_shutdown(); + + sdl_video_close(); + sdl_sound_close(); + sdl_sync_close(); + SDL_Quit(); + + return 0; +} diff --git a/sdl2/main.h b/sdl2/main.h new file mode 100644 index 0000000..dfa5d8d --- /dev/null +++ b/sdl2/main.h @@ -0,0 +1,11 @@ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#define MAX_INPUTS 8 + +extern int debug_on; +extern int log_error; +extern int sdl_input_update(void); + +#endif /* _MAIN_H_ */ diff --git a/sdl2/md.ico b/sdl2/md.ico new file mode 100644 index 0000000..7cf20f8 Binary files /dev/null and b/sdl2/md.ico differ diff --git a/sdl2/osd.h b/sdl2/osd.h new file mode 100644 index 0000000..ad95a52 --- /dev/null +++ b/sdl2/osd.h @@ -0,0 +1,35 @@ + +#ifndef _OSD_H_ +#define _OSD_H_ + +#include +#include +#include +#include + +#include +#include + +#include "shared.h" +#include "main.h" +#include "config.h" +#include "error.h" +#include "unzip.h" +#include "fileio.h" + +#define osd_input_update sdl_input_update + +#define GG_ROM "./ggenie.bin" +#define AR_ROM "./areplay.bin" +#define SK_ROM "./sk.bin" +#define SK_UPMEM "./sk2chip.bin" +#define CD_BIOS_US "./bios_CD_U.bin" +#define CD_BIOS_EU "./bios_CD_E.bin" +#define CD_BIOS_JP "./bios_CD_J.bin" +#define MD_BIOS "./bios_MD.bin" +#define MS_BIOS_US "./bios_U.sms" +#define MS_BIOS_EU "./bios_E.sms" +#define MS_BIOS_JP "./bios_J.sms" +#define GG_BIOS "./bios.gg" + +#endif /* _OSD_H_ */ diff --git a/sdl2/readme-sdl.txt b/sdl2/readme-sdl.txt new file mode 100644 index 0000000..3c8eb64 --- /dev/null +++ b/sdl2/readme-sdl.txt @@ -0,0 +1,5 @@ +Compile with MinGW. +You will also need to install the SDL library (http://www.libsdl.org/). +Zlib is required for zipped rom support. + +Please distribute required dlls with the executable. \ No newline at end of file diff --git a/sdl2/unzip.c b/sdl2/unzip.c new file mode 100644 index 0000000..ef52bc6 --- /dev/null +++ b/sdl2/unzip.c @@ -0,0 +1,1294 @@ +/* unzip.c -- IO on .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Read unzip.h for more info +*/ + + +#include +#include +#include +#include +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else + #include +#endif + + +#ifndef local + #define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +const char unz_copyright[] = + " unzip 0.15 Copyright 1998 Gilles Vollant "; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte(fin,pi) + FILE *fin; + int *pi; +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong (fin,pX) + FILE* fin; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir(fin) + FILE *fin; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen (path) + const char *path; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ +/* int err=UNZ_OK; */ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/sdl2/unzip.h b/sdl2/unzip.h new file mode 100644 index 0000000..a30f79c --- /dev/null +++ b/sdl2/unzip.h @@ -0,0 +1,273 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */