mirror of
https://github.com/libretro/FBNeo.git
synced 2026-11-07 02:55:59 -10:00
Step 2: Globalize cdlist.cpp to replace platform‑specific neocdlist.cpp implementations
This commit is contained in:
1 parent
33768c13a4
commit
e1a4d99852
31 files changed
+3332
-2273
No files matched your search
@@ -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 \
|
||||
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 \
|
||||
romdata.o mbtwc.o zip.o \
|
||||
\
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ alldir += burner burner/pi burner/sdl dep/libs/libspng dep/libs/lib7z \
|
||||
intf/perfcount intf/perfcount/pi dep/generated \
|
||||
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 \
|
||||
sshot.o state.o statec.o unzip.o zipfn.o \
|
||||
@@ -269,7 +269,7 @@ else
|
||||
endif
|
||||
|
||||
# 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
|
||||
ifdef INCLUDE_7Z_SUPPORT
|
||||
|
||||
+1
-1
@@ -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/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 \
|
||||
\
|
||||
|
||||
+1
-1
@@ -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/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 \
|
||||
\
|
||||
|
||||
@@ -84,13 +84,19 @@ INCLUDEPATH += \
|
||||
$$SRC/dep/libs \
|
||||
$$SRC/dep/libs/libpng \
|
||||
$$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 \
|
||||
LSB_FIRST \
|
||||
"__fastcall=" \
|
||||
"_fastcall=" \
|
||||
WITH_QTCREATOR \
|
||||
INCLUDE_LIB_PNGH
|
||||
INCLUDE_LIB_PNGH \
|
||||
CHDR_SYSTEM_ZLIB
|
||||
|
||||
linux: DEFINES += BUILD_QT_LINUX
|
||||
macx: DEFINES += BUILD_QT_MACX
|
||||
@@ -389,7 +395,7 @@ $$DRV_NEOGEO {
|
||||
|
||||
HEADERS += $$files(../../src/burn/drv/neogeo/*.h)
|
||||
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/lowpass2.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/video/vid_interface.cpp \
|
||||
../../src/intf/video/vid_support.cpp \
|
||||
|
||||
@@ -72,13 +72,19 @@ INCLUDEPATH += \
|
||||
$$SRC/intf/cd \
|
||||
$$SRC/dep/libs/libpng \
|
||||
$$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 \
|
||||
LSB_FIRST \
|
||||
"__fastcall=" \
|
||||
"_fastcall=" \
|
||||
WITH_QTCREATOR \
|
||||
INCLUDE_LIB_PNGH
|
||||
INCLUDE_LIB_PNGH \
|
||||
CHDR_SYSTEM_ZLIB
|
||||
|
||||
# no warnings...
|
||||
QMAKE_CXXFLAGS += -w
|
||||
@@ -1071,6 +1077,24 @@ SOURCES += \
|
||||
../../src/intf/audio/lowpass2.cpp \
|
||||
../../src/intf/audio/sdl/aud_sdl.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/sdl/inp_sdl.cpp \
|
||||
../../src/intf/video/vid_interface.cpp \
|
||||
@@ -1078,7 +1102,7 @@ SOURCES += \
|
||||
../../src/intf/video/sdl/vid_sdlfx.cpp \
|
||||
../../src/intf/video/sdl/vid_sdlopengl.cpp \
|
||||
../../src/cpu/z80_intf.cpp \
|
||||
../../src/burner/libretro/neocdlist.cpp \
|
||||
../../src/burner/cdlist.cpp \
|
||||
../../src/intf/video/vid_softfx.cpp \
|
||||
../../src/intf/video/scalers/2xpm.cpp \
|
||||
../../src/intf/video/scalers/2xsai.cpp \
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<ClCompile Include="..\..\src\burner\luasav.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\misc.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\sshot.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\state.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\statec.cpp" />
|
||||
@@ -66,7 +67,7 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\menu.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\numdial.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
|
||||
@@ -75,7 +76,6 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\progress.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\replay.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\run.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
|
||||
|
||||
@@ -1465,8 +1465,8 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
<ClCompile Include="..\..\src\burner\cdlist.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
@@ -3388,6 +3388,9 @@
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
@@ -3568,9 +3571,6 @@
|
||||
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
|
||||
<Filter>burn\drv\pre90s</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
|
||||
<Filter>burn\drv\taito</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<ClCompile Include="..\..\src\burner\luasav.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\misc.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\sshot.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\state.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\statec.cpp" />
|
||||
@@ -66,7 +67,7 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\menu.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\numdial.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
|
||||
@@ -75,7 +76,6 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\progress.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\replay.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\run.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
|
||||
|
||||
@@ -1465,8 +1465,8 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
<ClCompile Include="..\..\src\burner\cdlist.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
@@ -3388,6 +3388,9 @@
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
@@ -3568,9 +3571,6 @@
|
||||
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
|
||||
<Filter>burn\drv\pre90s</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
|
||||
<Filter>burn\drv\taito</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<ClCompile Include="..\..\src\burner\luasav.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\misc.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\sshot.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\state.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\statec.cpp" />
|
||||
@@ -66,7 +67,7 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\menu.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\numdial.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
|
||||
@@ -75,7 +76,6 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\progress.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\replay.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\run.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
|
||||
|
||||
@@ -1465,8 +1465,8 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
<ClCompile Include="..\..\src\burner\cdlist.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
@@ -3388,6 +3388,9 @@
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\luaconsole.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
@@ -3568,9 +3571,6 @@
|
||||
<ClCompile Include="..\..\src\burn\drv\pre90s\d_lockon.cpp">
|
||||
<Filter>burn\drv\pre90s</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burn\drv\taito\d_superqix.cpp">
|
||||
<Filter>burn\drv\taito</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -1036,6 +1036,7 @@
|
||||
<ClCompile Include="..\..\src\burner\luasav.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\misc.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\sshot.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\state.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\statec.cpp" />
|
||||
@@ -1069,7 +1070,7 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\memcard.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\menu.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\numdial.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\paletteviewer.cpp" />
|
||||
@@ -1078,7 +1079,6 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\progress.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\replay.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\run.cpp" />
|
||||
<ClCompile Include="..\..\src\burner\win32\scrn.cpp" />
|
||||
|
||||
@@ -3007,6 +3007,9 @@
|
||||
<ClCompile Include="..\..\src\burner\nvram.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\sshot.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
@@ -3106,8 +3109,8 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\misc_win32.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdlist.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
<ClCompile Include="..\..\src\burner\cdlist.cpp">
|
||||
<Filter>burner</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\neocdsel.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
@@ -3133,9 +3136,6 @@
|
||||
<ClCompile Include="..\..\src\burner\win32\res.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\romdata.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\burner\win32\roms.cpp">
|
||||
<Filter>burner\win32</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -1,5 +1,7 @@
|
||||
#ifndef _neocdlist_
|
||||
#define _neocdlist_
|
||||
#ifndef NEOCDLIST_H_
|
||||
#define NEOCDLIST_H_
|
||||
|
||||
#include "cdlist.h"
|
||||
|
||||
struct NGCDGAME
|
||||
{
|
||||
@@ -11,143 +13,28 @@ struct NGCDGAME
|
||||
};
|
||||
|
||||
NGCDGAME* GetNeoGeoCDInfo(UINT32 nID);
|
||||
INT32 GetNeoCDTitle(UINT32 nGameID);
|
||||
INT32 GetNeoGeoCD_Identifier();
|
||||
INT32 GetNGCDGameTitle(const UINT32 nGameID, NGCDGAME** ppOutGame, bool bPrintLog);
|
||||
void FreeNGCDGame(NGCDGAME** ppGame);
|
||||
INT32 NeoCDList_CheckISO(TCHAR* pszFile, void (*pfEntryCallBack)(INT32, TCHAR*));
|
||||
INT32 GetNeoCDTitle(UINT32 nGameID);
|
||||
INT32 GetNeoGeoCD_Identifier();
|
||||
|
||||
#ifdef BUILD_NEOGEO
|
||||
bool IsNeoGeoCD(); // neo_run.cpp
|
||||
TCHAR* GetIsoPath(); // cd_isowav.cpp
|
||||
|
||||
INT32 NeoCDInfo_Init();
|
||||
TCHAR* NeoCDInfo_Text(INT32 nText);
|
||||
INT32 NeoCDInfo_ID();
|
||||
void NeoCDInfo_SetTitle();
|
||||
void NeoCDInfo_Exit();
|
||||
#else
|
||||
static inline bool IsNeoGeoCD() { return false; }
|
||||
static inline TCHAR* GetIsoPath() { return NULL; }
|
||||
static inline int NeoCDInfo_Init() { return 0; }
|
||||
static inline TCHAR* NeoCDInfo_Text(int) { return NULL; }
|
||||
static inline int NeoCDInfo_ID() { return 0; }
|
||||
static inline void NeoCDInfo_SetTitle() { }
|
||||
static inline void NeoCDInfo_Exit() { }
|
||||
static inline bool IsNeoGeoCD() { return false; }
|
||||
static inline TCHAR* GetIsoPath() { return NULL; }
|
||||
static inline INT32 NeoCDInfo_Init() { return 0; }
|
||||
static inline TCHAR* NeoCDInfo_Text(INT32) { return NULL; }
|
||||
static inline INT32 NeoCDInfo_ID() { return 0; }
|
||||
static inline void NeoCDInfo_SetTitle() { }
|
||||
static inline void NeoCDInfo_Exit() { }
|
||||
#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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -27,7 +27,8 @@ frontend_sources = files(
|
||||
'logdialog.cpp',
|
||||
'main.cpp',
|
||||
'mainwindow.cpp',
|
||||
'neocdlist.cpp',
|
||||
'../cdlist.cpp',
|
||||
'../../intf/cd/cd_img.cpp',
|
||||
'oglviewport.cpp',
|
||||
'progress.cpp',
|
||||
'qaudiointerface.cpp',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ frontend_sources = files(
|
||||
'localise_gamelist.cpp',
|
||||
'main.cpp',
|
||||
'media.cpp',
|
||||
'neocdlist.cpp',
|
||||
'../cdlist.cpp',
|
||||
'replay.cpp',
|
||||
'romdata.cpp',
|
||||
'run.cpp',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 LoadBitmap(HWND hWnd, FILE* fp, int nWidth, int nHeight, int nPreset);
|
||||
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"
|
||||
|
||||
// romdata.cpp
|
||||
|
||||
@@ -60,7 +60,7 @@ frontend_sources = files(
|
||||
'memcard.cpp',
|
||||
'menu.cpp',
|
||||
'misc_win32.cpp',
|
||||
'neocdlist.cpp',
|
||||
'../cdlist.cpp',
|
||||
'neocdsel.cpp',
|
||||
'numdial.cpp',
|
||||
'paletteviewer.cpp',
|
||||
@@ -69,7 +69,6 @@ frontend_sources = files(
|
||||
'progress.cpp',
|
||||
'replay.cpp',
|
||||
'res.cpp',
|
||||
'romdata.cpp',
|
||||
'roms.cpp',
|
||||
'run.cpp',
|
||||
'scrn.cpp',
|
||||
|
||||
@@ -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
@@ -40,17 +40,17 @@ const INT32 nSectorLength = 2352;
|
||||
|
||||
// Stores single NeoGeo CD game metadata
|
||||
struct GAMELIST {
|
||||
bool bFoundCUE; // True if game loaded from .cue sheet file
|
||||
TCHAR* szPathCUE; // Full absolute path of cue file
|
||||
TCHAR* szPath; // Full absolute path of real image file (chd/bin)
|
||||
TCHAR* szISOFile; // Raw image filename extracted from cue
|
||||
TCHAR* szGameId; // Game identification number string
|
||||
TCHAR* szShortName; // Game short name for cover matching
|
||||
TCHAR* szTitle; // Game title
|
||||
TCHAR* szPublisher; // Publisher + release year combined string
|
||||
TCHAR* szAudioTracks; // Audio tracks string
|
||||
// TCHAR szTracks[99][256]; // Unused track storage array, commented out
|
||||
INT32 nIconIdx; // index inside NeoCD_ImageList
|
||||
INT32 nPlatform;
|
||||
UINT64 nKey;
|
||||
TCHAR* szPath;
|
||||
TCHAR* szISOFile;
|
||||
TCHAR* szGameId;
|
||||
TCHAR* szShortName;
|
||||
TCHAR* szTitle;
|
||||
TCHAR* szPublisher;
|
||||
TCHAR* szAudioTracks;
|
||||
TCHAR* szRequirement;
|
||||
INT32 nIconIdx;
|
||||
};
|
||||
|
||||
// Central game library container, thread-safe with critical section lock
|
||||
@@ -389,13 +389,13 @@ static void FreeGameItem(struct GAMELIST* pItem)
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
free_s((void**)&pItem->szPathCUE);
|
||||
free_s((void**)&pItem->szPath);
|
||||
free_s((void**)&pItem->szISOFile);
|
||||
free_s((void**)&pItem->szShortName);
|
||||
free_s((void**)&pItem->szPublisher);
|
||||
free_s((void**)&pItem->szTitle);
|
||||
free_s((void**)&pItem->szAudioTracks);
|
||||
free_s((void**)&pItem->szRequirement);
|
||||
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];
|
||||
|
||||
// Copy numeric value fields from source template
|
||||
pDst->bFoundCUE = pSrcTemplate->bFoundCUE;
|
||||
pDst->nPlatform = pSrcTemplate->nPlatform;
|
||||
pDst->nKey = pSrcTemplate->nKey;
|
||||
pDst->nIconIdx = pSrcTemplate->nIconIdx;
|
||||
|
||||
// Transfer string pointer ownership (share original heap memory, no duplication)
|
||||
pDst->szPathCUE = pSrcTemplate->szPathCUE;
|
||||
pDst->szPath = pSrcTemplate->szPath;
|
||||
pDst->szISOFile = pSrcTemplate->szISOFile;
|
||||
pDst->szShortName = pSrcTemplate->szShortName;
|
||||
@@ -447,6 +445,7 @@ static BOOL GameLib_AddGame(struct GAME_LIB* pLib, struct GAMELIST* pSrcTemplate
|
||||
pDst->szTitle = pSrcTemplate->szTitle;
|
||||
pDst->szGameId = pSrcTemplate->szGameId;
|
||||
pDst->szAudioTracks = pSrcTemplate->szAudioTracks;
|
||||
pDst->szRequirement = pSrcTemplate->szRequirement;
|
||||
|
||||
// Replace old game data array with reallocated buffer and update item counter
|
||||
pLib->pGameData = pNew;
|
||||
@@ -511,313 +510,57 @@ static void GameLib_Destroy(struct GAME_LIB* pLib)
|
||||
pGameLib = NULL;
|
||||
}
|
||||
|
||||
// ParseCueGetImageFile
|
||||
// Return NULL if file open failed / no valid FILE BINARY segment found
|
||||
TCHAR* ParseCueGetImageFile(const TCHAR* cueFullPath)
|
||||
static struct GAMELIST* NeoCD_BuildGameEntry(const TCHAR* pszPath, const CDListResult* pResult)
|
||||
{
|
||||
if (IsStrEmpty(cueFullPath))
|
||||
return NULL;
|
||||
if (!pszPath || !pResult || pResult->nPlatform != CDLIST_PLATFORM_NEOCD) return NULL;
|
||||
CDImage* pImage = CDImageOpen(pszPath);
|
||||
if (!pImage) return NULL;
|
||||
|
||||
FILE* fp = _tfopen(cueFullPath, _T("r"));
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
TCHAR szCueDir[2048] = { 0 };
|
||||
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;
|
||||
const CDImageTrack* pDataTrack = NULL;
|
||||
for (INT32 i = 0; i < CDImageGetTrackCount(pImage); i++) {
|
||||
const CDImageTrack* pTrack = CDImageGetTrack(pImage, i);
|
||||
if (pTrack && pTrack->nType != CDIMAGE_TRACK_AUDIO) {
|
||||
pDataTrack = pTrack;
|
||||
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));
|
||||
if (!pItem)
|
||||
return NULL;
|
||||
|
||||
pItem->nIconIdx = 0;
|
||||
|
||||
FILE* fp = _tfopen(cueFullPath, _T("r"));
|
||||
if (!fp) {
|
||||
free_s((void**)&pItem);
|
||||
if (!pItem) {
|
||||
CDImageClose(pImage);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Extract directory folder from full cue path, use safe _tcsncpy
|
||||
TCHAR szCueDir[2048] = { 0 };
|
||||
size_t nStrLen = ARRAY_SIZE(szCueDir);
|
||||
_tcsncpy(szCueDir, cueFullPath, nStrLen - 1);
|
||||
szCueDir[nStrLen - 1] = _T('\0');
|
||||
pItem->nPlatform = pResult->nPlatform;
|
||||
pItem->nKey = pResult->nNeoID;
|
||||
pItem->nIconIdx = IsFileExt((TCHAR*)pszPath, _T(".chd")) ? 1 : 0;
|
||||
pItem->szPath = _tcsdup_s(CDImageGetPath(pImage));
|
||||
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('\\'));
|
||||
if (pSep)
|
||||
*(pSep + 1) = _T('\0');
|
||||
TCHAR szText[256] = { 0 };
|
||||
_sntprintf(szText, ARRAY_SIZE(szText), _T("%s (%s)"), pResult->Metadata.szCompany, pResult->Metadata.szYear);
|
||||
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;
|
||||
TCHAR szBuffer[2048] = { 0 };
|
||||
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) {
|
||||
if (!pItem->szPath || !pItem->szISOFile || !pItem->szShortName || !pItem->szTitle ||
|
||||
!pItem->szPublisher || !pItem->szAudioTracks || !pItem->szGameId) {
|
||||
FreeGameItem(pItem);
|
||||
free_s((void**)&pItem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// Lazy init game lib
|
||||
@@ -831,57 +574,27 @@ static bool NeoCD_GameLibInit()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback function for directory scan, construct and store game metadata into game library
|
||||
static void NeoCD_AddGameLib_Callback(INT32 nGameID, TCHAR* filePath)
|
||||
static INT32 NeoCD_AddGameLib(const TCHAR* pszPath)
|
||||
{
|
||||
struct GAMELIST* pTempItem = NULL;
|
||||
// Build temporary game metadata entry from cue/chd file
|
||||
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;
|
||||
if (pGameLib && pGameLib->hGLEvent && WaitForSingleObject(pGameLib->hGLEvent, 0) == WAIT_OBJECT_0) return -1;
|
||||
if (!pszPath || (!IsFileExt((TCHAR*)pszPath, _T(".cue")) && !IsFileExt((TCHAR*)pszPath, _T(".ccd")) && !IsFileExt((TCHAR*)pszPath, _T(".chd")))) return 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
pGameLib->progressCount++;
|
||||
@@ -1442,104 +1155,6 @@ static bool FileExists(TCHAR *tcszFile)
|
||||
DWORD dwAttrib = GetFileAttributes(tcszFile);
|
||||
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)
|
||||
{
|
||||
PNGRESOLUTION nResolution = { 0, 0 };
|
||||
@@ -2028,7 +1643,7 @@ static INT_PTR CALLBACK NeoCDList_WndProc(HWND hDlg, UINT Msg, WPARAM wParam, LP
|
||||
{
|
||||
if(nSelectedItem >= 0) {
|
||||
GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem];
|
||||
const TCHAR* targetFile = (pEntry->bFoundCUE) ? pEntry->szPathCUE : pEntry->szPath;
|
||||
const TCHAR* targetFile = pEntry->szPath;
|
||||
nCDEmuSelect = 0;
|
||||
_tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1);
|
||||
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) {
|
||||
GAMELIST* pEntry = &pGameLib->pGameData[nSelectedItem];
|
||||
const TCHAR* targetFile = (pEntry->bFoundCUE) ? pEntry->szPathCUE : pEntry->szPath;
|
||||
const TCHAR* targetFile = pEntry->szPath;
|
||||
nCDEmuSelect = 0;
|
||||
_tcsncpy(CDEmuImage, targetFile, MAX_PATH - 1);
|
||||
CDEmuImage[MAX_PATH - 1]= _T('\0');
|
||||
|
||||
@@ -10,6 +10,24 @@ int nActiveGame;
|
||||
|
||||
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 OnInitMenuPopup(HWND, HMENU, UINT, BOOL);
|
||||
int OnUnInitMenuPopup(HWND, HMENU, UINT, BOOL);
|
||||
|
||||
+30
-18
@@ -23,6 +23,7 @@ struct ChdImage {
|
||||
INT32 nFramesPerHunk;
|
||||
UINT32 nTotalHunks;
|
||||
INT32 nVersion;
|
||||
UINT8 Sha1[20];
|
||||
INT32 nCachedHunk; // -1 = none
|
||||
ChdTrack Tracks[CHD_MAX_TRACKS + 1]; // +1 dummy lead-out entry
|
||||
};
|
||||
@@ -174,16 +175,16 @@ static INT32 ChdParseToc(ChdImage* pImage)
|
||||
return 1;
|
||||
}
|
||||
|
||||
pT->nSubSize = ChdSubSizeFromString(szSub);
|
||||
pT->nSubType = (pT->nSubSize != 0) ? 1 : 0;
|
||||
pT->nFrames = nFrames;
|
||||
pT->nPregap = nPregap;
|
||||
pT->nPostgap = nPostgap;
|
||||
pT->nSubSize = ChdSubSizeFromString(szSub);
|
||||
pT->nSubType = (pT->nSubSize != 0) ? 1 : 0;
|
||||
pT->nFrames = nFrames;
|
||||
pT->nPregap = nPregap;
|
||||
pT->nPostgap = nPostgap;
|
||||
pT->nPadFrames = nPad;
|
||||
// chdman pads each track up to a 4-frame boundary in the CHD.
|
||||
INT32 nPadded = (nFrames + CHD_TRACK_PADDING - 1) / CHD_TRACK_PADDING;
|
||||
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) {
|
||||
@@ -278,6 +279,7 @@ ChdImage* ChdOpenFile(const TCHAR* szPath)
|
||||
pImage->nFramesPerHunk = pImage->nHunkBytes / CHD_FRAME_SIZE;
|
||||
pImage->nTotalHunks = pHeader->totalhunks;
|
||||
pImage->nVersion = (INT32)pHeader->version;
|
||||
memcpy(pImage->Sha1, pHeader->sha1, sizeof(pImage->Sha1));
|
||||
|
||||
pImage->nContainer = ChdDetectContainer(pImage);
|
||||
|
||||
@@ -316,13 +318,25 @@ void ChdClose(ChdImage* pImage)
|
||||
free(pImage);
|
||||
}
|
||||
|
||||
INT32 ChdGetContainerType(ChdImage* pImage) { return pImage ? pImage->nContainer : CHD_CONTAINER_NONE; }
|
||||
INT32 ChdGetNumTracks(ChdImage* pImage) { return pImage ? pImage->nNumTracks : 0; }
|
||||
INT32 ChdGetTotalFrames(ChdImage* pImage) { return pImage ? pImage->nTotalFrames : 0; }
|
||||
INT32 ChdGetVersion(ChdImage* pImage) { return pImage ? pImage->nVersion : 0; }
|
||||
INT32 ChdGetHunkBytes(ChdImage* pImage) { return pImage ? pImage->nHunkBytes : 0; }
|
||||
INT32 ChdGetContainerType(ChdImage* pImage) { return pImage ? pImage->nContainer : CHD_CONTAINER_NONE; }
|
||||
INT32 ChdGetNumTracks(ChdImage* pImage) { return pImage ? pImage->nNumTracks : 0; }
|
||||
INT32 ChdGetTotalFrames(ChdImage* pImage) { return pImage ? pImage->nTotalFrames : 0; }
|
||||
INT32 ChdGetVersion(ChdImage* pImage) { return pImage ? pImage->nVersion : 0; }
|
||||
INT32 ChdGetHunkBytes(ChdImage* pImage) { return pImage ? pImage->nHunkBytes : 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)
|
||||
{
|
||||
if (!pImage || nTrack < 0 || nTrack >= pImage->nNumTracks) {
|
||||
@@ -342,7 +356,7 @@ static INT32 ChdReadFrameBytes(ChdImage* pImage, INT32 nChdFrame, INT32 nOffset,
|
||||
return 1;
|
||||
}
|
||||
|
||||
INT32 nHunk = nChdFrame / pImage->nFramesPerHunk;
|
||||
INT32 nHunk = nChdFrame / pImage->nFramesPerHunk;
|
||||
INT32 nFrameInHunk = nChdFrame % pImage->nFramesPerHunk;
|
||||
if ((UINT32)nHunk >= pImage->nTotalHunks) {
|
||||
return 1;
|
||||
@@ -393,7 +407,7 @@ INT32 ChdReadSector(ChdImage* pImage, INT32 nLba, INT32 nDataType, UINT8* pDest)
|
||||
return 1;
|
||||
}
|
||||
|
||||
INT32 nTrack = 0;
|
||||
INT32 nTrack = 0;
|
||||
INT32 nChdFrame = ChdLogicalToChd(pImage, nLba, &nTrack);
|
||||
if (nChdFrame < 0) {
|
||||
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)
|
||||
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);
|
||||
memset(pDest, 0, 2352);
|
||||
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
|
||||
if (nDataType == CHD_TRACK_MODE1 &&
|
||||
(nTrackType == CHD_TRACK_MODE2_FORM1 || nTrackType == CHD_TRACK_MODE2_RAW)) {
|
||||
if (nDataType == CHD_TRACK_MODE1 && (nTrackType == CHD_TRACK_MODE2_FORM1 || nTrackType == CHD_TRACK_MODE2_RAW)) {
|
||||
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)
|
||||
if (nDataType == CHD_TRACK_MODE2 &&
|
||||
(nTrackType == CHD_TRACK_MODE1_RAW || nTrackType == CHD_TRACK_MODE2_RAW)) {
|
||||
if (nDataType == CHD_TRACK_MODE2 && (nTrackType == CHD_TRACK_MODE1_RAW || nTrackType == CHD_TRACK_MODE2_RAW)) {
|
||||
return ChdReadFrameBytes(pImage, nChdFrame, 16, 2336, pDest);
|
||||
}
|
||||
|
||||
|
||||
+23
-22
@@ -7,37 +7,37 @@
|
||||
|
||||
// Track types (mirror libchdr cdrom.h so consumers need not include it).
|
||||
enum {
|
||||
CHD_TRACK_MODE1 = 0, // mode 1, 2048 data bytes
|
||||
CHD_TRACK_MODE1_RAW, // mode 1, 2352 raw bytes
|
||||
CHD_TRACK_MODE2, // mode 2, 2336 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_FORM_MIX, // mode 2 mixed, 2336 data bytes
|
||||
CHD_TRACK_MODE2_RAW, // mode 2, 2352 raw bytes
|
||||
CHD_TRACK_AUDIO, // redbook audio, 2352 bytes
|
||||
CHD_TRACK_MODE1 = 0, // mode 1, 2048 data bytes
|
||||
CHD_TRACK_MODE1_RAW, // mode 1, 2352 raw bytes
|
||||
CHD_TRACK_MODE2, // mode 2, 2336 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_FORM_MIX, // mode 2 mixed, 2336 data bytes
|
||||
CHD_TRACK_MODE2_RAW, // mode 2, 2352 raw 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.
|
||||
enum {
|
||||
CHD_CONTAINER_NONE = 0,
|
||||
CHD_CONTAINER_CD, // CHT2 / CHTR metadata
|
||||
CHD_CONTAINER_GDROM, // CHGD metadata
|
||||
CHD_CONTAINER_HDD // GDDD / hard-disk metadata (e.g. CPS-2 data)
|
||||
CHD_CONTAINER_CD, // CHT2 / CHTR metadata
|
||||
CHD_CONTAINER_GDROM, // CHGD metadata
|
||||
CHD_CONTAINER_HDD // GDDD / hard-disk metadata (e.g. CPS-2 data)
|
||||
};
|
||||
|
||||
struct ChdTrack {
|
||||
INT32 nType; // CHD_TRACK_*
|
||||
INT32 nSubType; // 0 none / 1 normal / 2 raw
|
||||
INT32 nDataSize; // 2048 / 2324 / 2336 / 2352
|
||||
INT32 nSubSize; // 0 or 96
|
||||
INT32 nFrames; // sectors in the track (incl. pregap)
|
||||
INT32 nPregap; // pregap sectors
|
||||
INT32 nPostgap; // postgap sectors
|
||||
INT32 nPadFrames; // GD-ROM padding sectors
|
||||
INT32 nExtraFrames; // chdman 4-frame-boundary padding
|
||||
INT32 nControl; // Q-channel control nibble << 4 flags (0x41 data / 0x01 audio)
|
||||
INT32 nType; // CHD_TRACK_*
|
||||
INT32 nSubType; // 0 none / 1 normal / 2 raw
|
||||
INT32 nDataSize; // 2048 / 2324 / 2336 / 2352
|
||||
INT32 nSubSize; // 0 or 96
|
||||
INT32 nFrames; // sectors in the track (incl. pregap)
|
||||
INT32 nPregap; // pregap sectors
|
||||
INT32 nPostgap; // postgap sectors
|
||||
INT32 nPadFrames; // GD-ROM padding sectors
|
||||
INT32 nExtraFrames; // chdman 4-frame-boundary padding
|
||||
INT32 nControl; // Q-channel control nibble << 4 flags (0x41 data / 0x01 audio)
|
||||
INT32 nPhysFrameOfs;
|
||||
INT32 nChdFrameOfs;
|
||||
INT32 nLogFrameOfs;
|
||||
@@ -63,6 +63,7 @@ const TCHAR* ChdTrackTypeName(INT32 nType);
|
||||
INT32 ChdGetVersion(ChdImage* pImage);
|
||||
INT32 ChdGetHunkBytes(ChdImage* pImage);
|
||||
INT32 ChdGetFramesPerHunk(ChdImage* pImage);
|
||||
INT32 ChdGetSha1(ChdImage* pImage, UINT8* pSha1);
|
||||
|
||||
// Total logical sectors on the disc (lead-out LBA).
|
||||
INT32 ChdGetTotalFrames(ChdImage* pImage);
|
||||
|
||||
+755
-132
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,45 @@
|
||||
#ifndef 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);
|
||||
extern struct CDEmuDo cdimgDo;
|
||||
|
||||
|
||||
Reference in new issue
Block a user