Step 2: Globalize cdlist.cpp to replace platform‑specific neocdlist.cpp implementations

This commit is contained in:
taoenwen committed 2026-08-12 19:40:07 +08:00
1 parent 33768c13a4
commit e1a4d99852
31 files changed
+3332 -2273

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ alldir += burner burner/win32 dep/kaillera/client dep/libs/libspng dep/libs/lib
depobj += about.o bzip.o choose_monitor.o cona.o debugger.o drv.o d3dkmt_sync.o fba_kaillera.o gameinfo.o image_win32.o \ depobj += about.o bzip.o choose_monitor.o cona.o debugger.o drv.o d3dkmt_sync.o fba_kaillera.o gameinfo.o image_win32.o \
inpc.o inpcheat.o inpd.o inpdipsw.o inps.o ips_manager.o localise.o localise_download.o localise_gamelist.o main.o \ inpc.o inpcheat.o inpd.o inpdipsw.o inps.o ips_manager.o localise.o localise_download.o localise_gamelist.o main.o \
media.o memcard.o menu.o misc_win32.o neocdlist.o neocdsel.o numdial.o paletteviewer.o placeholder.o popup_win32.o \ media.o memcard.o menu.o misc_win32.o cdlist.o neocdsel.o numdial.o paletteviewer.o placeholder.o popup_win32.o \
progress.o replay.o res.o roms.o run.o scrn.o sel.o sfactd.o splash.o stated.o support_paths.o systeminfo.o wave.o \ progress.o replay.o res.o roms.o run.o scrn.o sel.o sfactd.o splash.o stated.o support_paths.o systeminfo.o wave.o \
romdata.o mbtwc.o zip.o \ romdata.o mbtwc.o zip.o \
\ \
+2 -2
View File
@@ -49,7 +49,7 @@ alldir += burner burner/pi burner/sdl dep/libs/libspng dep/libs/lib7z \
intf/perfcount intf/perfcount/pi dep/generated \ intf/perfcount intf/perfcount/pi dep/generated \
dep/pi/gles dep/pi/gles
depobj += neocdlist.o \ depobj += cdlist.o \
\ \
conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o \ conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o \
sshot.o state.o statec.o unzip.o zipfn.o \ sshot.o state.o statec.o unzip.o zipfn.o \
@@ -269,7 +269,7 @@ else
endif endif
# For zlib # For zlib
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=64 DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=64 -DCHDR_SYSTEM_ZLIB
# For lib7z # For lib7z
ifdef INCLUDE_7Z_SUPPORT ifdef INCLUDE_7Z_SUPPORT
+1 -1
View File
@@ -53,7 +53,7 @@ alldir += burner burner/sdl burner/sdl dep/libs/libspng dep/libs/lib7z dep/libs
intf/video/scalers intf/video/sdl intf/audio intf/audio/sdl intf/input intf/input/sdl intf/cd \ intf/video/scalers intf/video/sdl intf/audio intf/audio/sdl intf/input intf/input/sdl intf/cd \
intf/perfcount intf/perfcount/sdl dep/generated intf/perfcount intf/perfcount/sdl dep/generated
depobj += neocdlist.o \ depobj += cdlist.o \
\ \
conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \ conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \
\ \
+1 -1
View File
@@ -54,7 +54,7 @@ alldir += burner burner/sdl burner/sdl dep/libs/libspng dep/libs/lib7z dep/libs
intf/video/scalers intf/video/sdl intf/audio intf/audio/sdl intf/input intf/input/sdl intf/cd \ intf/video/scalers intf/video/sdl intf/audio intf/audio/sdl intf/input intf/input/sdl intf/cd \
intf/perfcount intf/perfcount/sdl dep/generated intf/perfcount intf/perfcount/sdl dep/generated
depobj += neocdlist.o \ depobj += cdlist.o \
\ \
conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \ conc.o cong.o dat.o gamc.o gami.o image.o ioapi.o misc.o sshot.o state.o statec.o unzip.o zipfn.o \
\ \
+26 -2
View File
@@ -84,13 +84,19 @@ INCLUDEPATH += \
$$SRC/dep/libs \ $$SRC/dep/libs \
$$SRC/dep/libs/libpng \ $$SRC/dep/libs/libpng \
$$SRC/dep/libs/zlib \ $$SRC/dep/libs/zlib \
$$SRC/dep/libs/libchdr \
$$SRC/dep/libs/libchdr/include \
$$SRC/dep/libs/lzma \
$$SRC/dep/libs/lzma/include \
$$SRC/dep/libs/zstd \
DEFINES += BUILD_QT \ DEFINES += BUILD_QT \
LSB_FIRST \ LSB_FIRST \
"__fastcall=" \ "__fastcall=" \
"_fastcall=" \ "_fastcall=" \
WITH_QTCREATOR \ WITH_QTCREATOR \
INCLUDE_LIB_PNGH INCLUDE_LIB_PNGH \
CHDR_SYSTEM_ZLIB
linux: DEFINES += BUILD_QT_LINUX linux: DEFINES += BUILD_QT_LINUX
macx: DEFINES += BUILD_QT_MACX macx: DEFINES += BUILD_QT_MACX
@@ -389,7 +395,7 @@ $$DRV_NEOGEO {
HEADERS += $$files(../../src/burn/drv/neogeo/*.h) HEADERS += $$files(../../src/burn/drv/neogeo/*.h)
SOURCES += $$files(../../src/burn/drv/neogeo/*.cpp) SOURCES += $$files(../../src/burn/drv/neogeo/*.cpp)
SOURCES *= ../../src/burner/qt/neocdlist.cpp SOURCES *= ../../src/burner/cdlist.cpp
} }
#=============================================================================== #===============================================================================
@@ -659,6 +665,24 @@ SOURCES += \
../../src/intf/audio/aud_interface.cpp \ ../../src/intf/audio/aud_interface.cpp \
../../src/intf/audio/lowpass2.cpp \ ../../src/intf/audio/lowpass2.cpp \
../../src/intf/cd/cd_interface.cpp \ ../../src/intf/cd/cd_interface.cpp \
../../src/intf/cd/cd_img.cpp \
../../src/intf/cd/cd_chd.cpp \
../../src/dep/libs/libchdr/libchdr_bitstream.c \
../../src/dep/libs/libchdr/libchdr_cdrom.c \
../../src/dep/libs/libchdr/libchdr_chd.c \
../../src/dep/libs/libchdr/libchdr_codec_cdfl.c \
../../src/dep/libs/libchdr/libchdr_codec_cdlz.c \
../../src/dep/libs/libchdr/libchdr_codec_cdzl.c \
../../src/dep/libs/libchdr/libchdr_codec_cdzs.c \
../../src/dep/libs/libchdr/libchdr_codec_flac.c \
../../src/dep/libs/libchdr/libchdr_codec_huff.c \
../../src/dep/libs/libchdr/libchdr_codec_lzma.c \
../../src/dep/libs/libchdr/libchdr_codec_zlib.c \
../../src/dep/libs/libchdr/libchdr_codec_zstd.c \
../../src/dep/libs/libchdr/libchdr_flac.c \
../../src/dep/libs/libchdr/libchdr_huffman.c \
../../src/dep/libs/lzma/libchdr_lzma.c \
../../src/dep/libs/zstd/zstddeclib.c \
../../src/intf/input/inp_interface.cpp \ ../../src/intf/input/inp_interface.cpp \
../../src/intf/video/vid_interface.cpp \ ../../src/intf/video/vid_interface.cpp \
../../src/intf/video/vid_support.cpp \ ../../src/intf/video/vid_support.cpp \
+26 -2
View File
@@ -72,13 +72,19 @@ INCLUDEPATH += \
$$SRC/intf/cd \ $$SRC/intf/cd \
$$SRC/dep/libs/libpng \ $$SRC/dep/libs/libpng \
$$SRC/dep/libs/zlib \ $$SRC/dep/libs/zlib \
$$SRC/dep/libs/libchdr \
$$SRC/dep/libs/libchdr/include \
$$SRC/dep/libs/lzma \
$$SRC/dep/libs/lzma/include \
$$SRC/dep/libs/zstd \
DEFINES += BUILD_SDL \ DEFINES += BUILD_SDL \
LSB_FIRST \ LSB_FIRST \
"__fastcall=" \ "__fastcall=" \
"_fastcall=" \ "_fastcall=" \
WITH_QTCREATOR \ WITH_QTCREATOR \
INCLUDE_LIB_PNGH INCLUDE_LIB_PNGH \
CHDR_SYSTEM_ZLIB
# no warnings... # no warnings...
QMAKE_CXXFLAGS += -w QMAKE_CXXFLAGS += -w
@@ -1071,6 +1077,24 @@ SOURCES += \
../../src/intf/audio/lowpass2.cpp \ ../../src/intf/audio/lowpass2.cpp \
../../src/intf/audio/sdl/aud_sdl.cpp \ ../../src/intf/audio/sdl/aud_sdl.cpp \
../../src/intf/cd/cd_interface.cpp \ ../../src/intf/cd/cd_interface.cpp \
../../src/intf/cd/cd_img.cpp \
../../src/intf/cd/cd_chd.cpp \
../../src/dep/libs/libchdr/libchdr_bitstream.c \
../../src/dep/libs/libchdr/libchdr_cdrom.c \
../../src/dep/libs/libchdr/libchdr_chd.c \
../../src/dep/libs/libchdr/libchdr_codec_cdfl.c \
../../src/dep/libs/libchdr/libchdr_codec_cdlz.c \
../../src/dep/libs/libchdr/libchdr_codec_cdzl.c \
../../src/dep/libs/libchdr/libchdr_codec_cdzs.c \
../../src/dep/libs/libchdr/libchdr_codec_flac.c \
../../src/dep/libs/libchdr/libchdr_codec_huff.c \
../../src/dep/libs/libchdr/libchdr_codec_lzma.c \
../../src/dep/libs/libchdr/libchdr_codec_zlib.c \
../../src/dep/libs/libchdr/libchdr_codec_zstd.c \
../../src/dep/libs/libchdr/libchdr_flac.c \
../../src/dep/libs/libchdr/libchdr_huffman.c \
../../src/dep/libs/lzma/libchdr_lzma.c \
../../src/dep/libs/zstd/zstddeclib.c \
../../src/intf/input/inp_interface.cpp \ ../../src/intf/input/inp_interface.cpp \
../../src/intf/input/sdl/inp_sdl.cpp \ ../../src/intf/input/sdl/inp_sdl.cpp \
../../src/intf/video/vid_interface.cpp \ ../../src/intf/video/vid_interface.cpp \
@@ -1078,7 +1102,7 @@ SOURCES += \
../../src/intf/video/sdl/vid_sdlfx.cpp \ ../../src/intf/video/sdl/vid_sdlfx.cpp \
../../src/intf/video/sdl/vid_sdlopengl.cpp \ ../../src/intf/video/sdl/vid_sdlopengl.cpp \
../../src/cpu/z80_intf.cpp \ ../../src/cpu/z80_intf.cpp \
../../src/burner/libretro/neocdlist.cpp \ ../../src/burner/cdlist.cpp \
../../src/intf/video/vid_softfx.cpp \ ../../src/intf/video/vid_softfx.cpp \
../../src/intf/video/scalers/2xpm.cpp \ ../../src/intf/video/scalers/2xpm.cpp \
../../src/intf/video/scalers/2xsai.cpp \ ../../src/intf/video/scalers/2xsai.cpp \
@@ -34,6 +34,7 @@
<ClCompile Include="..\..\src\burner\luasav.cpp" /> <ClCompile Include="..\..\src\burner\luasav.cpp" />
<ClCompile Include="..\..\src\burner\misc.cpp" /> <ClCompile Include="..\..\src\burner\misc.cpp" />
<ClCompile Include="..\..\src\burner\nvram.cpp" /> <ClCompile Include="..\..\src\burner\nvram.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\sshot.cpp" /> <ClCompile Include="..\..\src\burner\sshot.cpp" />
<ClCompile Include="..\..\src\burner\state.cpp" /> <ClCompile Include="..\..\src\burner\state.cpp" />
<ClCompile Include="..\..\src\burner\statec.cpp" /> <ClCompile Include="..\..\src\burner\statec.cpp" />
@@ -66,7 +67,7 @@
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" /> <ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
<ClCompile Include="..\..\src\burner\win32\menu.cpp" /> <ClCompile Include="..\..\src\burner\win32\menu.cpp" />
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" /> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp" /> <ClCompile Include="..\..\src\burner\cdlist.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" /> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" />
<ClCompile Include="..\..\src\burner\win32\numdial.cpp" /> <ClCompile Include="..\..\src\burner\win32\numdial.cpp" />
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" /> <ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
@@ -75,7 +76,6 @@
<ClCompile Include="..\..\src\burner\win32\progress.cpp" /> <ClCompile Include="..\..\src\burner\win32\progress.cpp" />
<ClCompile Include="..\..\src\burner\win32\replay.cpp" /> <ClCompile Include="..\..\src\burner\win32\replay.cpp" />
<ClCompile Include="..\..\src\burner\win32\res.cpp" /> <ClCompile Include="..\..\src\burner\win32\res.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\win32\roms.cpp" /> <ClCompile Include="..\..\src\burner\win32\roms.cpp" />
<ClCompile Include="..\..\src\burner\win32\run.cpp" /> <ClCompile Include="..\..\src\burner\win32\run.cpp" />
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" /> <ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
@@ -1465,8 +1465,8 @@
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp"> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp"> <ClCompile Include="..\..\src\burner\cdlist.cpp">
<Filter>burner\win32</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp"> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
@@ -3388,6 +3388,9 @@
<ClCompile Include="..\..\src\burner\nvram.cpp"> <ClCompile Include="..\..\src\burner\nvram.cpp">
<Filter>burner</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp"> <ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
@@ -3568,9 +3571,6 @@
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp"> <ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
<Filter>burn\drv\pre90s</Filter> <Filter>burn\drv\pre90s</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp"> <ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
<Filter>burn\drv\taito</Filter> <Filter>burn\drv\taito</Filter>
</ClCompile> </ClCompile>
@@ -34,6 +34,7 @@
<ClCompile Include="..\..\src\burner\luasav.cpp" /> <ClCompile Include="..\..\src\burner\luasav.cpp" />
<ClCompile Include="..\..\src\burner\misc.cpp" /> <ClCompile Include="..\..\src\burner\misc.cpp" />
<ClCompile Include="..\..\src\burner\nvram.cpp" /> <ClCompile Include="..\..\src\burner\nvram.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\sshot.cpp" /> <ClCompile Include="..\..\src\burner\sshot.cpp" />
<ClCompile Include="..\..\src\burner\state.cpp" /> <ClCompile Include="..\..\src\burner\state.cpp" />
<ClCompile Include="..\..\src\burner\statec.cpp" /> <ClCompile Include="..\..\src\burner\statec.cpp" />
@@ -66,7 +67,7 @@
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" /> <ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
<ClCompile Include="..\..\src\burner\win32\menu.cpp" /> <ClCompile Include="..\..\src\burner\win32\menu.cpp" />
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" /> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp" /> <ClCompile Include="..\..\src\burner\cdlist.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" /> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" />
<ClCompile Include="..\..\src\burner\win32\numdial.cpp" /> <ClCompile Include="..\..\src\burner\win32\numdial.cpp" />
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" /> <ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
@@ -75,7 +76,6 @@
<ClCompile Include="..\..\src\burner\win32\progress.cpp" /> <ClCompile Include="..\..\src\burner\win32\progress.cpp" />
<ClCompile Include="..\..\src\burner\win32\replay.cpp" /> <ClCompile Include="..\..\src\burner\win32\replay.cpp" />
<ClCompile Include="..\..\src\burner\win32\res.cpp" /> <ClCompile Include="..\..\src\burner\win32\res.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\win32\roms.cpp" /> <ClCompile Include="..\..\src\burner\win32\roms.cpp" />
<ClCompile Include="..\..\src\burner\win32\run.cpp" /> <ClCompile Include="..\..\src\burner\win32\run.cpp" />
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" /> <ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
@@ -1465,8 +1465,8 @@
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp"> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp"> <ClCompile Include="..\..\src\burner\cdlist.cpp">
<Filter>burner\win32</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp"> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
@@ -3388,6 +3388,9 @@
<ClCompile Include="..\..\src\burner\nvram.cpp"> <ClCompile Include="..\..\src\burner\nvram.cpp">
<Filter>burner</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp"> <ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
@@ -3568,9 +3571,6 @@
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp"> <ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
<Filter>burn\drv\pre90s</Filter> <Filter>burn\drv\pre90s</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp"> <ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
<Filter>burn\drv\taito</Filter> <Filter>burn\drv\taito</Filter>
</ClCompile> </ClCompile>
@@ -34,6 +34,7 @@
<ClCompile Include="..\..\src\burner\luasav.cpp" /> <ClCompile Include="..\..\src\burner\luasav.cpp" />
<ClCompile Include="..\..\src\burner\misc.cpp" /> <ClCompile Include="..\..\src\burner\misc.cpp" />
<ClCompile Include="..\..\src\burner\nvram.cpp" /> <ClCompile Include="..\..\src\burner\nvram.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\sshot.cpp" /> <ClCompile Include="..\..\src\burner\sshot.cpp" />
<ClCompile Include="..\..\src\burner\state.cpp" /> <ClCompile Include="..\..\src\burner\state.cpp" />
<ClCompile Include="..\..\src\burner\statec.cpp" /> <ClCompile Include="..\..\src\burner\statec.cpp" />
@@ -66,7 +67,7 @@
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" /> <ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
<ClCompile Include="..\..\src\burner\win32\menu.cpp" /> <ClCompile Include="..\..\src\burner\win32\menu.cpp" />
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" /> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp" /> <ClCompile Include="..\..\src\burner\cdlist.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" /> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" />
<ClCompile Include="..\..\src\burner\win32\numdial.cpp" /> <ClCompile Include="..\..\src\burner\win32\numdial.cpp" />
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" /> <ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
@@ -75,7 +76,6 @@
<ClCompile Include="..\..\src\burner\win32\progress.cpp" /> <ClCompile Include="..\..\src\burner\win32\progress.cpp" />
<ClCompile Include="..\..\src\burner\win32\replay.cpp" /> <ClCompile Include="..\..\src\burner\win32\replay.cpp" />
<ClCompile Include="..\..\src\burner\win32\res.cpp" /> <ClCompile Include="..\..\src\burner\win32\res.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\win32\roms.cpp" /> <ClCompile Include="..\..\src\burner\win32\roms.cpp" />
<ClCompile Include="..\..\src\burner\win32\run.cpp" /> <ClCompile Include="..\..\src\burner\win32\run.cpp" />
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" /> <ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
@@ -1465,8 +1465,8 @@
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp"> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp"> <ClCompile Include="..\..\src\burner\cdlist.cpp">
<Filter>burner\win32</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp"> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
@@ -3388,6 +3388,9 @@
<ClCompile Include="..\..\src\burner\nvram.cpp"> <ClCompile Include="..\..\src\burner\nvram.cpp">
<Filter>burner</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp"> <ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
@@ -3568,9 +3571,6 @@
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp"> <ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
<Filter>burn\drv\pre90s</Filter> <Filter>burn\drv\pre90s</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp"> <ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
<Filter>burn\drv\taito</Filter> <Filter>burn\drv\taito</Filter>
</ClCompile> </ClCompile>
@@ -1036,6 +1036,7 @@
<ClCompile Include="..\..\src\burner\luasav.cpp" /> <ClCompile Include="..\..\src\burner\luasav.cpp" />
<ClCompile Include="..\..\src\burner\misc.cpp" /> <ClCompile Include="..\..\src\burner\misc.cpp" />
<ClCompile Include="..\..\src\burner\nvram.cpp" /> <ClCompile Include="..\..\src\burner\nvram.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\sshot.cpp" /> <ClCompile Include="..\..\src\burner\sshot.cpp" />
<ClCompile Include="..\..\src\burner\state.cpp" /> <ClCompile Include="..\..\src\burner\state.cpp" />
<ClCompile Include="..\..\src\burner\statec.cpp" /> <ClCompile Include="..\..\src\burner\statec.cpp" />
@@ -1069,7 +1070,7 @@
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" /> <ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
<ClCompile Include="..\..\src\burner\win32\menu.cpp" /> <ClCompile Include="..\..\src\burner\win32\menu.cpp" />
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" /> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp" /> <ClCompile Include="..\..\src\burner\cdlist.cpp" />
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" /> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp" />
<ClCompile Include="..\..\src\burner\win32\numdial.cpp" /> <ClCompile Include="..\..\src\burner\win32\numdial.cpp" />
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" /> <ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
@@ -1078,7 +1079,6 @@
<ClCompile Include="..\..\src\burner\win32\progress.cpp" /> <ClCompile Include="..\..\src\burner\win32\progress.cpp" />
<ClCompile Include="..\..\src\burner\win32\replay.cpp" /> <ClCompile Include="..\..\src\burner\win32\replay.cpp" />
<ClCompile Include="..\..\src\burner\win32\res.cpp" /> <ClCompile Include="..\..\src\burner\win32\res.cpp" />
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
<ClCompile Include="..\..\src\burner\win32\roms.cpp" /> <ClCompile Include="..\..\src\burner\win32\roms.cpp" />
<ClCompile Include="..\..\src\burner\win32\run.cpp" /> <ClCompile Include="..\..\src\burner\win32\run.cpp" />
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" /> <ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
@@ -3007,6 +3007,9 @@
<ClCompile Include="..\..\src\burner\nvram.cpp"> <ClCompile Include="..\..\src\burner\nvram.cpp">
<Filter>burner</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burner\sshot.cpp"> <ClCompile Include="..\..\src\burner\sshot.cpp">
<Filter>burner</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
@@ -3106,8 +3109,8 @@
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp"> <ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp"> <ClCompile Include="..\..\src\burner\cdlist.cpp">
<Filter>burner\win32</Filter> <Filter>burner</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp"> <ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
@@ -3133,9 +3136,6 @@
<ClCompile Include="..\..\src\burner\win32\res.cpp"> <ClCompile Include="..\..\src\burner\win32\res.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
<Filter>burner\win32</Filter>
</ClCompile>
<ClCompile Include="..\..\src\burner\win32\roms.cpp"> <ClCompile Include="..\..\src\burner\win32\roms.cpp">
<Filter>burner\win32</Filter> <Filter>burner\win32</Filter>
</ClCompile> </ClCompile>
+590
View File
@@ -0,0 +1,590 @@
#include "burner.h"
#include "cdlist.h"
#include "neocdlist.h"
#include "cd_img.h"
#include "neocdlist_games.h"
#include "pcecdlist_games.h"
static NGCDGAME* pNeoGame;
static void CopyText(TCHAR* pszDest, UINT32 nDest, const TCHAR* pszSource)
{
if (!pszDest || !nDest)
return;
if (!pszSource)
pszSource = _T("");
_tcsncpy(pszDest, pszSource, nDest - 1);
pszDest[nDest - 1] = 0;
}
static TCHAR* DuplicateText(const TCHAR* pszSource)
{
if (!pszSource)
return NULL;
UINT32 nLength = (UINT32)_tcslen(pszSource) + 1;
TCHAR* pszDest = (TCHAR*)malloc(nLength * sizeof(TCHAR));
if (pszDest)
memcpy(pszDest, pszSource, nLength * sizeof(TCHAR));
return pszDest;
}
static INT32 FindTextI(const TCHAR* pszText, const TCHAR* pszNeedle)
{
if (!pszText || !pszNeedle || !*pszNeedle)
return 0;
for (; *pszText; pszText++) {
const TCHAR* pText = pszText;
const TCHAR* pNeedle = pszNeedle;
while (*pText && *pNeedle && _totlower(*pText) == _totlower(*pNeedle)) {
pText++; pNeedle++;
}
if (!*pNeedle)
return 1;
}
return 0;
}
static UINT32 ReadLE32(const UINT8* pData)
{
return (UINT32)pData[0] | ((UINT32)pData[1] << 8) | ((UINT32)pData[2] << 16) | ((UINT32)pData[3] << 24);
}
static INT32 ReadSector(CDImage* pImage, INT32 nLba, UINT8* pData, INT32* pnSize)
{
INT32 nSize = 0;
if (CDImageReadUserSector(pImage, nLba, pData, &nSize))
return 0;
if (pnSize)
*pnSize = nSize;
return nSize > 0;
}
static const CDImageTrack* FindDataTrack(const CDImage* pImage)
{
for (INT32 i = 0; i < CDImageGetTrackCount(pImage); i++) {
const CDImageTrack* pTrack = CDImageGetTrack(pImage, i);
if (pTrack && pTrack->nType != CDIMAGE_TRACK_AUDIO)
return pTrack;
}
return NULL;
}
NGCDGAME* GetNeoGeoCDInfo(UINT32 nID)
{
for (UINT32 i = 0; i < sizeof(games) / sizeof(games[0]); i++) {
if (games[i].id == nID)
return &games[i];
}
return NULL;
}
void FreeNGCDGame(NGCDGAME** ppGame)
{
if (!ppGame || !*ppGame)
return;
free_s((void**)&((*ppGame)->pszName));
free_s((void**)&((*ppGame)->pszTitle));
free_s((void**)&((*ppGame)->pszYear));
free_s((void**)&((*ppGame)->pszCompany));
free(*ppGame); *ppGame = NULL;
}
INT32 GetNGCDGameTitle(const UINT32 nGameID, NGCDGAME** ppOutGame, bool bPrintLog)
{
if (!ppOutGame)
return 0;
*ppOutGame = NULL;
NGCDGAME* pSource = GetNeoGeoCDInfo(nGameID);
if (!pSource)
return 0;
NGCDGAME* pGame = (NGCDGAME*)calloc(1, sizeof(NGCDGAME));
if (!pGame)
return 0;
pGame->id = pSource->id;
pGame->pszName = DuplicateText(pSource->pszName);
pGame->pszTitle = DuplicateText(pSource->pszTitle);
pGame->pszYear = DuplicateText(pSource->pszYear);
pGame->pszCompany = DuplicateText(pSource->pszCompany);
if (!pGame->pszName || !pGame->pszTitle || !pGame->pszYear || !pGame->pszCompany) {
FreeNGCDGame(&pGame);
return 0;
}
if (bPrintLog) {
bprintf(PRINT_NORMAL, _T(" Title: %s\n" ), pGame->pszTitle);
bprintf(PRINT_NORMAL, _T(" Shortname: %s\n"), pGame->pszName);
bprintf(PRINT_NORMAL, _T(" Year: %s\n" ), pGame->pszYear);
bprintf(PRINT_NORMAL, _T(" Company: %s\n" ), pGame->pszCompany);
}
*ppOutGame = pGame;
return 1;
}
static UINT32 ReviseNeoID(UINT32 nID, const UINT8* pDate, const UINT8* pData, INT32 bGotDDPRG, const char* pszVolume, const TCHAR* pszPath)
{
if ((nID == 0x0016 || nID == 0x0025 || nID == 0x0076 || nID == 0x0062) && pDate[0] == 94 && pDate[1] == 12 && pDate[2] == 20) nID |= 0x1000; // Justin Gibbons Hacks (kotm | eightman |zedblade | spinmast)
if ( nID == 0x0059 && pDate[0] == 95 && pDate[1] == 6 && pDate[2] == 20) nID |= 0x1000; // Savage Reign Rev 1
if ( nID == 0x0066 && pDate[0] == 125 && pDate[1] == 4 && pDate[2] == 10) nID |= 0x1200; // Digger Man (Prototype)
if ( nID == 0x069c && pDate[0] == 95 && pDate[1] == 4 && pDate[2] == 29) nID |= 0x1000; // Fatal Fury 3 Rev 1
if ( nID == 0x069c && pDate[0] == 95 && pDate[1] == 6 && pDate[2] == 1) nID |= 0x2000; // Fatal Fury 3 Rev 2
if ( nID == 0x069c && pDate[0] == 95 && pDate[1] == 7 && pDate[2] == 10) nID |= 0x3000; // Fatal Fury 3 Rev 3
if ( nID == 0x0090 && pDate[0] == 95 && pDate[1] == 7 && pDate[2] == 21) nID |= 0x1000; // World Heroes Perfect
if ( nID == 0x0058 && pDate[0] == 94 && pDate[1] == 10 && pDate[2] == 14) nID |= 0x1000; // Fatal Fury Special Rev 1
if ( nID == 0x0052 && pDate[0] == 123 && pDate[1] == 7 && pDate[2] == 1) nID |= 0x1000; // Abyssal Infants
if ( nID == 0x0052 && pDate[0] == 123 && pDate[1] == 6 && pDate[2] == 20) nID |= 0x1001; // Neo Fight
if ( nID == 0x0082) {
if (bGotDDPRG) nID |= 0x1000; // Double Dragon Rev 1
else if (FindTextI(pszPath, _T("OST")) || FindTextI(pszPath, _T("PS")) || FindTextI(pszPath, _T("PlayStation"))) nID |= 0x2000; // Double Dragon PS1 OST
}
if (nID == 0x0085) {
if ( pDate[0] == 123 && pDate[1] == 11 && pDate[2] == 29) nID |= 0x1000; // Samurai Shodown RPG (English Translation)
else if (pDate[0] == 124 && pDate[1] == 1 && pDate[2] == 26) nID |= 0x3000; // Samurai Shodown RPG (English Translation v1.1)
else if (pDate[0] == 126 && pDate[1] == 6 && pDate[2] == 1) nID |= 0x4000; // Samurai Shodown RPG (Simplified Chinese Translation v1.1)
else if (FindTextI(pszPath, _T("FR")) || FindTextI(pszPath, _T("French"))) nID |= 0x2000; // Samurai Shodown RPG (FR)
}
if (nID == 0x5345 && (!strcmp(pszVolume, "BLUEANDREDFIGHTTHEROBOTS") || FindTextI(pszPath, _T("NTSC")))) nID = 0x5346; // Blue And Red - Fight The Robots! (NTSC)
if (nID == 0x1234 && pDate[0] == 105 && pDate[1] == 4 && pDate[2] == 25) nID = 0x2234; // Neo Puzzle League
if (nID == 0x1234 && pDate[0] == 124 && pDate[1] == 12 && pDate[2] == 2) nID = 0x2235; // Neo Tetris
if (nID == 0x1234 && pDate[0] == 112 && pDate[1] == 3 && pDate[2] == 4) nID = 0x2236; // NGD::ARK
if (nID == 0x1234 && pDate[0] == 112 && pDate[1] == 12 && pDate[2] == 4) nID = 0x2237; // Santa Ball
if (nID == 0x2000 && !strcmp(pszVolume, "COLUMNS")) nID |= 0x1000; // Columns
if (nID == 0xffff && !strcmp(pszVolume, "CODENAME BLUT ENGEL")) nID = 0xfffe; // Codename Blut Engel
if (nID == 0x7777 && pDate[0] == 114 && pDate[1] == 8 && pDate[2] == 14) nID = 0x7778; // Puzzle de Pon! CD Collection
if (nID == 0x2019 && !strcmp(pszVolume, "LOOPTRSP")) nID |= 0x0100; // Looptris Plus
if (nID == 0x0048 && pData[0x67] == 0x08) nID |= 0x1000; // Treasure of Caribbean (c) 1994 / (c) 2011 NCI
if (nID == 0x0055 && pData[0x67] == 0xdE) /* 10-6-1994 (P1.PRG) */ {/* ...continue*/ } // King of Fighters '94, The (1994)(SNK)(JP)
if (nID == 0x0055 && pData[0x67] == 0xe6) /* 11-21-1994 (P1.PRG) */ nID |= 0x1000; // King of Fighters '94, The (1994)(SNK)(JP-US)
if (nID == 0x0084 && pData[0x6C] == 0xc0) /* 9-11-1995 (P1.PRG) */ {/* ...continue*/ } // King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B01, B03-B06, NGCD-084E MT B01]
if (nID == 0x0084 && pData[0x6c] == 0xff) /* 10-5-1995 (P1.PRG) */ nID |= 0x1000; // King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B10, NGCD-084E MT B03]
return nID;
}
static INT32 IdentifyNeo(CDImage* pImage, const TCHAR* pszPath, CDListResult* pResult)
{
const CDImageTrack* pTrack = FindDataTrack(pImage);
if (!pTrack)
return 0;
UINT8 pvd[2448] = { 0 };
INT32 nSize = 0;
if (!ReadSector(pImage, pTrack->nIndex1LBA + 16, pvd, &nSize) || nSize < 190 || memcmp(pvd + 1, "CD001", 5))
return 0;
char szVolume[33] = { 0 };
memcpy(szVolume, pvd + 40, 32);
for (INT32 i = 31; i >= 0 && szVolume[i] == ' '; i--)
szVolume[i] = 0;
UINT32 nRootLba = ReadLE32(pvd + 158);
UINT32 nRootSize = ReadLE32(pvd + 166);
if (!nRootLba || !nRootSize)
return 0;
INT32 bGotDDPRG = 0;
INT32 bQueued = 0;
UINT32 nQueuedID = 0;
for (UINT32 nPosition = 0; nPosition < nRootSize;) {
UINT8 sector[2448] = { 0 };
INT32 nSectorSize = 0;
UINT32 nSector = nPosition / 2048;
UINT32 nOffset = nPosition % 2048;
if (!ReadSector(pImage, pTrack->nIndex1LBA + (INT32)nRootLba + (INT32)nSector, sector, &nSectorSize)) break;
if (nOffset >= (UINT32)nSectorSize)
break;
UINT8 nLength = sector[nOffset];
if (!nLength) {
nPosition = (nPosition + 2048) & ~2047U;
continue;
}
if (nOffset + nLength > (UINT32)nSectorSize || nLength < 34)
break;
const UINT8* pRecord = sector + nOffset;
UINT8 nNameLength = pRecord[32];
if (!(pRecord[25] & 2) && nNameLength && 33 + nNameLength <= nLength) {
char szName[256] = { 0 };
UINT32 nCopy = nNameLength < sizeof(szName) - 1 ? nNameLength : sizeof(szName) - 1;
memcpy(szName, pRecord + 33, nCopy);
char* pVersion = strchr(szName, ';');
if (pVersion)
*pVersion = 0;
if (!strcmp(szName, "DDPRG.ACM"))
bGotDDPRG = 1;
UINT32 nFileLba = ReadLE32(pRecord + 2);
UINT8 data[2448] = { 0 };
INT32 nDataSize = 0;
if (ReadSector(pImage, pTrack->nIndex1LBA + (INT32)nFileLba, data, &nDataSize) && nDataSize >= 0x10a && !memcmp(data + 0x100, "NEO-GEO", 7)) {
UINT32 nID = ((UINT32)data[0x108] << 8) | data[0x109];
nID = ReviseNeoID(nID, pRecord + 18, data, bGotDDPRG, szVolume, pszPath);
if (nID == 0x0229) {
pResult->nNeoID = nID;
return 1;
}
if ( nID == 0x0214 || // King of Fighters '96, The
(nID == 0x0058 && !(pRecord[18] == 94 && pRecord[19] == 8 && pRecord[20] == 5))) { // !Fatal Fury Special Rev 0
// continue checking other files...
bQueued = 1;
nQueuedID = nID;
} else {
pResult->nNeoID = nID;
return 1;
}
}
}
nPosition += nLength;
}
if (bQueued) {
pResult->nNeoID = nQueuedID;
return 1;
}
return 0;
}
struct CDListSha1
{
UINT32 State[5];
UINT64 nBytes;
UINT8 Buffer[64];
};
static UINT32 RotateLeft(UINT32 nValue, INT32 nBits)
{
return (nValue << nBits) | (nValue >> (32 - nBits));
}
static void Sha1Transform(CDListSha1* pSha1, const UINT8* pData)
{
UINT32 w[80];
for (INT32 i = 0; i < 16; i++)
w[i] = ((UINT32)pData[i * 4] << 24) | ((UINT32)pData[i * 4 + 1] << 16) | ((UINT32)pData[i * 4 + 2] << 8) | pData[i * 4 + 3];
for (INT32 i = 16; i < 80; i++)
w[i] = RotateLeft(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
UINT32 a = pSha1->State[0];
UINT32 b = pSha1->State[1];
UINT32 c = pSha1->State[2];
UINT32 d = pSha1->State[3];
UINT32 e = pSha1->State[4];
for (INT32 i = 0; i < 80; i++) {
UINT32 f, k;
if (i < 20) {
f = (b & c) | (~b & d); k = 0x5a827999;
} else if (i < 40) {
f = b ^ c ^ d; k = 0x6ed9eba1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc;
} else {
f = b ^ c ^ d; k = 0xca62c1d6;
}
UINT32 nTemp = RotateLeft(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = RotateLeft(b, 30);
b = a;
a = nTemp;
}
pSha1->State[0] += a;
pSha1->State[1] += b;
pSha1->State[2] += c;
pSha1->State[3] += d;
pSha1->State[4] += e;
}
static void Sha1Init(CDListSha1* pSha1)
{
pSha1->State[0] = 0x67452301;
pSha1->State[1] = 0xefcdab89;
pSha1->State[2] = 0x98badcfe;
pSha1->State[3] = 0x10325476;
pSha1->State[4] = 0xc3d2e1f0;
pSha1->nBytes = 0;
}
static void Sha1Update(CDListSha1* pSha1, const UINT8* pData, UINT32 nLength)
{
UINT32 nUsed = (UINT32)(pSha1->nBytes & 63);
pSha1->nBytes += nLength;
while (nLength) {
UINT32 nCopy = 64 - nUsed;
if (nCopy > nLength)
nCopy = nLength;
memcpy(pSha1->Buffer + nUsed, pData, nCopy);
nUsed += nCopy;
pData += nCopy;
nLength -= nCopy;
if (nUsed == 64) {
Sha1Transform(pSha1, pSha1->Buffer);
nUsed = 0;
}
}
}
static void Sha1Final(CDListSha1* pSha1, UINT8* pDigest)
{
UINT64 nBits = pSha1->nBytes * 8;
UINT8 pFinal[72] = { 0x80 };
UINT32 nUsed = (UINT32)(pSha1->nBytes & 63);
UINT32 nPadding = nUsed < 56 ? 56 - nUsed : 120 - nUsed;
for (INT32 i = 0; i < 8; i++)
pFinal[nPadding + i] = (UINT8)(nBits >> (56 - i * 8));
Sha1Update(pSha1, pFinal, nPadding + 8);
for (INT32 i = 0; i < 5; i++) {
pDigest[i * 4 + 0] = (UINT8)(pSha1->State[i] >> 24);
pDigest[i * 4 + 1] = (UINT8)(pSha1->State[i] >> 16);
pDigest[i * 4 + 2] = (UINT8)(pSha1->State[i] >> 8);
pDigest[i * 4 + 3] = (UINT8) pSha1->State[i];
}
}
static INT32 HashDataTrack(CDImage* pImage, const CDImageTrack* pTrack, UINT8* pDigest)
{
if (!pImage || !pTrack || !pDigest || pTrack->nSectors <= 0)
return 0;
CDListSha1 Sha1;
Sha1Init(&Sha1);
UINT8 sector[2448];
for (INT32 i = 0; i < pTrack->nSectors; i++) {
INT32 nSize = 0;
if (!ReadSector(pImage, pTrack->nIndex1LBA + i, sector, &nSize))
return 0;
Sha1Update(&Sha1, sector, (UINT32)nSize);
}
Sha1Final(&Sha1, pDigest);
return 1;
}
static UINT32 CalculateCrc32(const UINT8* pData, UINT32 nLength)
{
UINT32 nCrc = 0xffffffff;
for (UINT32 i = 0; i < nLength; i++) {
nCrc ^= pData[i];
for (INT32 j = 0; j < 8; j++)
nCrc = (nCrc >> 1) ^ (0xedb88320U & (0U - (nCrc & 1)));
}
return nCrc ^ 0xffffffff;
}
static INT32 IsGamesExpress(CDImage* pImage, const CDImageTrack* pTrack, UINT8* pSector)
{
INT32 nSize = 0;
if (!ReadSector(pImage, pTrack->nIndex1LBA + 0x10, pSector, &nSize) || nSize < 0x1c) return 0;
if (!memcmp(pSector + 8, "HACKER CD ROM SYSTEM", 20)) return 1;
if (memcmp(pSector + 1, "CD001", 5)) return 0;
if (!ReadSector(pImage, pTrack->nIndex1LBA + 0x14, pSector, &nSize) || nSize != 2048) return 0;
UINT32 nCrc = CalculateCrc32(pSector, 2048);
return nCrc == 0xd7b47c06 || nCrc == 0x86aec522 || nCrc == 0xc8d1b5ef || nCrc == 0x0bdbde64;
}
static INT32 IdentifyPlatform(CDImage* pImage, CDListResult* pResult)
{
static const UINT8 pPceMagic[32] = {
0x82, 0xb1, 0x82, 0xcc, 0x83, 0x76, 0x83, 0x8d,
0x83, 0x4f, 0x83, 0x89, 0x83, 0x80, 0x82, 0xcc,
0x92, 0x98, 0x8d, 0xec, 0x8c, 0xa0, 0x82, 0xcd,
0x8a, 0x94, 0x8e, 0xae, 0x89, 0xef, 0x8e, 0xd0
};
UINT8 sector[2448] = { 0 };
for (INT32 i = 0; i < CDImageGetTrackCount(pImage); i++) {
const CDImageTrack* pTrack = CDImageGetTrack(pImage, i);
INT32 nSize = 0;
if (pTrack && pTrack->nType != CDIMAGE_TRACK_AUDIO && ReadSector(pImage, pTrack->nIndex1LBA, sector, &nSize) && nSize >= 15 && !memcmp(sector, "PC-FX:Hu_CD-ROM", 15)) {
pResult->nPlatform = CDLIST_PLATFORM_PCFX;
pResult->nSource = CDLIST_SOURCE_MAGIC;
pResult->nConfidence = CDLIST_CONFIDENCE_EXACT;
CopyText(pResult->Metadata.szDescriptor, CDLIST_TEXT_SIZE, _T("PC-FX boot signature"));
return 1;
}
}
const CDImageTrack* pTrack = FindDataTrack(pImage);
if (!pTrack)
return 0;
INT32 nSize = 0;
if (ReadSector(pImage, pTrack->nIndex1LBA, sector, &nSize) && nSize >= 32 && !memcmp(sector, pPceMagic, sizeof(pPceMagic))) {
pResult->nPlatform = CDLIST_PLATFORM_PCECD;
pResult->nSource = CDLIST_SOURCE_MAGIC;
pResult->nConfidence = CDLIST_CONFIDENCE_STRONG;
CopyText(pResult->Metadata.szRequirement, CDLIST_TEXT_SIZE, _T("PC Engine CD System Card"));
CopyText(pResult->Metadata.szDescriptor, CDLIST_TEXT_SIZE, _T("PC Engine program copyright header"));
return 1;
}
if (ReadSector(pImage, pTrack->nIndex1LBA + 1, sector, &nSize) && nSize >= 55 && !memcmp(sector + 0x20, "PC Engine CD-ROM SYSTEM", 23)) {
pResult->nPlatform = CDLIST_PLATFORM_PCECD;
pResult->nSource = CDLIST_SOURCE_MAGIC;
pResult->nConfidence = CDLIST_CONFIDENCE_EXACT;
CopyText(pResult->Metadata.szRequirement, CDLIST_TEXT_SIZE, _T("PC Engine CD System Card"));
CopyText(pResult->Metadata.szDescriptor, CDLIST_TEXT_SIZE, _T("PC Engine CD-ROM SYSTEM header"));
return 1;
}
if (IsGamesExpress(pImage, pTrack, sector)) {
pResult->nPlatform = CDLIST_PLATFORM_PCECD;
pResult->nSource = CDLIST_SOURCE_MAGIC;
pResult->nConfidence = CDLIST_CONFIDENCE_EXACT;
CopyText(pResult->Metadata.szRequirement, CDLIST_TEXT_SIZE, _T("Games Express CD Card"));
CopyText(pResult->Metadata.szDescriptor, CDLIST_TEXT_SIZE, _T("Games Express disc signature"));
return 1;
}
return 0;
}
#ifdef BUILD_WIN32
static void CopyAnsiText(TCHAR* pszDest, UINT32 nDest, const char* pszSource)
{
if (!pszDest || !nDest) return;
INT32 nLength = pszSource ? MultiByteToWideChar(65001, 0, pszSource, -1, NULL, 0) : 0;
if (nLength > 0) MultiByteToWideChar(65001, 0, pszSource, -1, pszDest, (int)nDest);
if (nLength <= 0) pszDest[0] = 0;
pszDest[nDest - 1] = 0;
}
#else
#define CopyAnsiText CopyText
#endif
static INT32 FindPceChdGame(const UINT8* pSha1, CDListMetadata* pMetadata)
{
if (!pSha1 || !pMetadata)
return 0;
UINT32 nLow = 0;
UINT32 nHigh = pceCdGameCount;
while (nLow < nHigh) {
UINT32 nMiddle = nLow + (nHigh - nLow) / 2;
INT32 nCompare = memcmp(pSha1, pceCdGames[nMiddle].sha1, CDLIST_SHA1_SIZE);
if (nCompare > 0) nLow = nMiddle + 1;
else nHigh = nMiddle;
}
if (nLow >= pceCdGameCount || memcmp(pSha1, pceCdGames[nLow].sha1, CDLIST_SHA1_SIZE)) return 0;
const PceCdGame* pGame = &pceCdGames[nLow];
CopyAnsiText(pMetadata->szName, CDLIST_TEXT_SIZE, pceCdGameStringData + pGame->shortname);
CopyAnsiText(pMetadata->szTitle, CDLIST_TEXT_SIZE, pceCdGameStringData + pGame->description);
CopyAnsiText(pMetadata->szYear, 32, pceCdGameStringData + pGame->year);
CopyAnsiText(pMetadata->szCompany, CDLIST_TEXT_SIZE, pceCdGameStringData + pGame->publisher);
CopyAnsiText(pMetadata->szRegion, 64, pceCdGameStringData + pGame->region);
CopyAnsiText(pMetadata->szRequirement, CDLIST_TEXT_SIZE, pceCdGameStringData + pGame->requirement);
CopyText(pMetadata->szDescriptor, CDLIST_TEXT_SIZE, _T("MAME pcecd CHD SHA1"));
return 1;
}
static void FillNeoMetadata(CDListResult* pResult)
{
NGCDGAME* pGame = GetNeoGeoCDInfo(pResult->nNeoID);
if (!pGame)
return;
CopyText(pResult->Metadata.szName, CDLIST_TEXT_SIZE, pGame->pszName);
CopyText(pResult->Metadata.szTitle, CDLIST_TEXT_SIZE, pGame->pszTitle);
CopyText(pResult->Metadata.szYear, 32, pGame->pszYear);
CopyText(pResult->Metadata.szCompany, CDLIST_TEXT_SIZE, pGame->pszCompany);
CopyText(pResult->Metadata.szDescriptor, CDLIST_TEXT_SIZE, _T("Neo Geo CD program header"));
}
INT32 CDListIdentify(const TCHAR* pszPath, CDListResult* pResult)
{
if (!pszPath || !pResult)
return 0;
memset(pResult, 0, sizeof(*pResult));
CDImage* pImage = CDImageOpen(pszPath);
if (!pImage)
return 0;
if (!CDImageGetChdSha1(pImage, pResult->ChdSha1)) {
pResult->bHasChdSha1 = 1;
pResult->bRawSha1Unsupported = 1;
pResult->bChdMameMatch = FindPceChdGame(pResult->ChdSha1, &pResult->ChdMetadata);
} else {
const CDImageTrack* pTrack = FindDataTrack(pImage);
pResult->bHasRawSha1 = HashDataTrack(pImage, pTrack, pResult->RawSha1);
}
if (IdentifyNeo(pImage, pszPath, pResult)) {
pResult->nPlatform = CDLIST_PLATFORM_NEOCD;
pResult->nSource = CDLIST_SOURCE_NEO_ID;
pResult->nConfidence = CDLIST_CONFIDENCE_EXACT;
FillNeoMetadata(pResult);
} else {
IdentifyPlatform(pImage, pResult);
if (pResult->bChdMameMatch) {
pResult->Metadata = pResult->ChdMetadata;
pResult->nPlatform = CDLIST_PLATFORM_PCECD;
pResult->nSource = CDLIST_SOURCE_CHD_SHA1;
pResult->nConfidence = CDLIST_CONFIDENCE_EXACT;
}
}
CDImageClose(pImage);
return pResult->nPlatform != CDLIST_PLATFORM_UNKNOWN;
}
INT32 NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*))
{
CDListResult Result;
if (CDListIdentify(pszFile, &Result) && Result.nPlatform == CDLIST_PLATFORM_NEOCD) {
if (pfEntryCallBack) pfEntryCallBack((INT32)Result.nNeoID, pszFile);
return 1;
}
return 0;
}
INT32 GetNeoCDTitle(UINT32 nGameID)
{
FreeNGCDGame(&pNeoGame);
return GetNGCDGameTitle(nGameID, &pNeoGame, true);
}
INT32 GetNeoGeoCD_Identifier()
{
#ifdef BUILD_NEOGEO
TCHAR* pszPath = GetIsoPath();
if (!pszPath || !IsNeoGeoCD())
return 0;
CDListResult Result;
if (CDListIdentify(pszPath, &Result) && Result.nPlatform == CDLIST_PLATFORM_NEOCD) {
GetNeoCDTitle(Result.nNeoID);
return 1;
}
return 0;
#else
return 0;
#endif
}
#ifdef BUILD_NEOGEO
INT32 NeoCDInfo_Init()
{
NeoCDInfo_Exit();
return GetNeoGeoCD_Identifier();
}
TCHAR* NeoCDInfo_Text(INT32 nText)
{
if (!pNeoGame || !IsNeoGeoCD())
return NULL;
switch (nText) {
case DRV_NAME: return pNeoGame->pszName;
case DRV_FULLNAME: return pNeoGame->pszTitle;
case DRV_MANUFACTURER: return pNeoGame->pszCompany;
case DRV_DATE: return pNeoGame->pszYear;
}
return NULL;
}
INT32 NeoCDInfo_ID()
{
if (!pNeoGame || !IsNeoGeoCD())
return 0;
return (INT32)pNeoGame->id;
}
void NeoCDInfo_Exit()
{
FreeNGCDGame(&pNeoGame);
}
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifndef CDLIST_H_
#define CDLIST_H_
#define CDLIST_SHA1_SIZE (20)
#define CDLIST_TEXT_SIZE (256)
enum CDListPlatform {
CDLIST_PLATFORM_UNKNOWN = 0,
CDLIST_PLATFORM_NEOCD,
CDLIST_PLATFORM_PCECD,
CDLIST_PLATFORM_PCFX
};
enum CDListSource {
CDLIST_SOURCE_NONE = 0,
CDLIST_SOURCE_MAGIC,
CDLIST_SOURCE_NEO_ID,
CDLIST_SOURCE_CHD_SHA1,
CDLIST_SOURCE_RAW_SHA1
};
enum CDListConfidence {
CDLIST_CONFIDENCE_NONE = 0,
CDLIST_CONFIDENCE_POSSIBLE,
CDLIST_CONFIDENCE_STRONG,
CDLIST_CONFIDENCE_EXACT
};
struct CDListMetadata {
TCHAR szName[CDLIST_TEXT_SIZE];
TCHAR szTitle[CDLIST_TEXT_SIZE];
TCHAR szYear[32];
TCHAR szCompany[CDLIST_TEXT_SIZE];
TCHAR szRegion[64];
TCHAR szRequirement[CDLIST_TEXT_SIZE];
TCHAR szDescriptor[CDLIST_TEXT_SIZE];
};
struct CDListResult {
INT32 nPlatform;
INT32 nSource;
INT32 nConfidence;
UINT32 nNeoID;
CDListMetadata Metadata;
INT32 bHasChdSha1;
UINT8 ChdSha1[CDLIST_SHA1_SIZE];
INT32 bChdMameMatch;
CDListMetadata ChdMetadata;
INT32 bHasRawSha1;
INT32 bRawSha1Unsupported;
UINT8 RawSha1[CDLIST_SHA1_SIZE];
};
INT32 CDListIdentify(const TCHAR* pszPath, CDListResult* pResult);
#endif
+16 -129
View File
@@ -1,5 +1,7 @@
#ifndef _neocdlist_ #ifndef NEOCDLIST_H_
#define _neocdlist_ #define NEOCDLIST_H_
#include "cdlist.h"
struct NGCDGAME struct NGCDGAME
{ {
@@ -11,143 +13,28 @@ struct NGCDGAME
}; };
NGCDGAME* GetNeoGeoCDInfo(UINT32 nID); NGCDGAME* GetNeoGeoCDInfo(UINT32 nID);
INT32 GetNeoCDTitle(UINT32 nGameID); INT32 GetNGCDGameTitle(const UINT32 nGameID, NGCDGAME** ppOutGame, bool bPrintLog);
INT32 GetNeoGeoCD_Identifier(); void FreeNGCDGame(NGCDGAME** ppGame);
INT32 NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*));
INT32 GetNeoCDTitle(UINT32 nGameID);
INT32 GetNeoGeoCD_Identifier();
#ifdef BUILD_NEOGEO #ifdef BUILD_NEOGEO
bool IsNeoGeoCD(); // neo_run.cpp bool IsNeoGeoCD(); // neo_run.cpp
TCHAR* GetIsoPath(); // cd_isowav.cpp TCHAR* GetIsoPath(); // cd_isowav.cpp
INT32 NeoCDInfo_Init(); INT32 NeoCDInfo_Init();
TCHAR* NeoCDInfo_Text(INT32 nText); TCHAR* NeoCDInfo_Text(INT32 nText);
INT32 NeoCDInfo_ID(); INT32 NeoCDInfo_ID();
void NeoCDInfo_SetTitle(); void NeoCDInfo_SetTitle();
void NeoCDInfo_Exit(); void NeoCDInfo_Exit();
#else #else
static inline bool IsNeoGeoCD() { return false; } static inline bool IsNeoGeoCD() { return false; }
static inline TCHAR* GetIsoPath() { return NULL; } static inline TCHAR* GetIsoPath() { return NULL; }
static inline int NeoCDInfo_Init() { return 0; } static inline INT32 NeoCDInfo_Init() { return 0; }
static inline TCHAR* NeoCDInfo_Text(int) { return NULL; } static inline TCHAR* NeoCDInfo_Text(INT32) { return NULL; }
static inline int NeoCDInfo_ID() { return 0; } static inline INT32 NeoCDInfo_ID() { return 0; }
static inline void NeoCDInfo_SetTitle() { } static inline void NeoCDInfo_SetTitle() { }
static inline void NeoCDInfo_Exit() { } static inline void NeoCDInfo_Exit() { }
#endif #endif
// ------------------------------------------------------
// ISO9660 STUFF
// ISO9660 date and time
struct iso9660_date
{
UINT8 Year; // Number of year since 1900
UINT8 Month; // Month (1 to 12)
UINT8 Day; // Day (1 to 31)
UINT8 Hour; // Hour (0 to 23)
UINT8 Minute; // Minute (0 to 59)
UINT8 Second; // Second (0 to 59)
UINT8 Zone; // Offset related to GMT, by 15-min INT32erval (from -48 to +52)
};
// ISO9660 BCD date and time
struct iso9660_bcd_date
{
UINT8 Year[4];
UINT8 Month[2];
UINT8 Day[2];
UINT8 Hour[2];
UINT8 Minute[2];
UINT8 Second[2];
UINT8 SecFrac[2];
char Zone;
};
struct iso9660_DirectoryRecord
{
UINT8 len_dr; // [1] Length of Directory Record (bytes)
UINT8 ext_attr_rec_len; // [1] Extended Attribute Record Length (bytes)
UINT8 location_of_extent[8]; // [8] [LEF / BEF] LBN / Sector location of the file data
UINT8 data_lenth[8]; // [8] [LEF / BEF] Length of the file section (bytes)
iso9660_date rec_date_time; // [7] Recording Date and Time
UINT8 file_flags; // [1] 8-bit flags
// [bit 0] File is Hidden if this bit is 1
// [bit 1] Entry is a Directory if this bit is 1
// [bit 2] Entry is an Associated file is this bit is 1
// [bit 3] Information is structured according to the extended attribute record if this bit is 1
// [bit 4] Owner, group and permissions are specified in the extended attribute record if this bit is 1
// [bit 5] Reserved (0)
// [bit 6] Reserved (0)
// [bit 7] File has more than one directory record if this bit is 1
UINT8 file_unit_size; // [1] This field is only valid if the file is recorded in INT32erleave mode, otherwise this field is (00)
UINT8 INT32_gap_size; // [1] This field is only valid if the file is recorded in INT32erleave mode, otherwise this field is (00)
UINT8 vol_seq_number[4]; // [4] The ordinal number of the volume in the Volume Set on which the file described by the directory record is recorded.
UINT8 len_fi; // [1] Length of File Identifier (LEN_FI)
char* file_id; // [LEN_FI] File Identifier
};
struct iso9660_PathTableRecord
{
UINT8 len_di; // [1] Length of Directory Identifier
UINT8 extended_attr_len; // [1] Extended Attribute Record Length
UINT8 extent_location[4]; // [4] Extent Location (Sector)
UINT8 parent_dir_num; // [1] Parent Directory Number
char* directory_id; // [LEN_DI] Directory Identifier
};
// Volume Descriptor Header (Sector 16)
struct iso9660_VDH
{
char vdtype; // [1] Volume Descriptor Type
UINT8 stdid[5]; // [5] ISO9660 Standard Identifier
char vdver; // [1] Volume Descriptor Version
};
// Primary Volume Descriptor (Volume Descriptor Type 1)
struct iso9660_PVD
{
// -----------------------------
// Volume Descriptor Header
char type;
UINT8 id[5];
char version;
// -----------------------------
// Primary Volume Descriptor
char unused1;
UINT8 system_id[32];
UINT8 volume_id[32];
UINT8 unused2[8];
UINT8 volume_space_size[8];
UINT8 unused3[32];
UINT8 volume_set_size[4];
UINT8 volume_sequence_number[4];
UINT8 logical_block_size[4];
UINT8 path_table_size[8];
UINT8 type_l_path_table[4];
UINT8 opt_type_l_path_table[4];
UINT8 type_m_path_table[4];
UINT8 opt_type_m_path_table[4];
iso9660_DirectoryRecord root_directory_record;
UINT8 volume_set_id[128];
UINT8 publisher_id[128];
UINT8 preparer_id[128];
UINT8 application_id[128];
UINT8 copyright_file_id[37];
UINT8 abstract_file_id[37];
UINT8 bibliographic_file_id[37];
iso9660_bcd_date creation_date; // [17]
iso9660_bcd_date modification_date; // [17]
iso9660_bcd_date expiration_date; // [17]
iso9660_bcd_date effective_date; // [17]
char file_structure_version;
char unused4;
UINT8 application_data[512];
UINT8 unused5[643];
};
void iso9660_ReadOffset(UINT8 *Dest, FILE* fp, UINT32 lOffset, UINT32 lSize, UINT32 lLength);
// ------------------------------------------------------
#endif #endif
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -27,7 +27,8 @@ frontend_sources = files(
'logdialog.cpp', 'logdialog.cpp',
'main.cpp', 'main.cpp',
'mainwindow.cpp', 'mainwindow.cpp',
'neocdlist.cpp', '../cdlist.cpp',
'../../intf/cd/cd_img.cpp',
'oglviewport.cpp', 'oglviewport.cpp',
'progress.cpp', 'progress.cpp',
'qaudiointerface.cpp', 'qaudiointerface.cpp',
-393
View File
@@ -1,393 +0,0 @@
// ---------------------------------------------------------------------------------------
// NeoGeo CD Game Info Module (by CaptainCPS-X)
// ---------------------------------------------------------------------------------------
#include "burner.h"
#include "../neocdlist.h"
#include "../neocdlist_games.h"
NGCDGAME* GetNeoGeoCDInfo(unsigned int nID)
{
for(unsigned int nGame = 0; nGame < (sizeof(games) / sizeof(NGCDGAME)); nGame++) {
if(nID == games[nGame].id ) {
return &games[nGame];
}
}
return NULL;
}
NGCDGAME* game;
// Get the title
int GetNeoCDTitle(unsigned int nGameID)
{
game = (NGCDGAME*)malloc(sizeof(NGCDGAME));
memset(game, 0, sizeof(NGCDGAME));
if(GetNeoGeoCDInfo(nGameID))
{
memcpy(game, GetNeoGeoCDInfo(nGameID), sizeof(NGCDGAME));
return 1;
}
game = NULL;
return 0;
}
void iso9660_ReadOffset(unsigned char *Dest, FILE* fp, unsigned int lOffset, unsigned int lSize, unsigned int lLength)
{
if(fp == NULL) return;
if (Dest == NULL) return;
fseek(fp, lOffset, SEEK_SET);
fread(Dest, lLength, lSize, fp);
}
static void NeoCDList_iso9660_CheckDirRecord(FILE* fp, int nSector)
{
int nSectorLength = 2048;
//int nFile = 0;
unsigned int lBytesRead = 0;
//int nLen = 0;
unsigned int lOffset = 0;
bool bNewSector = false;
bool bRevisionQueve = false;
int nRevisionQueveID = 0;
lOffset = (nSector * nSectorLength);
unsigned char* nLenDR = (unsigned char*)malloc(1 * sizeof(unsigned char));
unsigned char* Flags = (unsigned char*)malloc(1 * sizeof(unsigned char));
unsigned char* ExtentLoc = (unsigned char*)malloc(8 * sizeof(unsigned char));
unsigned char* Data = (unsigned char*)malloc(0x10b * sizeof(unsigned char));
unsigned char* LEN_FI = (unsigned char*)malloc(1 * sizeof(unsigned char));
char *File = (char*)malloc(32 * sizeof(char));
while(1)
{
iso9660_ReadOffset(nLenDR, fp, lOffset, 1, sizeof(unsigned char));
if(nLenDR[0] == 0x22) {
lOffset += nLenDR[0];
lBytesRead += nLenDR[0];
continue;
}
if(nLenDR[0] < 0x22)
{
if(bNewSector)
{
if(bRevisionQueve) {
bRevisionQueve = false;
GetNeoCDTitle(nRevisionQueveID);
}
return;
}
nLenDR[0] = 0;
iso9660_ReadOffset(nLenDR, fp, lOffset + 1, 1, sizeof(unsigned char));
if(nLenDR[0] < 0x22) {
lOffset += (2048 - lBytesRead);
lBytesRead = 0;
bNewSector = true;
continue;
}
}
bNewSector = false;
iso9660_ReadOffset(Flags, fp, lOffset + 25, 1, sizeof(unsigned char));
if(!(Flags[0] & (1 << 1)))
{
iso9660_ReadOffset(ExtentLoc, fp, lOffset + 2, 8, sizeof(unsigned char));
char szValue[9];
sprintf(szValue, "%02x%02x%02x%02x", ExtentLoc[4], ExtentLoc[5], ExtentLoc[6], ExtentLoc[7]);
unsigned int nValue = 0;
sscanf(szValue, "%x", &nValue);
iso9660_ReadOffset(Data, fp, nValue * 2048, 0x10a, sizeof(unsigned char));
char szData[8];
sprintf(szData, "%c%c%c%c%c%c%c", Data[0x100], Data[0x101], Data[0x102], Data[0x103], Data[0x104], Data[0x105], Data[0x106]);
if(!strncmp(szData, "NEO-GEO", 7))
{
char id[] = "0000";
sprintf(id, "%02X%02X", Data[0x108], Data[0x109]);
unsigned int nID = 0;
sscanf(id, "%x", &nID);
iso9660_ReadOffset(LEN_FI, fp, lOffset + 32, 1, sizeof(unsigned char));
iso9660_ReadOffset((unsigned char*)File, fp, lOffset + 33, LEN_FI[0], sizeof(char));
strncpy(File, File, LEN_FI[0]);
File[LEN_FI[0]] = 0;
// King of Fighters '94, The (1994)(SNK)(JP)
// 10-6-1994 (P1.PRG)
if(nID == 0x0055 && Data[0x67] == 0xDE) {
// ...continue
}
// King of Fighters '94, The (1994)(SNK)(JP-US)
// 11-21-1994 (P1.PRG)
if(nID == 0x0055 && Data[0x67] == 0xE6) {
// Change to custom revision id
nID = 0x1055;
}
// King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B01, B03-B06, NGCD-084E MT B01]
// 9-11-1995 (P1.PRG)
if(nID == 0x0084 && Data[0x6C] == 0xC0) {
// ... continue
}
// King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B10, NGCD-084E MT B03]
// 10-5-1995 (P1.PRG)
if(nID == 0x0084 && Data[0x6C] == 0xFF) {
// Change to custom revision id
nID = 0x1084;
}
// King of Fighters '96 NEOGEO Collection, The
if(nID == 0x0229) {
bRevisionQueve = false;
GetNeoCDTitle(nID);
break;
}
// King of Fighters '96, The
if(nID == 0x0214) {
bRevisionQueve = true;
nRevisionQueveID = nID;
lOffset += nLenDR[0];
lBytesRead += nLenDR[0];
continue;
}
GetNeoCDTitle(nID);
break;
}
}
lOffset += nLenDR[0];
lBytesRead += nLenDR[0];
}
if (nLenDR) {
free(nLenDR);
nLenDR = NULL;
}
if (Flags) {
free(Flags);
Flags = NULL;
}
if (ExtentLoc) {
free(ExtentLoc);
ExtentLoc = NULL;
}
if (Data) {
free(Data);
Data = NULL;
}
if (LEN_FI) {
free(LEN_FI);
LEN_FI = NULL;
}
if (File) {
free(File);
File = NULL;
}
}
// Check the specified ISO, and proceed accordingly
static int NeoCDList_CheckISO(TCHAR* pszFile)
{
if(!pszFile) {
// error
return 0;
}
// Make sure we have a valid ISO file extension...
if(_tcsstr(pszFile, _T(".iso")) || _tcsstr(pszFile, _T(".ISO")) )
{
FILE* fp = _tfopen(pszFile, _T("rb"));
if(fp)
{
// Read ISO and look for 68K ROM standard program header, ID is always there
// Note: This function works very quick, doesn't compromise performance :)
// it just read each sector first 264 bytes aproximately only.
// Get ISO Size (bytes)
fseek(fp, 0, SEEK_END);
unsigned int lSize = 0;
lSize = ftell(fp);
//rewind(fp);
fseek(fp, 0, SEEK_SET);
// If it has at least 16 sectors proceed
if(lSize > (2048 * 16))
{
// Check for Standard ISO9660 Identifier
unsigned char IsoHeader[2048 * 16 + 1];
unsigned char IsoCheck[6];
fread(IsoHeader, 1, 2048 * 16 + 1, fp); // advance to sector 16 and PVD Field 2
fread(IsoCheck, 1, 5, fp); // get Standard Identifier Field from PVD
// Verify that we have indeed a valid ISO9660 MODE1/2048
if(!memcmp(IsoCheck, "CD001", 5))
{
//bprintf(PRINT_NORMAL, _T(" Standard ISO9660 Identifier Found. \n"));
iso9660_VDH vdh;
// Get Volume Descriptor Header
memset(&vdh, 0, sizeof(vdh));
//memcpy(&vdh, iso9660_ReadOffset(fp, (2048 * 16), sizeof(vdh)), sizeof(vdh));
iso9660_ReadOffset((unsigned char*)&vdh, fp, 2048 * 16, 1, sizeof(vdh));
// Check for a valid Volume Descriptor Type
if(vdh.vdtype == 0x01)
{
#if 0
// This will fail on 64-bit due to differing variable sizes in the pvd struct
// Get Primary Volume Descriptor
iso9660_PVD pvd;
memset(&pvd, 0, sizeof(pvd));
//memcpy(&pvd, iso9660_ReadOffset(fp, (2048 * 16), sizeof(pvd)), sizeof(pvd));
iso9660_ReadOffset((unsigned char*)&pvd, fp, 2048 * 16, 1, sizeof(pvd));
// ROOT DIRECTORY RECORD
// Handle Path Table Location
char szRootSector[32];
unsigned int nRootSector = 0;
sprintf(szRootSector, "%02X%02X%02X%02X",
pvd.root_directory_record.location_of_extent[4],
pvd.root_directory_record.location_of_extent[5],
pvd.root_directory_record.location_of_extent[6],
pvd.root_directory_record.location_of_extent[7]);
// Convert HEX string to Decimal
sscanf(szRootSector, "%X", &nRootSector);
#else
// Just read from the file directly at the correct offset (0x8000 + 0x9e for the start of the root directory record)
unsigned char buffer[8];
char szRootSector[4];
unsigned int nRootSector = 0;
fseek(fp, 0x809e, SEEK_SET);
fread(buffer, 1, 8, fp);
sprintf(szRootSector, "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]);
sscanf(szRootSector, "%x", &nRootSector);
#endif
// Process the Root Directory Records
NeoCDList_iso9660_CheckDirRecord(fp, nRootSector);
// Path Table Records are not processed, since NeoGeo CD should not have subdirectories
// ...
}
} else {
//bprintf(PRINT_NORMAL, _T(" Standard ISO9660 Identifier Not Found, cannot continue. \n"));
return 0;
}
}
fclose(fp);
} else {
//bprintf(PRINT_NORMAL, _T(" Couldn't open %s \n"), GetIsoPath());
return 0;
}
} else {
//bprintf(PRINT_NORMAL, _T(" File doesn't have a valid ISO extension [ .iso / .ISO ] \n"));
return 0;
}
return 1;
}
// This will do everything
int GetNeoGeoCD_Identifier()
{
if(!GetIsoPath() || !IsNeoGeoCD()) {
return 0;
}
// Make sure we have a valid ISO file extension...
if(_tcsstr(GetIsoPath(), _T(".iso")) || _tcsstr(GetIsoPath(), _T(".ISO")) )
{
if(_tfopen(GetIsoPath(), _T("rb")))
{
// Read ISO and look for 68K ROM standard program header, ID is always there
// Note: This function works very quick, doesn't compromise performance :)
// it just read each sector first 264 bytes aproximately only.
NeoCDList_CheckISO(GetIsoPath());
} else {
bprintf(PRINT_NORMAL, _T(" Couldn't open %s \n"), GetIsoPath());
return 0;
}
} else {
bprintf(PRINT_NORMAL, _T(" File doesn't have a valid ISO extension [ .iso / .ISO ] \n"));
return 0;
}
return 1;
}
int NeoCDInfo_Init()
{
NeoCDInfo_Exit();
return GetNeoGeoCD_Identifier();
}
TCHAR* NeoCDInfo_Text(int nText)
{
if(!game || !IsNeoGeoCD() || !bDrvOkay) return NULL;
switch(nText)
{
case DRV_NAME: return game->pszName;
case DRV_FULLNAME: return game->pszTitle;
case DRV_MANUFACTURER: return game->pszCompany;
case DRV_DATE: return game->pszYear;
}
return NULL;
}
int NeoCDInfo_ID()
{
if(!game || !IsNeoGeoCD() || !bDrvOkay) return 0;
return game->id;
}
void NeoCDInfo_Exit()
{
if(game) {
free(game);
game = NULL;
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ frontend_sources = files(
'localise_gamelist.cpp', 'localise_gamelist.cpp',
'main.cpp', 'main.cpp',
'media.cpp', 'media.cpp',
'neocdlist.cpp', '../cdlist.cpp',
'replay.cpp', 'replay.cpp',
'romdata.cpp', 'romdata.cpp',
'run.cpp', 'run.cpp',
-409
View File
@@ -1,409 +0,0 @@
// ---------------------------------------------------------------------------------------
// NeoGeo CD Game Info Module (by CaptainCPS-X)
// ---------------------------------------------------------------------------------------
#include "burner.h"
#include "neocdlist.h"
const int nSectorLength = 2352;
NGCDGAME* game;
#include "neocdlist_games.h"
NGCDGAME* GetNeoGeoCDInfo(unsigned int nID)
{
for (unsigned int nGame = 0; nGame < (sizeof(games) / sizeof(NGCDGAME)); nGame++) {
if (nID == games[nGame].id) {
return &games[nGame];
}
}
return NULL;
}
// Update the main window title
static void SetNeoCDTitle(TCHAR* pszTitle)
{
TCHAR szText[1024] = _T("");
_stprintf(szText, _T(APP_TITLE) _T(" v%.20s") _T(SEPERATOR_1) _T("%s") _T(SEPERATOR_1) _T("%s"), szAppBurnVer, BurnDrvGetText(DRV_FULLNAME), pszTitle);
// SetWindowText(hScrnWnd, szText);
}
void NeoCDInfo_SetTitle()
{
if (IsNeoGeoCD() && game && game->id) {
SetNeoCDTitle(game->pszTitle);
}
else if (IsNeoGeoCD()) {
SetNeoCDTitle("Unknown CD");
}
}
// Get the title
int GetNeoCDTitle(unsigned int nGameID)
{
game = (NGCDGAME*)malloc(sizeof(NGCDGAME));
memset(game, 0, sizeof(NGCDGAME));
if (GetNeoGeoCDInfo(nGameID)) {
memcpy(game, GetNeoGeoCDInfo(nGameID), sizeof(NGCDGAME));
bprintf(PRINT_NORMAL, _T(" Title: %s \n"), game->pszTitle);
bprintf(PRINT_NORMAL, _T(" Shortname: %s \n"), game->pszName);
bprintf(PRINT_NORMAL, _T(" Year: %s \n"), game->pszYear);
bprintf(PRINT_NORMAL, _T(" Company: %s \n"), game->pszCompany);
// Update the main window title
//SetNeoCDTitle(game->pszTitle);
return 1;
}
else {
//SetNeoCDTitle(FBALoadStringEx(hAppInst, IDS_UNIDENTIFIED_CD, true));
}
return 0;
}
void iso9660_ReadOffset(UINT8* Dest, FILE* fp, unsigned int lOffset, unsigned int lSize, unsigned int lLength)
{
if (fp == NULL || Dest == NULL) return;
fseek(fp, lOffset + ((nSectorLength == 2352) ? 16 : 0), SEEK_SET);
fread(Dest, lLength, lSize, fp);
}
static void NeoCDList_iso9660_CheckDirRecord(FILE* fp, int nSector)
{
unsigned int lBytesRead = 0;
unsigned int lOffset = 0;
bool bNewSector = false;
bool bRevisionQueve = false;
int nRevisionQueveID = 0;
lOffset = (nSector * nSectorLength);
UINT8 nLenDR;
UINT8 Flags;
UINT8 LEN_FI;
UINT8* ExtentLoc = (UINT8*)malloc(8 + 32);
UINT8* Data = (UINT8*)malloc(0x10b + 32);
char* File = (char*)malloc(32 + 32);
while (1)
{
iso9660_ReadOffset(&nLenDR, fp, lOffset, 1, sizeof(UINT8));
if (nLenDR == 0x22) {
lOffset += nLenDR;
lBytesRead += nLenDR;
continue;
}
if (nLenDR < 0x22)
{
if (bNewSector)
{
if (bRevisionQueve) {
bRevisionQueve = false;
GetNeoCDTitle(nRevisionQueveID);
}
return;
}
nLenDR = 0;
iso9660_ReadOffset(&nLenDR, fp, lOffset + 1, 1, sizeof(UINT8));
if (nLenDR < 0x22) {
lOffset += (nSectorLength - lBytesRead);
lBytesRead = 0;
bNewSector = true;
continue;
}
}
bNewSector = false;
iso9660_ReadOffset(&Flags, fp, lOffset + 25, 1, sizeof(UINT8));
if (!(Flags & (1 << 1)))
{
iso9660_ReadOffset(ExtentLoc, fp, lOffset + 2, 8, sizeof(UINT8));
char szValue[32];
sprintf(szValue, "%02x%02x%02x%02x", ExtentLoc[4], ExtentLoc[5], ExtentLoc[6], ExtentLoc[7]);
unsigned int nValue = 0;
sscanf(szValue, "%x", &nValue);
iso9660_ReadOffset(Data, fp, nValue * nSectorLength, 0x10a, sizeof(UINT8));
char szData[32];
sprintf(szData, "%c%c%c%c%c%c%c", Data[0x100], Data[0x101], Data[0x102], Data[0x103], Data[0x104], Data[0x105], Data[0x106]);
if (!strncmp(szData, "NEO-GEO", 7))
{
char id[32];
sprintf(id, "%02X%02X", Data[0x108], Data[0x109]);
unsigned int nID = 0;
sscanf(id, "%x", &nID);
iso9660_ReadOffset(&LEN_FI, fp, lOffset + 32, 1, sizeof(UINT8));
iso9660_ReadOffset((UINT8*)File, fp, lOffset + 33, LEN_FI, sizeof(UINT8));
strncpy(File, File, LEN_FI);
File[LEN_FI] = 0;
// King of Fighters '94, The (1994)(SNK)(JP)
// 10-6-1994 (P1.PRG)
if (nID == 0x0055 && Data[0x67] == 0xDE) {
// ...continue
}
// King of Fighters '94, The (1994)(SNK)(JP-US)
// 11-21-1994 (P1.PRG)
if (nID == 0x0055 && Data[0x67] == 0xE6) {
// Change to custom revision id
nID = 0x1055;
}
// King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B01, B03-B06, NGCD-084E MT B01]
// 9-11-1995 (P1.PRG)
if (nID == 0x0084 && Data[0x6C] == 0xC0) {
// ... continue
}
// King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B10, NGCD-084E MT B03]
// 10-5-1995 (P1.PRG)
if (nID == 0x0084 && Data[0x6C] == 0xFF) {
// Change to custom revision id
nID = 0x1084;
}
// King of Fighters '96 NEOGEO Collection, The
if (nID == 0x0229) {
bRevisionQueve = false;
GetNeoCDTitle(nID);
break;
}
// King of Fighters '96, The
if (nID == 0x0214) {
bRevisionQueve = true;
nRevisionQueveID = nID;
lOffset += nLenDR;
lBytesRead += nLenDR;
continue;
}
GetNeoCDTitle(nID);
break;
}
}
lOffset += nLenDR;
lBytesRead += nLenDR;
}
if (ExtentLoc) {
free(ExtentLoc);
ExtentLoc = NULL;
}
if (Data) {
free(Data);
Data = NULL;
}
if (File) {
free(File);
File = NULL;
}
}
// Check the specified ISO, and proceed accordingly
static int NeoCDList_CheckISO(TCHAR* pszFile)
{
if (!pszFile) {
// error
return 0;
}
// Make sure we have a valid ISO file extension...
if (IsFileExt(pszFile, _T(".img")) || IsFileExt(pszFile, _T(".bin")))
{
FILE* fp = _tfopen(pszFile, _T("rb"));
if (fp)
{
// Read ISO and look for 68K ROM standard program header, ID is always there
// Note: This function works very quick, doesn't compromise performance :)
// it just read each sector first 264 bytes aproximately only.
// Get ISO Size (bytes)
fseek(fp, 0, SEEK_END);
unsigned int lSize = 0;
lSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
// If it has at least 16 sectors proceed
if (lSize > (nSectorLength * 16))
{
// Check for Standard ISO9660 Identifier
UINT8 IsoCheck[32];
// advance to sector 16 and PVD Field 2
iso9660_ReadOffset(&IsoCheck[0], fp, nSectorLength * 16 + 1, 1, 5); // get Standard Identifier Field from PVD
// Verify that we have indeed a valid ISO9660 MODE1/2352
if (!memcmp(IsoCheck, "CD001", 5))
{
//bprintf(PRINT_NORMAL, _T(" Standard ISO9660 Identifier Found. \n"));
iso9660_VDH vdh;
// Get Volume Descriptor Header
memset(&vdh, 0, sizeof(vdh));
//memcpy(&vdh, iso9660_ReadOffset(fp, (2048 * 16), sizeof(vdh)), sizeof(vdh));
iso9660_ReadOffset((UINT8*)&vdh, fp, 16 * nSectorLength, 1, sizeof(vdh));
// Check for a valid Volume Descriptor Type
if (vdh.vdtype == 0x01)
{
#if 0
// This will fail on 64-bit due to differing variable sizes in the pvd struct
// Get Primary Volume Descriptor
iso9660_PVD pvd;
memset(&pvd, 0, sizeof(pvd));
//memcpy(&pvd, iso9660_ReadOffset(fp, (2048 * 16), sizeof(pvd)), sizeof(pvd));
iso9660_ReadOffset((UINT8*)&pvd, fp, nSectorLength * 16, 1, sizeof(pvd));
// ROOT DIRECTORY RECORD
// Handle Path Table Location
char szRootSector[32];
unsigned int nRootSector = 0;
sprintf(szRootSector, "%02X%02X%02X%02X",
pvd.root_directory_record.location_of_extent[4],
pvd.root_directory_record.location_of_extent[5],
pvd.root_directory_record.location_of_extent[6],
pvd.root_directory_record.location_of_extent[7]);
// Convert HEX string to Decimal
sscanf(szRootSector, "%X", &nRootSector);
#else
// Just read from the file directly at the correct offset (SECTOR_SIZE * 16 + 0x9e for the start of the root directory record)
UINT8 buffer[32];
char szRootSector[32];
unsigned int nRootSector = 0;
iso9660_ReadOffset(&buffer[0], fp, nSectorLength * 16 + 0x9e, 1, 8);
sprintf(szRootSector, "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]);
sscanf(szRootSector, "%x", &nRootSector);
#endif
// Process the Root Directory Records
NeoCDList_iso9660_CheckDirRecord(fp, nRootSector);
// Path Table Records are not processed, since NeoGeo CD should not have subdirectories
// ...
}
}
else {
//bprintf(PRINT_NORMAL, _T(" Standard ISO9660 Identifier Not Found, cannot continue. \n"));
return 0;
}
}
}
else {
//bprintf(PRINT_NORMAL, _T(" Couldn't open %s \n"), GetIsoPath());
return 0;
}
if (fp) fclose(fp);
}
else {
//bprintf(PRINT_NORMAL, _T(" File doesn't have a valid ISO extension [ .iso / .ISO ] \n"));
return 0;
}
return 1;
}
// This will do everything
int GetNeoGeoCD_Identifier()
{
if (!GetIsoPath() || !IsNeoGeoCD()) {
return 0;
}
// Make sure we have a valid ISO file extension...
if (IsFileExt(GetIsoPath(), _T(".img")) || IsFileExt(GetIsoPath(), _T(".bin")))
{
if (_tfopen(GetIsoPath(), _T("rb")))
{
bprintf(0, _T("NeoCDList: checking %s\n"), GetIsoPath());
// Read ISO and look for 68K ROM standard program header, ID is always there
// Note: This function works very quick, doesn't compromise performance :)
// it just read each sector first 264 bytes aproximately only.
NeoCDList_CheckISO(GetIsoPath());
}
else {
bprintf(PRINT_NORMAL, _T(" Couldn't open %s \n"), GetIsoPath());
return 0;
}
}
else {
bprintf(PRINT_NORMAL, _T(" File doesn't have a valid ISO extension [ .img / .bin ] \n"));
return 0;
}
return 1;
}
int NeoCDInfo_Init()
{
NeoCDInfo_Exit();
return GetNeoGeoCD_Identifier();
}
TCHAR* NeoCDInfo_Text(int nText)
{
if (!game || !IsNeoGeoCD()) return NULL;
switch (nText)
{
case DRV_NAME: return game->pszName;
case DRV_FULLNAME: return game->pszTitle;
case DRV_MANUFACTURER: return game->pszCompany;
case DRV_DATE: return game->pszYear;
}
return NULL;
}
int NeoCDInfo_ID()
{
if (!game || !IsNeoGeoCD()) return 0;
return game->id;
}
void NeoCDInfo_Exit()
{
if (game) {
free(game);
game = NULL;
}
}
-3
View File
@@ -403,9 +403,6 @@ HBITMAP PNGLoadBitmap(HWND hWnd, FILE* fp, int nWidth, int nHeight, int nPreset)
HBITMAP PNGLoadBitmapBuffer(HWND hWnd, void *buffer, int bufferLength, int nWidth, int nHeight, int nPreset); HBITMAP PNGLoadBitmapBuffer(HWND hWnd, void *buffer, int bufferLength, int nWidth, int nHeight, int nPreset);
HBITMAP LoadBitmap(HWND hWnd, FILE* fp, int nWidth, int nHeight, int nPreset); HBITMAP LoadBitmap(HWND hWnd, FILE* fp, int nWidth, int nHeight, int nPreset);
int NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*)); int NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*));
TCHAR* ParseCueGetImageFile(const TCHAR* cueFullPath);
void FreeNGCDGame(NGCDGAME** ppGame);
INT32 GetNGCDGameTitle(const UINT32 nGameID, NGCDGAME** ppOutGame, bool bPrintLog = false);
#include "cd_img.h" #include "cd_img.h"
// romdata.cpp // romdata.cpp
+1 -2
View File
@@ -60,7 +60,7 @@ frontend_sources = files(
'memcard.cpp', 'memcard.cpp',
'menu.cpp', 'menu.cpp',
'misc_win32.cpp', 'misc_win32.cpp',
'neocdlist.cpp', '../cdlist.cpp',
'neocdsel.cpp', 'neocdsel.cpp',
'numdial.cpp', 'numdial.cpp',
'paletteviewer.cpp', 'paletteviewer.cpp',
@@ -69,7 +69,6 @@ frontend_sources = files(
'progress.cpp', 'progress.cpp',
'replay.cpp', 'replay.cpp',
'res.cpp', 'res.cpp',
'romdata.cpp',
'roms.cpp', 'roms.cpp',
'run.cpp', 'run.cpp',
'scrn.cpp', 'scrn.cpp',
-680
View File
@@ -1,680 +0,0 @@
// ---------------------------------------------------------------------------------------
// NeoGeo CD Game Info Module (by CaptainCPS-X)
// ---------------------------------------------------------------------------------------
#include "burner.h"
#include "neocdlist.h"
#include "burnint.h"
#include "cd_chd.h"
#ifdef BUILD_NEOGEO
#define DEBUG_CD 0
const INT32 nSectorLength = 2352;
static NGCDGAME* game;
#include "neocdlist_games.h"
// Distinguish between plain file and CHD I/O types
enum IO_TYPE {
IO_TYPE_NONE = 0,
IO_TYPE_FILE,
IO_TYPE_CHD
};
union IO_UNION {
FILE *pFile; // plain file handle
ChdImage *pChd; // CHD image (cd_chd module)
};
struct ISO_CTX {
enum IO_TYPE ioType; // current I/O type
union IO_UNION ioUnion; // I/O handle union
char szVolumeID[64]; // disc volume label (moved from former global)
INT32 bValid; // context validity flag
// Full-image common metadata (parsed once, reused throughout)
UINT32 sectorSize; // bytes per sector
UINT32 totalSectors; // total image sectors
};
struct IO_STRATEGY
{
enum IO_TYPE ioType;
// Open image, initialize context
INT32 (*fnOpen )(struct ISO_CTX* pIsoCtx, TCHAR* pszFile);
// Close image, release resources
void (*fnClose)(struct ISO_CTX* pIsoCtx);
// Read data by offset
void (*fnRead )(struct ISO_CTX* pIsoCtx, UINT8* Dest, UINT32 lOffset, UINT32 lSize, UINT32 lLength);
};
// TCHAR safe string duplicate (ANSI / Unicode auto-adaptive)
// Allocates heap memory and copies source TCHAR string safely
// Allocated memory must be released by free() or free_s()
static TCHAR* _tcsdup_s(const TCHAR* pSrc)
{
if (IsStrEmpty(pSrc))
return NULL;
size_t srcLen = _tcslen(pSrc);
size_t allocSize = (srcLen + 1) * sizeof(TCHAR);
TCHAR* pDst = (TCHAR*)malloc(allocSize);
if (!pDst)
return NULL;
_tcsncpy(pDst, pSrc, srcLen);
pDst[srcLen] = _T('\0');
return pDst;
}
static void iso9660_ReadOffset(FILE* fp, UINT8* Dest, UINT32 lOffset, UINT32 lSize, UINT32 lLength)
{
if (!fp || !Dest) return;
fseek(fp, lOffset + ((nSectorLength == 2352) ? 16 : 0), SEEK_SET);
fread(Dest, lLength, lSize, fp);
}
static INT32 FileIO_Open(struct ISO_CTX* pIsoCtx, TCHAR* pszFile)
{
if (!pIsoCtx || !pszFile) return 0;
FILE* fp = _tfopen(pszFile, _T("rb"));
if (!fp) return 0;
pIsoCtx->ioType = IO_TYPE_FILE;
pIsoCtx->ioUnion.pFile = fp;
pIsoCtx->bValid = 1;
pIsoCtx->sectorSize = nSectorLength;
fseek(fp, 0, SEEK_END);
pIsoCtx->totalSectors = (UINT32)(ftell(fp) / nSectorLength);
fseek(fp, 0, SEEK_SET);
return 1;
}
static void FileIO_Close(struct ISO_CTX* pIsoCtx)
{
if (!pIsoCtx) return;
if (pIsoCtx->ioType == IO_TYPE_FILE && pIsoCtx->ioUnion.pFile) {
fclose(pIsoCtx->ioUnion.pFile);
pIsoCtx->ioUnion.pFile = NULL;
}
pIsoCtx->bValid = 0;
}
static void FileIO_Read(struct ISO_CTX* pIsoCtx, UINT8* Dest, UINT32 lOffset, UINT32 lSize, UINT32 lLength)
{
if (!pIsoCtx || pIsoCtx->ioType != IO_TYPE_FILE) return;
iso9660_ReadOffset(pIsoCtx->ioUnion.pFile, Dest, lOffset, lSize, lLength);
}
// Read from a CHD via cd_chd. lOffset uses the 2352-stride convention shared
// with the FileIO path (sector*2352 + in-sector byte offset), but the offset
// always lands inside the 2048-byte user area. We translate to a logical LBA
// and read the mode-1 user data, so both 2048 and 2352 source CHDs work.
static void iso9660_ReadOffset_CHD(UINT8* Dest, ChdImage* pChd, UINT32 lOffset, UINT32 lSize, UINT32 lLength)
{
if (!Dest || !pChd) return;
UINT32 total_bytes = lSize * lLength;
UINT32 bytes_read = 0;
UINT8 sector[2048];
while (bytes_read < total_bytes) {
UINT32 lba = lOffset / nSectorLength;
UINT32 offset_in_user = lOffset % nSectorLength;
if (offset_in_user >= 2048) {
// beyond the user data area (raw sync/ECC region) - pad with zero
memset(Dest + bytes_read, 0, total_bytes - bytes_read);
return;
}
if (ChdReadSector(pChd, (INT32)lba, CHD_TRACK_MODE1, sector) != 0) {
memset(Dest + bytes_read, 0, total_bytes - bytes_read);
return;
}
UINT32 avail = 2048 - offset_in_user;
UINT32 to_read = total_bytes - bytes_read;
if (to_read > avail) to_read = avail;
memcpy(Dest + bytes_read, sector + offset_in_user, to_read);
bytes_read += to_read;
lOffset += to_read;
}
}
static INT32 ChdIO_Open(struct ISO_CTX* pIsoCtx, TCHAR* pszFile)
{
if (!pIsoCtx || !pszFile) return 0;
ChdImage* pChd = ChdOpenFile(pszFile);
if (!pChd) {
bprintf(PRINT_ERROR, _T("ChdIO_Open: ChdOpenFile failed for %s\n"), pszFile);
return 0;
}
INT32 nContainer = ChdGetContainerType(pChd);
if (nContainer != CHD_CONTAINER_CD && nContainer != CHD_CONTAINER_GDROM) {
ChdClose(pChd);
return 0;
}
pIsoCtx->ioType = IO_TYPE_CHD;
pIsoCtx->ioUnion.pChd = pChd;
pIsoCtx->bValid = 1;
// Report user-data sector size and total logical sectors.
pIsoCtx->sectorSize = 2048;
pIsoCtx->totalSectors = (UINT32)ChdGetTotalFrames(pChd);
return 1;
}
static void ChdIO_Close(struct ISO_CTX* pIsoCtx)
{
if (!pIsoCtx || pIsoCtx->ioType != IO_TYPE_CHD) return;
if (pIsoCtx->ioUnion.pChd) {
ChdClose(pIsoCtx->ioUnion.pChd);
pIsoCtx->ioUnion.pChd = NULL;
}
pIsoCtx->bValid = 0;
}
static void ChdIO_Read(struct ISO_CTX* pIsoCtx, UINT8* Dest, UINT32 lOffset, UINT32 lSize, UINT32 lLength)
{
if (!pIsoCtx || pIsoCtx->ioType != IO_TYPE_CHD) return;
iso9660_ReadOffset_CHD(Dest, pIsoCtx->ioUnion.pChd, lOffset, lSize, lLength);
}
// Match I/O strategy by file extension
static const struct IO_STRATEGY ioStrategyList[] =
{
{ IO_TYPE_FILE, FileIO_Open, FileIO_Close, FileIO_Read },
{ IO_TYPE_CHD, ChdIO_Open, ChdIO_Close, ChdIO_Read }
};
static void IsoRead(struct ISO_CTX* pIsoCtx, UINT8* Dest, UINT32 lOffset, UINT32 lSize, UINT32 lLength)
{
if (!pIsoCtx || !pIsoCtx->bValid) return;
// Dispatch by I/O type; caller does not need to distinguish between file and CHD
switch (pIsoCtx->ioType) {
case IO_TYPE_FILE:
FileIO_Read(pIsoCtx, Dest, lOffset, lSize, lLength);
break;
case IO_TYPE_CHD:
ChdIO_Read(pIsoCtx, Dest, lOffset, lSize, lLength);
break;
default:
break;
}
}
static INT32 IsoCheckAndReadLabel(struct ISO_CTX* pIsoCtx)
{
if (!pIsoCtx || !pIsoCtx->bValid) return 0;
UINT8 IsoCheck[64] = { 0 };
// Read CD001 identifier from the PVD area
IsoRead(pIsoCtx, IsoCheck, nSectorLength * 16 + 1, 1, sizeof(IsoCheck));
if (!memcmp(IsoCheck, "CD001", 5)) {
// Read and trim the volume label (stored in ISO_CTX)
strncpy(pIsoCtx->szVolumeID, (char*)&IsoCheck[39], 24);
pIsoCtx->szVolumeID[sizeof(pIsoCtx->szVolumeID) - 1] = '\0';
INT32 l = strlen(pIsoCtx->szVolumeID);
while (l > 0 && pIsoCtx->szVolumeID[l - 1] == ' ')
pIsoCtx->szVolumeID[--l] = '\0';
#if DEBUG_CD
bprintf(0, _T("VolumeID is [%S]\n"), pIsoCtx->szVolumeID);
#endif
return 1;
}
bprintf(PRINT_ERROR, _T("ISO9660 CD001 check failed\n"));
return 0;
}
static UINT32 IsoReadRootSector(struct ISO_CTX* pIsoCtx)
{
UINT8 buffer[32] = { 0 };
char szRootSector[32] = { 0 };
UINT32 nRootSector = 0;
// Read root directory address at fixed offset 0x9E
IsoRead(pIsoCtx, buffer, nSectorLength * 16 + 0x9e, 1, 8);
snprintf(szRootSector, sizeof(szRootSector), "%02x%02x%02x%02x", buffer[4], buffer[5], buffer[6], buffer[7]);
szRootSector[sizeof(szRootSector) - 1] = '\0';
sscanf(szRootSector, "%x", &nRootSector);
return nRootSector;
}
static void NeoCDList_CheckDirCommon(void (*pfEntryCallBack)(INT32, TCHAR*), TCHAR* pszFile, struct ISO_CTX* pIsoCtx, INT32 nSector)
{
UINT32 lBytesRead = 0;
UINT32 lOffset = (UINT32)nSector * nSectorLength;
bool bNewSector = false;
bool bRevisionQueve = false;
INT32 nRevisionQueveID = 0;
bool bGotDDPRG_ACM = false;
TCHAR* pIsoPath = NULL;
if (IsFileExt(pszFile, _T(".cue"))) {
pIsoPath = ParseCueGetImageFile(pszFile);
if (!pIsoPath) return;
TCHAR szIsoPath[MAX_PATH] = { 0 };
_tcsncpy(szIsoPath, pIsoPath, MAX_PATH - 1);
szIsoPath[MAX_PATH - 1] = _T('\0');
free_s((void**)&pIsoPath);
pIsoPath = szIsoPath;
}
pIsoPath = pszFile;
UINT8 nLenDR;
UINT8 Flags;
UINT8 LEN_FI;
UINT8* ExtentLoc = (UINT8*)malloc(8 + 64 + 32);
UINT8* Data = (UINT8*)malloc(0x10b + 32);
char* File = (char* )malloc(32 + 32);
if (!ExtentLoc || !Data || !File) {
free_s((void**)&ExtentLoc);
free_s((void**)&Data);
free_s((void**)&File);
return;
}
while (1) {
IsoRead(pIsoCtx, &nLenDR, lOffset, 1, sizeof(UINT8));
if (nLenDR == 0x22) {
lOffset += nLenDR;
lBytesRead += nLenDR;
continue;
}
if (nLenDR < 0x22) {
if (bNewSector) {
if (bRevisionQueve) {
bRevisionQueve = false;
pfEntryCallBack(nRevisionQueveID, pIsoPath);
}
return;
}
nLenDR = 0;
IsoRead(pIsoCtx, &nLenDR, lOffset + 1, 1, sizeof(UINT8));
if (nLenDR < 0x22) {
lOffset += (nSectorLength - lBytesRead);
lBytesRead = 0;
bNewSector = true;
continue;
}
}
bNewSector = false;
IsoRead(pIsoCtx, &Flags, lOffset + 25, 1, sizeof(UINT8));
if (!(Flags & (1 << 1))) {
IsoRead(pIsoCtx, ExtentLoc, lOffset + 2, 54, sizeof(UINT8));
char szFname[64];
UINT8 nDate[3] = { 0, 0, 0 };
memset(szFname, 0, sizeof(szFname));
INT32 fname_len = (ExtentLoc[30] < 32) ? ExtentLoc[30] : 32;
strncpy(szFname, (char*)&ExtentLoc[31], fname_len);
if (!strcmp(szFname, "DDPRG.ACM")) bGotDDPRG_ACM = true;
if (fname_len == 0) break;
nDate[0] = ExtentLoc[16];
nDate[1] = ExtentLoc[17];
nDate[2] = ExtentLoc[18];
#if 0
bprintf(0, _T("Checking File [%S] %d-%d-%d\n"), szFname, nDate[0], nDate[1], nDate[2]);
#endif
// Restore original multi-byte composition logic (reverted custom modifications)
UINT32 nValue =
((UINT32)ExtentLoc[0]) |
((UINT32)ExtentLoc[1] << 8) |
((UINT32)ExtentLoc[2] << 16) |
((UINT32)ExtentLoc[3] << 24);
IsoRead(pIsoCtx, Data, nValue * nSectorLength, 0x10a, sizeof(UINT8));
char szData[32];
snprintf(szData, sizeof(szData), "%c%c%c%c%c%c%c", Data[0x100], Data[0x101], Data[0x102], Data[0x103], Data[0x104], Data[0x105], Data[0x106]);
szData[sizeof(szData) - 1] = '\0';
if (!strncmp(szData, "NEO-GEO", 7)) {
char id[32];
snprintf(id, sizeof(id), "%02X%02X", Data[0x108], Data[0x109]);
id[sizeof(id) - 1] = '\0';
UINT32 nID = 0;
sscanf(id, "%x", &nID);
#if 0
bprintf(0, _T("----- ID: %x\n"), nID);
#endif
IsoRead(pIsoCtx, &LEN_FI, lOffset + 32, 1, sizeof(UINT8));
IsoRead(pIsoCtx, (UINT8*)File, lOffset + 33, LEN_FI, sizeof(UINT8));
File[LEN_FI] = 0;
if (nID == 0x0016 && nDate[0] == 94 && nDate[1] == 12 && nDate[2] == 20) { nID |= 0x1000; } // Justin Gibbons Hacks (kotm)
if (nID == 0x0025 && nDate[0] == 94 && nDate[1] == 12 && nDate[2] == 20) { nID |= 0x1000; } // Justin Gibbons Hacks (eightman)
if (nID == 0x0076 && nDate[0] == 94 && nDate[1] == 12 && nDate[2] == 20) { nID |= 0x1000; } // Justin Gibbons Hacks (zedblade)
if (nID == 0x0062 && nDate[0] == 94 && nDate[1] == 12 && nDate[2] == 20) { nID |= 0x1000; } // Justin Gibbons Hacks (spinmast)
if (nID == 0x0059 && nDate[0] == 95 && nDate[1] == 6 && nDate[2] == 20) { nID |= 0x1000; } // Savage Reign Rev 1
if (nID == 0x0066 && nDate[0] == 125 && nDate[1] == 4 && nDate[2] == 10) { nID |= 0x1200; } // Digger Man (Prototype)
if (nID == 0x069c && nDate[0] == 95 && nDate[1] == 4 && nDate[2] == 29) { nID |= 0x1000; } // Fatal Fury 3 Rev 1
if (nID == 0x069c && nDate[0] == 95 && nDate[1] == 6 && nDate[2] == 1) { nID |= 0x2000; } // Fatal Fury 3 Rev 2
if (nID == 0x069c && nDate[0] == 95 && nDate[1] == 7 && nDate[2] == 10) { nID |= 0x3000; } // Fatal Fury 3 Rev 3
if (nID == 0x0090 && nDate[0] == 95 && nDate[1] == 7 && nDate[2] == 21) { nID |= 0x1000; } // World Heroes Perfect
if (nID == 0x0058 && nDate[0] == 94 && nDate[1] == 10 && nDate[2] == 14) { nID |= 0x1000; } // Fatal Fury Special Rev 1
if (nID == 0x0052 && nDate[0] == 123 && nDate[1] == 7 && nDate[2] == 1) { nID |= 0x1000; } // Abyssal Infants
if (nID == 0x0052 && nDate[0] == 123 && nDate[1] == 6 && nDate[2] == 20) { nID |= 0x1001; } // Neo Fight
if (nID == 0x0082) {
if (bGotDDPRG_ACM) { nID |= 0x1000; } // Double Dragon Rev 1
else if (StrStrI(pIsoPath, _T("OST")) ||
StrStrI(pIsoPath, _T("PS")) ||
StrStrI(pIsoPath, _T("PlayStation"))) { nID |= 0x2000; } // Double Dragon PS1 OST
}
if (nID == 0x0085) {
if (nDate[0] == 123 && nDate[1] == 11 && nDate[2] == 29) { nID |= 0x1000; } // Samurai Shodown RPG (English Translation)
else if (nDate[0] == 124 && nDate[1] == 1 && nDate[2] == 26) { nID |= 0x3000; } // Samurai Shodown RPG (English Translation v1.1)
else if (nDate[0] == 126 && nDate[1] == 6 && nDate[2] == 1) { nID |= 0x4000; } // Samurai Shodown RPG (Simplified Chinese Translation v1.1)
else if (StrStrI(pIsoPath, _T("FR")) ||
StrStrI(pIsoPath, _T("French"))) { nID |= 0x2000; } // Samurai Shodown RPG (FR)
}
if (nID == 0x5345) {
if (!strcmp(pIsoCtx->szVolumeID, "BLUEANDREDFIGHTTHEROBOTS") ||
(StrStrI(pIsoPath, _T("NTSC")))) { nID = 0x5346; } // Blue And Red - Fight The Robots! (NTSC)
}
if (nID == 0x1234 && nDate[0] == 105 && nDate[1] == 4 && nDate[2] == 25) { nID = 0x2234; } // Neo Puzzle League
if (nID == 0x1234 && nDate[0] == 124 && nDate[1] == 12 && nDate[2] == 2) { nID = 0x2235; } // Neo Tetris
if (nID == 0x1234 && nDate[0] == 112 && nDate[1] == 3 && nDate[2] == 4) { nID = 0x2236; } // NGD::ARK
if (nID == 0x1234 && nDate[0] == 112 && nDate[1] == 12 && nDate[2] == 4) { nID = 0x2237; } // Santa Ball
if (nID == 0x2000 && !strcmp(pIsoCtx->szVolumeID, "COLUMNS")) { nID |= 0x1000; } // Columns
if (nID == 0xFFFF && !strcmp(pIsoCtx->szVolumeID, "CODENAME BLUT ENGEL")) { nID = 0xFFFE; } // Codename Blut Engel
if (nID == 0x7777 && nDate[0] == 114 && nDate[1] == 8 && nDate[2] == 14) { nID = 0x7778; } // Puzzle de Pon! CD Collection
if (nID == 0x2019 && !strcmp(pIsoCtx->szVolumeID, "LOOPTRSP")) { nID |= 0x0100; } // Looptris Plus
if (nID == 0x0048 && Data[0x67] == 0x08) { nID |= 0x1000; } // Treasure of Caribbean (c) 1994 / (c) 2011 NCI
if (nID == 0x0055 && Data[0x67] == 0xDE) /* 10-6-1994 (P1.PRG) */ {/* ...continue*/} // King of Fighters '94, The (1994)(SNK)(JP)
if (nID == 0x0055 && Data[0x67] == 0xE6) /* 11-21-1994 (P1.PRG) */ { nID |= 0x1000; } // King of Fighters '94, The (1994)(SNK)(JP-US)
if (nID == 0x0084 && Data[0x6C] == 0xC0) /* 9-11-1995 (P1.PRG) */ {/* ...continue*/} // King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B01, B03-B06, NGCD-084E MT B01]
if (nID == 0x0084 && Data[0x6C] == 0xFF) /* 10-5-1995 (P1.PRG) */ { nID |= 0x1000; } // King of Fighters '95, The (1995)(SNK)(JP-US)[!][NGCD-084 MT B10, NGCD-084E MT B03]
if (nID == 0x0229) { // King of Fighters '96 NEOGEO Collection, The
bRevisionQueve = false;
pfEntryCallBack(nID, pszFile);
break;
}
// Sometimes there's multiple .prg entries in the
// list, .old / .bak files which preceed the proper one..
// For these, we have to keep searching the file list:
if (nID == 0x0214 // King of Fighters '96, The
|| (nID == 0x0058 && !(nDate[0] == 94 && nDate[1] == 8 && nDate[2] == 5))) { // !Fatal Fury Special Rev 0
// continue checking other files...
bRevisionQueve = true;
nRevisionQueveID = nID;
lOffset += nLenDR;
lBytesRead += nLenDR;
continue;
}
pfEntryCallBack(nID, pszFile);
break;
}
}
lOffset += nLenDR;
lBytesRead += nLenDR;
}
// Unified safe release
free_s((void**)&ExtentLoc);
free_s((void**)&Data);
free_s((void**)&File);
}
static void PrintNGCDGameInfo(const NGCDGAME* pGame)
{
if (!pGame) return;
bprintf(PRINT_NORMAL, _T(" Title: %s \n"), pGame->pszTitle);
bprintf(PRINT_NORMAL, _T(" Shortname: %s \n"), pGame->pszName);
bprintf(PRINT_NORMAL, _T(" Year: %s \n"), pGame->pszYear);
bprintf(PRINT_NORMAL, _T(" Company: %s \n"), pGame->pszCompany);
}
// Internal reusable tool: deep copy game meta by ID, output via ppOutGame
// Return 1 success, 0 fail
INT32 GetNGCDGameTitle(const UINT32 nGameID, NGCDGAME** ppOutGame, bool bPrintLog)
{
if (!ppOutGame)
return 0;
*ppOutGame = NULL;
NGCDGAME* pGameInfo = GetNeoGeoCDInfo(nGameID);
if (!pGameInfo) {
bprintf(0, _T("NeoGeoCD Unknown GAME ID %x\n"), nGameID);
return 0;
}
NGCDGAME* pnew = (NGCDGAME*)calloc(1, sizeof(NGCDGAME));
if (!pnew)
return 0;
// Deep copy all fields
pnew->id = pGameInfo->id;
pnew->pszName = _tcsdup_s(pGameInfo->pszName);
if (!pnew->pszName)
goto CLEAN_FAIL;
pnew->pszTitle = _tcsdup_s(pGameInfo->pszTitle);
if (!pnew->pszTitle)
goto CLEAN_FAIL;
pnew->pszYear = _tcsdup_s(pGameInfo->pszYear);
if (!pnew->pszYear)
goto CLEAN_FAIL;
pnew->pszCompany = _tcsdup_s(pGameInfo->pszCompany);
if (!pnew->pszCompany)
goto CLEAN_FAIL;
// Print only when switch enabled
if (bPrintLog)
PrintNGCDGameInfo(pnew);
*ppOutGame = pnew;
return 1;
CLEAN_FAIL:
free_s((void**)&pnew->pszName);
free_s((void**)&pnew->pszTitle);
free_s((void**)&pnew->pszYear);
free_s((void**)&pnew->pszCompany);
free_s((void**)&pnew);
return 0;
}
INT32 NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*))
{
if (!pszFile)
return 0;
TCHAR* pIsoPath = NULL;
if (IsFileExt(pszFile, _T(".cue"))) {
pIsoPath = ParseCueGetImageFile(pszFile);
if (!pIsoPath) return 0;
TCHAR szIsoPath[MAX_PATH] = { 0 };
_tcsncpy(szIsoPath, pIsoPath, MAX_PATH - 1);
szIsoPath[MAX_PATH - 1] = _T('\0');
free_s((void**)&pIsoPath);
pIsoPath = szIsoPath;
}
if (!pIsoPath) pIsoPath = pszFile;
INT32 ret = 0;
// Match I/O strategy
const struct IO_STRATEGY* pStrategy = NULL;
if ( IsFileExt(pIsoPath, _T(".img")) ||
IsFileExt(pIsoPath, _T(".bin"))) {
pStrategy = &ioStrategyList[0];
} else if (IsFileExt(pIsoPath, _T(".chd"))) {
pStrategy = &ioStrategyList[1];
} else {
// Unsupported format, exit directly
return 0;
}
// Allocate top-level context
struct ISO_CTX* pIsoCtx = (struct ISO_CTX*)calloc(1, sizeof(struct ISO_CTX));
if (!pIsoCtx) return 0;
// Open image and initialize context
if (!pStrategy->fnOpen(pIsoCtx, pIsoPath)) {
free_s((void**)&pIsoCtx);
return 0;
}
// Minimum sector count check
if (pIsoCtx->totalSectors <= 16) {
pStrategy->fnClose(pIsoCtx);
free_s((void**)&pIsoCtx);
return 0;
}
// ISO identifier and volume label check
if (IsoCheckAndReadLabel(pIsoCtx)) {
UINT32 nRootSector = IsoReadRootSector(pIsoCtx);
// Call the single unified directory function
NeoCDList_CheckDirCommon(pfEntryCallBack, pszFile, pIsoCtx, (INT32)nRootSector);
ret = 1;
}
// Unified resource cleanup and context release
pStrategy->fnClose(pIsoCtx);
free_s((void**)&pIsoCtx);
return ret;
}
NGCDGAME* GetNeoGeoCDInfo(UINT32 nID)
{
for(UINT32 nGame = 0; nGame < (sizeof(games) / sizeof(NGCDGAME)); nGame++) {
if(nID == games[nGame].id ) {
return &games[nGame];
}
}
return NULL;
}
// Update the main window title
static void SetNeoCDTitle(TCHAR* pszTitle)
{
TCHAR szText[1024] = _T("");
_sntprintf(szText, ARRAY_SIZE(szText), _T(APP_TITLE) _T( " v%.20s") _T(SEPERATOR_1) _T("%s") _T(SEPERATOR_1) _T("%s"), szAppBurnVer, BurnDrvGetText(DRV_FULLNAME), pszTitle);
szText[ARRAY_SIZE(szText) - 1] = '\0';
SetWindowText(hScrnWnd, szText);
}
void NeoCDInfo_SetTitle()
{
if (IsNeoGeoCD() && game && game->id) {
SetNeoCDTitle(game->pszTitle);
} else if (IsNeoGeoCD()) {
SetNeoCDTitle(FBALoadStringEx(hAppInst, IDS_UNIDENTIFIED_CD, true));
}
}
void FreeNGCDGame(NGCDGAME** ppGame)
{
if (!ppGame || !*ppGame)
return;
NGCDGAME* p = *ppGame;
free_s((void**)&p->pszName);
free_s((void**)&p->pszTitle);
free_s((void**)&p->pszYear);
free_s((void**)&p->pszCompany);
free_s((void**)ppGame);
}
// Get the title
INT32 GetNeoCDTitle(UINT32 nGameID)
{
// Release previous global data first to avoid memory leak
FreeNGCDGame(&game);
// Global scene needs log output, pass true
return GetNGCDGameTitle(nGameID, &game, true);
}
static void NeoCDList_Callback(INT32 nID, TCHAR *pszFile)
{
GetNeoCDTitle(nID);
}
void NeoCDInfo_Exit()
{
FreeNGCDGame(&game);
}
// This function scans and identifies NeoGeo CD game information from supported image files
INT32 GetNeoGeoCD_Identifier()
{
TCHAR* szIsoPath = GetIsoPath();
// Skip if ISO path is empty or NeoGeo CD mode is disabled
if (!szIsoPath || !IsNeoGeoCD())
return 0;
// Clear previous game global data to avoid old info pollution
NeoCDInfo_Exit();
// Check supported image extensions: img / bin / chd
if (IsFileExt(szIsoPath, _T(".img")) || IsFileExt(szIsoPath, _T(".bin")) || IsFileExt(szIsoPath, _T(".chd"))) {
bprintf(0, _T("NeoCDList: checking %s\n"), szIsoPath);
INT32 ret = NeoCDList_CheckISO(szIsoPath, NeoCDList_Callback);
if (!ret) {
bprintf(PRINT_NORMAL, _T(" Failed to parse image file %s\n"), szIsoPath);
return 0;
}
return 1;
} else {
bprintf(PRINT_NORMAL, _T(" File doesn't have a valid ISO extension [.img / .bin / .chd]\n"));
return 0;
}
}
INT32 NeoCDInfo_Init()
{
NeoCDInfo_Exit();
return GetNeoGeoCD_Identifier();
}
TCHAR* NeoCDInfo_Text(INT32 nText)
{
if(!game || !IsNeoGeoCD()) return NULL;
switch(nText) {
case DRV_NAME: return game->pszName;
case DRV_FULLNAME: return game->pszTitle;
case DRV_MANUFACTURER: return game->pszCompany;
case DRV_DATE: return game->pszYear;
}
return NULL;
}
INT32 NeoCDInfo_ID()
{
if(!game || !IsNeoGeoCD()) return 0;
return game->id;
}
#endif
+61 -446
View File
@@ -40,17 +40,17 @@ const INT32 nSectorLength = 2352;
// Stores single NeoGeo CD game metadata // Stores single NeoGeo CD game metadata
struct GAMELIST { struct GAMELIST {
bool bFoundCUE; // True if game loaded from .cue sheet file INT32 nPlatform;
TCHAR* szPathCUE; // Full absolute path of cue file UINT64 nKey;
TCHAR* szPath; // Full absolute path of real image file (chd/bin) TCHAR* szPath;
TCHAR* szISOFile; // Raw image filename extracted from cue TCHAR* szISOFile;
TCHAR* szGameId; // Game identification number string TCHAR* szGameId;
TCHAR* szShortName; // Game short name for cover matching TCHAR* szShortName;
TCHAR* szTitle; // Game title TCHAR* szTitle;
TCHAR* szPublisher; // Publisher + release year combined string TCHAR* szPublisher;
TCHAR* szAudioTracks; // Audio tracks string TCHAR* szAudioTracks;
// TCHAR szTracks[99][256]; // Unused track storage array, commented out TCHAR* szRequirement;
INT32 nIconIdx; // index inside NeoCD_ImageList INT32 nIconIdx;
}; };
// Central game library container, thread-safe with critical section lock // Central game library container, thread-safe with critical section lock
@@ -389,13 +389,13 @@ static void FreeGameItem(struct GAMELIST* pItem)
if (!pItem) if (!pItem)
return; return;
free_s((void**)&pItem->szPathCUE);
free_s((void**)&pItem->szPath); free_s((void**)&pItem->szPath);
free_s((void**)&pItem->szISOFile); free_s((void**)&pItem->szISOFile);
free_s((void**)&pItem->szShortName); free_s((void**)&pItem->szShortName);
free_s((void**)&pItem->szPublisher); free_s((void**)&pItem->szPublisher);
free_s((void**)&pItem->szTitle); free_s((void**)&pItem->szTitle);
free_s((void**)&pItem->szAudioTracks); free_s((void**)&pItem->szAudioTracks);
free_s((void**)&pItem->szRequirement);
free_s((void**)&pItem->szGameId); free_s((void**)&pItem->szGameId);
} }
@@ -435,11 +435,9 @@ static BOOL GameLib_AddGame(struct GAME_LIB* pLib, struct GAMELIST* pSrcTemplate
struct GAMELIST* pDst = &pNew[pLib->dataCount]; struct GAMELIST* pDst = &pNew[pLib->dataCount];
// Copy numeric value fields from source template // Copy numeric value fields from source template
pDst->bFoundCUE = pSrcTemplate->bFoundCUE; pDst->nPlatform = pSrcTemplate->nPlatform;
pDst->nKey = pSrcTemplate->nKey;
pDst->nIconIdx = pSrcTemplate->nIconIdx; pDst->nIconIdx = pSrcTemplate->nIconIdx;
// Transfer string pointer ownership (share original heap memory, no duplication)
pDst->szPathCUE = pSrcTemplate->szPathCUE;
pDst->szPath = pSrcTemplate->szPath; pDst->szPath = pSrcTemplate->szPath;
pDst->szISOFile = pSrcTemplate->szISOFile; pDst->szISOFile = pSrcTemplate->szISOFile;
pDst->szShortName = pSrcTemplate->szShortName; pDst->szShortName = pSrcTemplate->szShortName;
@@ -447,6 +445,7 @@ static BOOL GameLib_AddGame(struct GAME_LIB* pLib, struct GAMELIST* pSrcTemplate
pDst->szTitle = pSrcTemplate->szTitle; pDst->szTitle = pSrcTemplate->szTitle;
pDst->szGameId = pSrcTemplate->szGameId; pDst->szGameId = pSrcTemplate->szGameId;
pDst->szAudioTracks = pSrcTemplate->szAudioTracks; pDst->szAudioTracks = pSrcTemplate->szAudioTracks;
pDst->szRequirement = pSrcTemplate->szRequirement;
// Replace old game data array with reallocated buffer and update item counter // Replace old game data array with reallocated buffer and update item counter
pLib->pGameData = pNew; pLib->pGameData = pNew;
@@ -511,313 +510,57 @@ static void GameLib_Destroy(struct GAME_LIB* pLib)
pGameLib = NULL; pGameLib = NULL;
} }
// ParseCueGetImageFile static struct GAMELIST* NeoCD_BuildGameEntry(const TCHAR* pszPath, const CDListResult* pResult)
// Return NULL if file open failed / no valid FILE BINARY segment found
TCHAR* ParseCueGetImageFile(const TCHAR* cueFullPath)
{ {
if (IsStrEmpty(cueFullPath)) if (!pszPath || !pResult || pResult->nPlatform != CDLIST_PLATFORM_NEOCD) return NULL;
return NULL; CDImage* pImage = CDImageOpen(pszPath);
if (!pImage) return NULL;
FILE* fp = _tfopen(cueFullPath, _T("r")); const CDImageTrack* pDataTrack = NULL;
if (!fp) for (INT32 i = 0; i < CDImageGetTrackCount(pImage); i++) {
return NULL; const CDImageTrack* pTrack = CDImageGetTrack(pImage, i);
if (pTrack && pTrack->nType != CDIMAGE_TRACK_AUDIO) {
TCHAR szCueDir[2048] = { 0 }; pDataTrack = pTrack;
size_t nBufSize = ARRAY_SIZE(szCueDir);
_tcsncpy(szCueDir, cueFullPath, nBufSize - 1);
szCueDir[nBufSize - 1] = _T('\0');
TCHAR* pSep = _tcsrchr(szCueDir, _T('\\'));
if (pSep)
*(pSep + 1) = _T('\0');
bool bFoundBinary = false;
TCHAR szImgName[2048] = { 0 };
TCHAR szBuffer[ 2048] = { 0 };
while (_fgetts(szBuffer, ARRAY_SIZE(szBuffer), fp)) {
// Trim trailing whitespace & control characters (\r \n space etc.)
INT32 nLen = _tcslen(szBuffer);
while (nLen > 0 && szBuffer[nLen - 1] < 32)
{
szBuffer[nLen - 1] = _T('\0');
nLen--;
}
// Match FILE "filename" BINARY line
if (!_tcsncmp(szBuffer, _T("FILE"), 4)) {
TCHAR* pEndQ = _tcsrchr(szBuffer, _T('"'));
if (!pEndQ)
continue;
*pEndQ = _T('\0');
TCHAR* pStartQ = _tcschr(szBuffer, _T('"'));
if (!pStartQ)
continue;
// Skip if segment is not BINARY type
if (_tcsstr(pEndQ + 1, _T("BINARY")) == NULL)
continue;
// Extract image file name inside quotes
nBufSize = ARRAY_SIZE(szImgName);
_tcsncpy(szImgName, pStartQ + 1, nBufSize - 1);
szImgName[nBufSize - 1] = _T('\0');
bFoundBinary = true;
break; break;
} }
} }
fclose(fp);
if (!bFoundBinary)
return NULL;
// Combine cue directory and image filename to full absolute path
TCHAR* pFullImagePath = NULL;
PathCombine_s(&pFullImagePath, szCueDir, szImgName);
return pFullImagePath;
}
// Parse cue sheet file, fill path info & audio track count
// Return heap-allocated GAMELIST entry on success, NULL if failed
static struct GAMELIST* ParseCueCreateGameItem(const TCHAR* cueFullPath)
{
// Params validated upstream; skip duplicate check here
// Allocate zero-init struct, all pointers default NULL
struct GAMELIST* pItem = (struct GAMELIST*)calloc(1, sizeof(struct GAMELIST)); struct GAMELIST* pItem = (struct GAMELIST*)calloc(1, sizeof(struct GAMELIST));
if (!pItem) if (!pItem) {
return NULL; CDImageClose(pImage);
pItem->nIconIdx = 0;
FILE* fp = _tfopen(cueFullPath, _T("r"));
if (!fp) {
free_s((void**)&pItem);
return NULL; return NULL;
} }
// Extract directory folder from full cue path, use safe _tcsncpy pItem->nPlatform = pResult->nPlatform;
TCHAR szCueDir[2048] = { 0 }; pItem->nKey = pResult->nNeoID;
size_t nStrLen = ARRAY_SIZE(szCueDir); pItem->nIconIdx = IsFileExt((TCHAR*)pszPath, _T(".chd")) ? 1 : 0;
_tcsncpy(szCueDir, cueFullPath, nStrLen - 1); pItem->szPath = _tcsdup_s(CDImageGetPath(pImage));
szCueDir[nStrLen - 1] = _T('\0'); pItem->szISOFile = _tcsdup_s(pDataTrack ? pDataTrack->szPath : CDImageGetPath(pImage));
pItem->szShortName = _tcsdup_s(pResult->Metadata.szName);
pItem->szTitle = _tcsdup_s(pResult->Metadata.szTitle);
pItem->szRequirement = _tcsdup_s(pResult->Metadata.szRequirement);
TCHAR* pSep = _tcsrchr(szCueDir, _T('\\')); TCHAR szText[256] = { 0 };
if (pSep) _sntprintf(szText, ARRAY_SIZE(szText), _T("%s (%s)"), pResult->Metadata.szCompany, pResult->Metadata.szYear);
*(pSep + 1) = _T('\0'); szText[ARRAY_SIZE(szText) - 1] = _T('\0');
pItem->szPublisher = _tcsdup_s(szText);
_sntprintf(szText, ARRAY_SIZE(szText), _T("%04X"), pResult->nNeoID);
szText[ARRAY_SIZE(szText) - 1] = _T('\0');
pItem->szGameId = _tcsdup_s(szText);
_sntprintf(szText, ARRAY_SIZE(szText), _T("%d"), CDImageGetAudioTrackCount(pImage));
szText[ARRAY_SIZE(szText) - 1] = _T('\0');
pItem->szAudioTracks = _tcsdup_s(szText);
CDImageClose(pImage);
bool bHasBinary = false; if (!pItem->szPath || !pItem->szISOFile || !pItem->szShortName || !pItem->szTitle ||
TCHAR szBuffer[2048] = { 0 }; !pItem->szPublisher || !pItem->szAudioTracks || !pItem->szGameId) {
const size_t nBufSize = ARRAY_SIZE(szBuffer);
INT32 nAudioTracks = 0;
while (_fgetts(szBuffer, (INT32)nBufSize, fp)) {
// Trim trailing ASCII control chars (\r \n etc.)
INT32 nLen = _tcslen(szBuffer);
while (nLen > 0 && szBuffer[nLen - 1] < 32) {
szBuffer[nLen - 1] = _T('\0');
nLen--;
}
// Parse FILE "filename" BINARY segment
if (!_tcsncmp(szBuffer, _T("FILE"), 4)) {
TCHAR* pEndQ = _tcsrchr(szBuffer, _T('"'));
if (!pEndQ)
continue;
*pEndQ = _T('\0');
TCHAR* pStartQ = _tcschr(szBuffer, _T('"'));
if (!pStartQ)
continue;
if (!_tcsstr(pEndQ + 1, _T("BINARY")))
continue;
pItem->szISOFile = _tcsdup_s(pStartQ + 1);
pItem->szPathCUE = _tcsdup_s(cueFullPath);
TCHAR szFullImg[2048] = { 0 };
nStrLen = ARRAY_SIZE(szFullImg);
_sntprintf(szFullImg, nStrLen, _T("%s%s"), szCueDir, pStartQ + 1);
szFullImg[nStrLen - 1] = _T('\0');
pItem->szPath = _tcsdup_s(szFullImg);
pItem->bFoundCUE = true;
bHasBinary = true;
}
// Parse TRACK definition, same pointer logic as original source
TCHAR* t = LabelCheck(szBuffer, _T("TRACK"));
if (t) {
TCHAR* s = t;
// Parse track numeric id, advance t past digits
_tcstol(s, &t, 10);
s = t;
// Skip leading spaces to reach the type field
while (*s == _T(' ')) s++;
// CD-DA audio track, increment counter
if (!_tcsncmp(s, _T("AUDIO"), 5)) {
nAudioTracks++;
continue;
}
// Any MODE* type (MODE1/2048, MODE1/2352, MODE2/xxxx ...) is a data track
if (!_tcsncmp(s, _T("MODE"), 4))
continue;
}
}
fclose(fp);
memset(szBuffer, 0, nBufSize);
_sntprintf(szBuffer, nBufSize, _T("%d"), nAudioTracks);
szBuffer[nBufSize - 1] = _T('\0');
pItem->szAudioTracks = _tcsdup_s(szBuffer);
// No valid binary found in cue sheet, release resource
if (!bHasBinary) {
FreeGameItem(pItem); FreeGameItem(pItem);
free_s((void**)&pItem); free_s((void**)&pItem);
return NULL; return NULL;
} }
return pItem; return pItem;
} }
// Create base GAMELIST entry for CHD file, fill path & audio track count from CHD header
// Param chdFullPath: full absolute path of target chd file
// Return heap-allocated GAMELIST on success, NULL on failure
static struct GAMELIST* CreateChdBaseGameItem(TCHAR* chdFullPath)
{
struct GAMELIST* pItem = (struct GAMELIST*)calloc(1, sizeof(struct GAMELIST));
if (!pItem)
return NULL;
pItem->nIconIdx = 1;
// Store full CHD absolute path
pItem->szPath = _tcsdup_s(chdFullPath);
if (!pItem->szPath) {
free_s((void**)&pItem);
return NULL;
}
// Extract short file name for szISOFile
TCHAR szFileName[2048] = { 0 };
size_t nLen = ARRAY_SIZE(szFileName) - 1;
_tcsncpy(szFileName, chdFullPath, nLen);
szFileName[nLen] = _T('\0');
TCHAR* pNameStart = _tcsrchr(szFileName, _T('\\'));
if (pNameStart)
pNameStart++;
else
pNameStart = szFileName;
pItem->szISOFile = _tcsdup_s(pNameStart);
if (!pItem->szISOFile) {
FreeGameItem(pItem);
free_s((void**)&pItem);
return NULL;
}
pItem->bFoundCUE = FALSE;
// Get audio track count from CHD metadata
const INT32 nAudioTracks = cdimgCountChdAudioTracks(chdFullPath);
TCHAR szBuffer[10] = { 0 };
size_t nSize = ARRAY_SIZE(szBuffer);
_sntprintf(szBuffer, nSize, _T("%d"), nAudioTracks);
szBuffer[nSize - 1] = _T('\0');
pItem->szAudioTracks = _tcsdup_s(szBuffer);
return pItem;
}
// Unified entry: build game item for both .cue and .chd file
// Return TRUE if entry created successfully, FALSE on any failure / unsupported extension
static BOOL NeoCD_BuildGameEntry(UINT32 nGameID, TCHAR* filePath, struct GAMELIST** ppOutItem)
{
if (IsStrEmpty(filePath) || !ppOutItem)
return FALSE;
*ppOutItem = NULL;
INT32 nImgIdx = -1;
struct GAMELIST* pItem = NULL;
if ( IsFileExt(filePath, _T(".cue"))) {
pItem = ParseCueCreateGameItem(filePath);
nImgIdx = 0;
} else if (IsFileExt(filePath, _T(".chd"))) {
pItem = CreateChdBaseGameItem( filePath);
nImgIdx = 1;
} else {
// Unsupported format
return FALSE;
}
if (!pItem)
return FALSE;
NGCDGAME* pMeta = NULL;
if (!GetNGCDGameTitle(nGameID, &pMeta)) {
FreeGameItem(pItem);
free_s((void**)&pItem);
return FALSE;
}
// Combine publisher & release year string
TCHAR szBuffer[256] = { 0 };
const size_t nLen = ARRAY_SIZE(szBuffer);
_sntprintf(szBuffer, nLen, _T("%s (%s)"), pMeta->pszCompany, pMeta->pszYear);
szBuffer[nLen - 1] = _T('\0');
pItem->szPublisher = _tcsdup_s(szBuffer);
if (!pItem->szPublisher) {
FreeNGCDGame(&pMeta);
FreeGameItem(pItem);
free_s((void**)&pItem);
return FALSE;
}
// Fill game identity & display text fields
pItem->szShortName = _tcsdup_s(pMeta->pszName);
if (!pItem->szShortName) {
FreeNGCDGame(&pMeta);
FreeGameItem(pItem);
free_s((void**)&pItem);
return FALSE;
}
if (nGameID == 0x0000)
pItem->szTitle = _tcsdup_s(pItem->szPath);
else
pItem->szTitle = _tcsdup_s(pMeta->pszTitle);
if (!pItem->szTitle) {
FreeNGCDGame(&pMeta);
FreeGameItem(pItem);
free_s((void**)&pItem);
return FALSE;
}
memset(szBuffer, 0, sizeof(szBuffer));
_sntprintf(szBuffer, nLen, _T("%04X"), nGameID);
szBuffer[nLen - 1] = _T('\0');
pItem->szGameId = _tcsdup_s(szBuffer);
if (!pItem->szGameId) {
FreeNGCDGame(&pMeta);
FreeGameItem(pItem);
free_s((void**)&pItem);
return FALSE;
}
// Assign icon index based on file type
pItem->nIconIdx = nImgIdx;
FreeNGCDGame(&pMeta);
*ppOutItem = pItem;
return TRUE;
}
static bool NeoCD_GameLibInit() static bool NeoCD_GameLibInit()
{ {
// Lazy init game lib // Lazy init game lib
@@ -831,57 +574,27 @@ static bool NeoCD_GameLibInit()
return true; return true;
} }
// Callback function for directory scan, construct and store game metadata into game library static INT32 NeoCD_AddGameLib(const TCHAR* pszPath)
static void NeoCD_AddGameLib_Callback(INT32 nGameID, TCHAR* filePath)
{ {
struct GAMELIST* pTempItem = NULL; if (pGameLib && pGameLib->hGLEvent && WaitForSingleObject(pGameLib->hGLEvent, 0) == WAIT_OBJECT_0) return -1;
// Build temporary game metadata entry from cue/chd file if (!pszPath || (!IsFileExt((TCHAR*)pszPath, _T(".cue")) && !IsFileExt((TCHAR*)pszPath, _T(".ccd")) && !IsFileExt((TCHAR*)pszPath, _T(".chd")))) return 0;
if (!NeoCD_BuildGameEntry((UINT32)nGameID, filePath, &pTempItem) || !pTempItem) {
bprintf(PRINT_ERROR, _T("NeoCD_AddGameLib_Callback: build entry fail ID=0x%04X %s\n"), nGameID, filePath);
return;
}
// Transfer string pointer ownership to global game library array
BOOL bOk = GameLib_AddGame(pGameLib, pTempItem);
if (!bOk) {
bprintf(PRINT_ERROR, _T("NeoCD_AddGameLib_Callback: add to lib memory fail\n"));
}
// Only release temporary GAMELIST struct shell, do NOT free internal string buffers
// Strings are now owned by GAME_LIB and will be released in GameLib_Destroy
free_s((void**)&pTempItem);
}
// Add cue/chd game to static global game lib
static INT32 NeoCD_AddGameLib(const TCHAR* filePath)
{
// Check user cancel signal before processing current file
if (pGameLib && pGameLib->hGLEvent) {
// Non-blocking wait for abort event
if (WaitForSingleObject(pGameLib->hGLEvent, 0) == WAIT_OBJECT_0) {
// Return negative value to tell directory traversal to stop scan
return -1;
}
}
if (IsStrEmpty(filePath)) {
bprintf(PRINT_ERROR, _T("NeoCD_AddGameLib: empty or invalid path\n"));
return 0;
}
if (!IsFileExt((TCHAR*)filePath, _T(".cue")) && !IsFileExt((TCHAR*)filePath, _T(".chd")))
return 0;
SendDlgItemMessage(pGameLib->hGLDlg, IDC_WAIT_PROG, PBM_STEPIT, 0, 0); SendDlgItemMessage(pGameLib->hGLDlg, IDC_WAIT_PROG, PBM_STEPIT, 0, 0);
CDListResult Result;
if (!CDListIdentify(pszPath, &Result) || Result.nPlatform != CDLIST_PLATFORM_NEOCD) return 1;
NeoCDList_CheckISO((TCHAR*)filePath, NeoCD_AddGameLib_Callback); struct GAMELIST* pItem = NeoCD_BuildGameEntry(pszPath, &Result);
if (!pItem) return 1;
if (!GameLib_AddGame(pGameLib, pItem)) {
FreeGameItem(pItem);
}
free_s((void**)&pItem);
return 1; return 1;
} }
static INT32 NeoCD_GetCDImageCount(const TCHAR* filePath) static INT32 NeoCD_GetCDImageCount(const TCHAR* filePath)
{ {
if (!IsFileExt((TCHAR*)filePath, _T(".cue")) && !IsFileExt((TCHAR*)filePath, _T(".chd"))) if (!IsFileExt((TCHAR*)filePath, _T(".cue")) && !IsFileExt((TCHAR*)filePath, _T(".ccd")) && !IsFileExt((TCHAR*)filePath, _T(".chd")))
return 0; return 0;
pGameLib->progressCount++; pGameLib->progressCount++;
@@ -1442,104 +1155,6 @@ static bool FileExists(TCHAR *tcszFile)
DWORD dwAttrib = GetFileAttributes(tcszFile); DWORD dwAttrib = GetFileAttributes(tcszFile);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
} }
#if 0
// This will parse the specified CUE file and return the ISO path, if found
static TCHAR* NeoCDList_ParseCUE(TCHAR* pszFile)
{
//if(!pszFile) return NULL;
TCHAR* szISO = NULL;
szISO = (TCHAR*)malloc(sizeof(TCHAR) * 2048);
if(!szISO) return NULL;
// open file
FILE* fp = NULL;
fp = _tfopen(pszFile, _T("r"));
if(!fp) {
if (szISO)
{
free(szISO);
return NULL;
}
}
while(!feof(fp))
{
TCHAR szBuffer[2048];
TCHAR szOriginal[2048];
TCHAR* s;
TCHAR* t;
_fgetts(szBuffer, 2048, fp);
INT32 nLength = 0;
nLength = _tcslen(szBuffer);
// Remove ASCII control characters from the string (including the 'space' character)
while (szBuffer[nLength-1] < 32 && nLength > 0)
{
szBuffer[nLength-1] = 0;
nLength--;
}
_tcscpy(szOriginal, szBuffer);
if(!_tcsncmp(szBuffer, _T("FILE"), 4))
{
TCHAR* pEnd = _tcsrchr(szBuffer, '"');
if (!pEnd) {
break; // Invalid CUE format
}
*pEnd = 0;
TCHAR* pStart = _tcschr(szBuffer, '"');
if(!pStart) {
break; // Invalid CUE format
}
if(!_tcsncmp(pEnd + 2, _T("BINARY"), 6))
{
_tcscpy(szISO, pStart + 1);
ngcd_list[nListItems].bFoundCUE = true;
_tcscpy(ngcd_list[nListItems].szPathCUE, pszFile);
_tcscpy(ngcd_list[nListItems].szISOFile, pStart + 1);
}
}
// track info
if ((t = LabelCheck(szBuffer, _T("TRACK"))) != 0) {
s = t;
// track number
/*UINT8 track = */ _tcstol(s, &t, 10);
s = t;
// type of track
if ((t = LabelCheck(s, _T("MODE1/2352"))) != 0) {
//bprintf(0, _T(".cue: Track #%d, data.\n"), track);
continue;
}
if ((t = LabelCheck(s, _T("AUDIO"))) != 0) {
//bprintf(0, _T(".cue: Track #%d, AUDIO.\n"), track);
ngcd_list[nListItems].nAudioTracks++;
continue;
}
fclose(fp);
return szISO;
}
}
if(fp) fclose(fp);
return szISO;
}
#endif // 0
static PNGRESOLUTION GetPNGResolutionBuf(void *pPngBuf, size_t nPngSize) static PNGRESOLUTION GetPNGResolutionBuf(void *pPngBuf, size_t nPngSize)
{ {
PNGRESOLUTION nResolution = { 0, 0 }; PNGRESOLUTION nResolution = { 0, 0 };
@@ -2028,7 +1643,7 @@ static INT_PTR CALLBACK NeoCDList_WndProc(HWND hDlg, UINT Msg, WPARAM wParam, LP
{ {
if(nSelectedItem >= 0) { if(nSelectedItem >= 0) {
GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem]; GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem];
const TCHAR* targetFile = (pEntry->bFoundCUE) ? pEntry->szPathCUE : pEntry->szPath; const TCHAR* targetFile = pEntry->szPath;
nCDEmuSelect = 0; nCDEmuSelect = 0;
_tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1); _tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1);
CDEmuImage[MAX_PATH - 1]= _T('\0'); CDEmuImage[MAX_PATH - 1]= _T('\0');
@@ -2122,7 +1737,7 @@ static INT_PTR CALLBACK NeoCDList_WndProc(HWND hDlg, UINT Msg, WPARAM wParam, LP
{ {
if(nSelectedItem >= 0) { if(nSelectedItem >= 0) {
GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem]; GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem];
const TCHAR* targetFile = (pEntry->bFoundCUE) ? pEntry->szPathCUE : pEntry->szPath; const TCHAR* targetFile = pEntry->szPath;
nCDEmuSelect = 0; nCDEmuSelect = 0;
_tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1); _tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1);
CDEmuImage[MAX_PATH - 1]= _T('\0'); CDEmuImage[MAX_PATH - 1]= _T('\0');
+18
View File
@@ -10,6 +10,24 @@ int nActiveGame;
static bool bLoading = 0; static bool bLoading = 0;
#ifdef BUILD_NEOGEO
static void SetNeoCDTitle(TCHAR* pszTitle)
{
TCHAR szText[1024] = _T("");
_sntprintf(szText, _countof(szText), _T(APP_TITLE) _T(" v%.20s") _T(SEPERATOR_1) _T("%s") _T(SEPERATOR_1) _T("%s"), szAppBurnVer, BurnDrvGetText(DRV_FULLNAME), pszTitle);
szText[_countof(szText) - 1] = _T('\0');
SetWindowText(hScrnWnd, szText);
}
void NeoCDInfo_SetTitle()
{
if (!IsNeoGeoCD()) return;
TCHAR* pszTitle = NeoCDInfo_Text(DRV_FULLNAME);
SetNeoCDTitle(pszTitle ? pszTitle : FBALoadStringEx(hAppInst, IDS_UNIDENTIFIED_CD, true));
}
#endif
int OnMenuSelect(HWND, HMENU, int, HMENU, UINT); int OnMenuSelect(HWND, HMENU, int, HMENU, UINT);
int OnInitMenuPopup(HWND, HMENU, UINT, BOOL); int OnInitMenuPopup(HWND, HMENU, UINT, BOOL);
int OnUnInitMenuPopup(HWND, HMENU, UINT, BOOL); int OnUnInitMenuPopup(HWND, HMENU, UINT, BOOL);
+30 -18
View File
@@ -23,6 +23,7 @@ struct ChdImage {
INT32 nFramesPerHunk; INT32 nFramesPerHunk;
UINT32 nTotalHunks; UINT32 nTotalHunks;
INT32 nVersion; INT32 nVersion;
UINT8 Sha1[20];
INT32 nCachedHunk; // -1 = none INT32 nCachedHunk; // -1 = none
ChdTrack Tracks[CHD_MAX_TRACKS + 1]; // +1 dummy lead-out entry ChdTrack Tracks[CHD_MAX_TRACKS + 1]; // +1 dummy lead-out entry
}; };
@@ -174,16 +175,16 @@ static INT32 ChdParseToc(ChdImage* pImage)
return 1; return 1;
} }
pT->nSubSize = ChdSubSizeFromString(szSub); pT->nSubSize = ChdSubSizeFromString(szSub);
pT->nSubType = (pT->nSubSize != 0) ? 1 : 0; pT->nSubType = (pT->nSubSize != 0) ? 1 : 0;
pT->nFrames = nFrames; pT->nFrames = nFrames;
pT->nPregap = nPregap; pT->nPregap = nPregap;
pT->nPostgap = nPostgap; pT->nPostgap = nPostgap;
pT->nPadFrames = nPad; pT->nPadFrames = nPad;
// chdman pads each track up to a 4-frame boundary in the CHD. // chdman pads each track up to a 4-frame boundary in the CHD.
INT32 nPadded = (nFrames + CHD_TRACK_PADDING - 1) / CHD_TRACK_PADDING; INT32 nPadded = (nFrames + CHD_TRACK_PADDING - 1) / CHD_TRACK_PADDING;
pT->nExtraFrames = nPadded * CHD_TRACK_PADDING - nFrames; pT->nExtraFrames = nPadded * CHD_TRACK_PADDING - nFrames;
pT->nControl = (pT->nType == CHD_TRACK_AUDIO) ? 0x01 : 0x41; pT->nControl = (pT->nType == CHD_TRACK_AUDIO) ? 0x01 : 0x41;
} }
if (nTrk == 0) { if (nTrk == 0) {
@@ -278,6 +279,7 @@ ChdImage* ChdOpenFile(const TCHAR* szPath)
pImage->nFramesPerHunk = pImage->nHunkBytes / CHD_FRAME_SIZE; pImage->nFramesPerHunk = pImage->nHunkBytes / CHD_FRAME_SIZE;
pImage->nTotalHunks = pHeader->totalhunks; pImage->nTotalHunks = pHeader->totalhunks;
pImage->nVersion = (INT32)pHeader->version; pImage->nVersion = (INT32)pHeader->version;
memcpy(pImage->Sha1, pHeader->sha1, sizeof(pImage->Sha1));
pImage->nContainer = ChdDetectContainer(pImage); pImage->nContainer = ChdDetectContainer(pImage);
@@ -316,13 +318,25 @@ void ChdClose(ChdImage* pImage)
free(pImage); free(pImage);
} }
INT32 ChdGetContainerType(ChdImage* pImage) { return pImage ? pImage->nContainer : CHD_CONTAINER_NONE; } INT32 ChdGetContainerType(ChdImage* pImage) { return pImage ? pImage->nContainer : CHD_CONTAINER_NONE; }
INT32 ChdGetNumTracks(ChdImage* pImage) { return pImage ? pImage->nNumTracks : 0; } INT32 ChdGetNumTracks(ChdImage* pImage) { return pImage ? pImage->nNumTracks : 0; }
INT32 ChdGetTotalFrames(ChdImage* pImage) { return pImage ? pImage->nTotalFrames : 0; } INT32 ChdGetTotalFrames(ChdImage* pImage) { return pImage ? pImage->nTotalFrames : 0; }
INT32 ChdGetVersion(ChdImage* pImage) { return pImage ? pImage->nVersion : 0; } INT32 ChdGetVersion(ChdImage* pImage) { return pImage ? pImage->nVersion : 0; }
INT32 ChdGetHunkBytes(ChdImage* pImage) { return pImage ? pImage->nHunkBytes : 0; } INT32 ChdGetHunkBytes(ChdImage* pImage) { return pImage ? pImage->nHunkBytes : 0; }
INT32 ChdGetFramesPerHunk(ChdImage* pImage) { return pImage ? pImage->nFramesPerHunk : 0; } INT32 ChdGetFramesPerHunk(ChdImage* pImage) { return pImage ? pImage->nFramesPerHunk : 0; }
INT32 ChdGetSha1(ChdImage* pImage, UINT8* pSha1)
{
if (!pImage || !pSha1 || pImage->nVersion < 3) return 1;
for (INT32 i = 0; i < (INT32)sizeof(pImage->Sha1); i++) {
if (pImage->Sha1[i]) {
memcpy(pSha1, pImage->Sha1, sizeof(pImage->Sha1));
return 0;
}
}
return 1;
}
const ChdTrack* ChdGetTrack(ChdImage* pImage, INT32 nTrack) const ChdTrack* ChdGetTrack(ChdImage* pImage, INT32 nTrack)
{ {
if (!pImage || nTrack < 0 || nTrack >= pImage->nNumTracks) { if (!pImage || nTrack < 0 || nTrack >= pImage->nNumTracks) {
@@ -342,7 +356,7 @@ static INT32 ChdReadFrameBytes(ChdImage* pImage, INT32 nChdFrame, INT32 nOffset,
return 1; return 1;
} }
INT32 nHunk = nChdFrame / pImage->nFramesPerHunk; INT32 nHunk = nChdFrame / pImage->nFramesPerHunk;
INT32 nFrameInHunk = nChdFrame % pImage->nFramesPerHunk; INT32 nFrameInHunk = nChdFrame % pImage->nFramesPerHunk;
if ((UINT32)nHunk >= pImage->nTotalHunks) { if ((UINT32)nHunk >= pImage->nTotalHunks) {
return 1; return 1;
@@ -393,7 +407,7 @@ INT32 ChdReadSector(ChdImage* pImage, INT32 nLba, INT32 nDataType, UINT8* pDest)
return 1; return 1;
} }
INT32 nTrack = 0; INT32 nTrack = 0;
INT32 nChdFrame = ChdLogicalToChd(pImage, nLba, &nTrack); INT32 nChdFrame = ChdLogicalToChd(pImage, nLba, &nTrack);
if (nChdFrame < 0) { if (nChdFrame < 0) {
return 1; return 1;
@@ -418,7 +432,7 @@ INT32 ChdReadSector(ChdImage* pImage, INT32 nLba, INT32 nDataType, UINT8* pDest)
// 2352 mode-1 raw sector out of 2048 mode-1 data (synthesize sync + header) // 2352 mode-1 raw sector out of 2048 mode-1 data (synthesize sync + header)
if (nDataType == CHD_TRACK_MODE1_RAW && nTrackType == CHD_TRACK_MODE1) { if (nDataType == CHD_TRACK_MODE1_RAW && nTrackType == CHD_TRACK_MODE1) {
static const UINT8 SyncBytes[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; static const UINT8 SyncBytes[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
UINT32 nMsf = ChdLbaToMsf(nLba + 150); UINT32 nMsf = ChdLbaToMsf(nLba + 150);
memset(pDest, 0, 2352); memset(pDest, 0, 2352);
memcpy(pDest, SyncBytes, 12); memcpy(pDest, SyncBytes, 12);
@@ -430,8 +444,7 @@ INT32 ChdReadSector(ChdImage* pImage, INT32 nLba, INT32 nDataType, UINT8* pDest)
} }
// 2048 mode-1 data out of a mode-2 form1 or raw sector // 2048 mode-1 data out of a mode-2 form1 or raw sector
if (nDataType == CHD_TRACK_MODE1 && if (nDataType == CHD_TRACK_MODE1 && (nTrackType == CHD_TRACK_MODE2_FORM1 || nTrackType == CHD_TRACK_MODE2_RAW)) {
(nTrackType == CHD_TRACK_MODE2_FORM1 || nTrackType == CHD_TRACK_MODE2_RAW)) {
return ChdReadFrameBytes(pImage, nChdFrame, 24, 2048, pDest); return ChdReadFrameBytes(pImage, nChdFrame, 24, 2048, pDest);
} }
@@ -441,8 +454,7 @@ INT32 ChdReadSector(ChdImage* pImage, INT32 nLba, INT32 nDataType, UINT8* pDest)
} }
// 2336 mode-2 data out of a 2352 raw sector (skip the header) // 2336 mode-2 data out of a 2352 raw sector (skip the header)
if (nDataType == CHD_TRACK_MODE2 && if (nDataType == CHD_TRACK_MODE2 && (nTrackType == CHD_TRACK_MODE1_RAW || nTrackType == CHD_TRACK_MODE2_RAW)) {
(nTrackType == CHD_TRACK_MODE1_RAW || nTrackType == CHD_TRACK_MODE2_RAW)) {
return ChdReadFrameBytes(pImage, nChdFrame, 16, 2336, pDest); return ChdReadFrameBytes(pImage, nChdFrame, 16, 2336, pDest);
} }
+23 -22
View File
@@ -7,37 +7,37 @@
// Track types (mirror libchdr cdrom.h so consumers need not include it). // Track types (mirror libchdr cdrom.h so consumers need not include it).
enum { enum {
CHD_TRACK_MODE1 = 0, // mode 1, 2048 data bytes CHD_TRACK_MODE1 = 0, // mode 1, 2048 data bytes
CHD_TRACK_MODE1_RAW, // mode 1, 2352 raw bytes CHD_TRACK_MODE1_RAW, // mode 1, 2352 raw bytes
CHD_TRACK_MODE2, // mode 2, 2336 data bytes CHD_TRACK_MODE2, // mode 2, 2336 data bytes
CHD_TRACK_MODE2_FORM1, // mode 2 form 1, 2048 data bytes CHD_TRACK_MODE2_FORM1, // mode 2 form 1, 2048 data bytes
CHD_TRACK_MODE2_FORM2, // mode 2 form 2, 2324 data bytes CHD_TRACK_MODE2_FORM2, // mode 2 form 2, 2324 data bytes
CHD_TRACK_MODE2_FORM_MIX, // mode 2 mixed, 2336 data bytes CHD_TRACK_MODE2_FORM_MIX, // mode 2 mixed, 2336 data bytes
CHD_TRACK_MODE2_RAW, // mode 2, 2352 raw bytes CHD_TRACK_MODE2_RAW, // mode 2, 2352 raw bytes
CHD_TRACK_AUDIO, // redbook audio, 2352 bytes CHD_TRACK_AUDIO, // redbook audio, 2352 bytes
CHD_TRACK_RAW_DONTCARE // read: hand back whatever the track stores CHD_TRACK_RAW_DONTCARE // read: hand back whatever the track stores
}; };
// Container class, decided at open time. // Container class, decided at open time.
enum { enum {
CHD_CONTAINER_NONE = 0, CHD_CONTAINER_NONE = 0,
CHD_CONTAINER_CD, // CHT2 / CHTR metadata CHD_CONTAINER_CD, // CHT2 / CHTR metadata
CHD_CONTAINER_GDROM, // CHGD metadata CHD_CONTAINER_GDROM, // CHGD metadata
CHD_CONTAINER_HDD // GDDD / hard-disk metadata (e.g. CPS-2 data) CHD_CONTAINER_HDD // GDDD / hard-disk metadata (e.g. CPS-2 data)
}; };
struct ChdTrack { struct ChdTrack {
INT32 nType; // CHD_TRACK_* INT32 nType; // CHD_TRACK_*
INT32 nSubType; // 0 none / 1 normal / 2 raw INT32 nSubType; // 0 none / 1 normal / 2 raw
INT32 nDataSize; // 2048 / 2324 / 2336 / 2352 INT32 nDataSize; // 2048 / 2324 / 2336 / 2352
INT32 nSubSize; // 0 or 96 INT32 nSubSize; // 0 or 96
INT32 nFrames; // sectors in the track (incl. pregap) INT32 nFrames; // sectors in the track (incl. pregap)
INT32 nPregap; // pregap sectors INT32 nPregap; // pregap sectors
INT32 nPostgap; // postgap sectors INT32 nPostgap; // postgap sectors
INT32 nPadFrames; // GD-ROM padding sectors INT32 nPadFrames; // GD-ROM padding sectors
INT32 nExtraFrames; // chdman 4-frame-boundary padding INT32 nExtraFrames; // chdman 4-frame-boundary padding
INT32 nControl; // Q-channel control nibble << 4 flags (0x41 data / 0x01 audio) INT32 nControl; // Q-channel control nibble << 4 flags (0x41 data / 0x01 audio)
INT32 nPhysFrameOfs; INT32 nPhysFrameOfs;
INT32 nChdFrameOfs; INT32 nChdFrameOfs;
INT32 nLogFrameOfs; INT32 nLogFrameOfs;
@@ -63,6 +63,7 @@ const TCHAR* ChdTrackTypeName(INT32 nType);
INT32 ChdGetVersion(ChdImage* pImage); INT32 ChdGetVersion(ChdImage* pImage);
INT32 ChdGetHunkBytes(ChdImage* pImage); INT32 ChdGetHunkBytes(ChdImage* pImage);
INT32 ChdGetFramesPerHunk(ChdImage* pImage); INT32 ChdGetFramesPerHunk(ChdImage* pImage);
INT32 ChdGetSha1(ChdImage* pImage, UINT8* pSha1);
// Total logical sectors on the disc (lead-out LBA). // Total logical sectors on the disc (lead-out LBA).
INT32 ChdGetTotalFrames(ChdImage* pImage); INT32 ChdGetTotalFrames(ChdImage* pImage);
+755 -132
View File
File diff suppressed because it is too large. Load diff
+39
View File
@@ -1,6 +1,45 @@
#ifndef CD_IMG_H_ #ifndef CD_IMG_H_
#define CD_IMG_H_ #define CD_IMG_H_
#define CDIMAGE_MAX_TRACKS (99)
#define CDIMAGE_SHA1_SIZE (20)
enum {
CDIMAGE_TRACK_AUDIO = 0,
CDIMAGE_TRACK_MODE1_2048,
CDIMAGE_TRACK_MODE1_2352,
CDIMAGE_TRACK_MODE2_2336,
CDIMAGE_TRACK_MODE2_2352
};
struct CDImageTrack {
INT32 nNumber;
INT32 nType;
INT32 nControl;
INT32 nStartLBA;
INT32 nIndex0LBA;
INT32 nIndex1LBA;
INT32 nPregap;
INT32 nSectors;
INT32 nSectorSize;
INT32 nUserOffset;
INT32 nUserSize;
const TCHAR* szPath;
};
struct CDImage;
CDImage* CDImageOpen(const TCHAR* szPath);
void CDImageClose(CDImage* pImage);
INT32 CDImageGetTrackCount(const CDImage* pImage);
INT32 CDImageGetAudioTrackCount(const CDImage* pImage);
INT32 CDImageGetSectorCount(const CDImage* pImage);
const TCHAR* CDImageGetPath(const CDImage* pImage);
const CDImageTrack* CDImageGetTrack(const CDImage* pImage, INT32 nTrack);
INT32 CDImageReadRawSector(CDImage* pImage, INT32 nLba, UINT8* pDest);
INT32 CDImageReadUserSector(CDImage* pImage, INT32 nLba, UINT8* pDest, INT32* pnSize);
INT32 CDImageGetChdSha1(const CDImage* pImage, UINT8* pSha1);
INT32 cdimgCountChdAudioTracks(TCHAR* pszFile); INT32 cdimgCountChdAudioTracks(TCHAR* pszFile);
extern struct CDEmuDo cdimgDo; extern struct CDEmuDo cdimgDo;