From e1a4d998525938784faf320de2191d47b86c5cbe Mon Sep 17 00:00:00 2001
From: taoenwen <67533945+taoenwen@users.noreply.github.com>
Date: Wed, 12 Aug 2026 19:40:07 +0800
Subject: [PATCH] =?UTF-8?q?Step=202:=20Globalize=20cdlist.cpp=20to=20repla?=
=?UTF-8?q?ce=20platform=E2=80=91specific=20neocdlist.cpp=20implementation?=
=?UTF-8?q?s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
makefile.burner_win32_rules | 2 +-
makefile.pi | 4 +-
makefile.sdl | 2 +-
makefile.sdl2 | 2 +-
projectfiles/qtcreator/fba_qt.pro | 28 +-
projectfiles/qtcreator/fba_sdl.pro | 28 +-
.../visualstudio-2015/fbneo_vs2015.vcxproj | 4 +-
.../fbneo_vs2015.vcxproj.filters | 10 +-
.../visualstudio-2019/fbneo_vs2019.vcxproj | 4 +-
.../fbneo_vs2019.vcxproj.filters | 10 +-
.../visualstudio-2022/fbneo_vs2022.vcxproj | 4 +-
.../fbneo_vs2022.vcxproj.filters | 10 +-
.../visualstudio-2026/fbneo_vs2026.vcxproj | 4 +-
.../fbneo_vs2026.vcxproj.filters | 10 +-
src/burner/cdlist.cpp | 590 ++++++
src/burner/cdlist.h | 56 +
src/burner/neocdlist.h | 145 +-
src/burner/pcecdlist_games.h | 1655 +++++++++++++++++
src/burner/qt/meson.build | 3 +-
src/burner/qt/neocdlist.cpp | 393 ----
src/burner/sdl/meson.build | 2 +-
src/burner/sdl/neocdlist.cpp | 409 ----
src/burner/win32/burner_win32.h | 3 -
src/burner/win32/meson.build | 3 +-
src/burner/win32/neocdlist.cpp | 680 -------
src/burner/win32/neocdsel.cpp | 507 +----
src/burner/win32/scrn.cpp | 18 +
src/intf/cd/cd_chd.cpp | 48 +-
src/intf/cd/cd_chd.h | 45 +-
src/intf/cd/cd_img.cpp | 887 +++++++--
src/intf/cd/cd_img.h | 39 +
31 files changed, 3332 insertions(+), 2273 deletions(-)
create mode 100644 src/burner/cdlist.cpp
create mode 100644 src/burner/cdlist.h
create mode 100644 src/burner/pcecdlist_games.h
delete mode 100644 src/burner/qt/neocdlist.cpp
delete mode 100644 src/burner/sdl/neocdlist.cpp
delete mode 100644 src/burner/win32/neocdlist.cpp
diff --git a/makefile.burner_win32_rules b/makefile.burner_win32_rules
index e2b53df3e..9d8ad934a 100644
--- a/makefile.burner_win32_rules
+++ b/makefile.burner_win32_rules
@@ -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 \
\
diff --git a/makefile.pi b/makefile.pi
index 1680336f6..257e48054 100755
--- a/makefile.pi
+++ b/makefile.pi
@@ -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
diff --git a/makefile.sdl b/makefile.sdl
index 4d33e76e7..3038ce2ea 100644
--- a/makefile.sdl
+++ b/makefile.sdl
@@ -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 \
\
diff --git a/makefile.sdl2 b/makefile.sdl2
index 0e9b6750c..1c32039a8 100644
--- a/makefile.sdl2
+++ b/makefile.sdl2
@@ -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 \
\
diff --git a/projectfiles/qtcreator/fba_qt.pro b/projectfiles/qtcreator/fba_qt.pro
index c49de967f..b1e817f5a 100644
--- a/projectfiles/qtcreator/fba_qt.pro
+++ b/projectfiles/qtcreator/fba_qt.pro
@@ -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 \
diff --git a/projectfiles/qtcreator/fba_sdl.pro b/projectfiles/qtcreator/fba_sdl.pro
index fd34e8a4a..aaad627d1 100644
--- a/projectfiles/qtcreator/fba_sdl.pro
+++ b/projectfiles/qtcreator/fba_sdl.pro
@@ -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 \
diff --git a/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj b/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj
index aa829a827..d6012c480 100644
--- a/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj
+++ b/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj
@@ -34,6 +34,7 @@
+
@@ -66,7 +67,7 @@
-
+
@@ -75,7 +76,6 @@
-
diff --git a/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj.filters b/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj.filters
index 677d44846..35fe8f2bd 100644
--- a/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj.filters
+++ b/projectfiles/visualstudio-2015/fbneo_vs2015.vcxproj.filters
@@ -1465,8 +1465,8 @@
burner\win32
-
- burner\win32
+
+ burner
burner\win32
@@ -3388,6 +3388,9 @@
burner
+
+ burner\win32
+
burner\win32
@@ -3568,9 +3571,6 @@
burn\drv\pre90s
-
- burner\win32
-
burn\drv\taito
diff --git a/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj b/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj
index a3273d0eb..1c42008e5 100644
--- a/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj
+++ b/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj
@@ -34,6 +34,7 @@
+
@@ -66,7 +67,7 @@
-
+
@@ -75,7 +76,6 @@
-
diff --git a/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj.filters b/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj.filters
index 6dd0480ff..41e0ce6d3 100644
--- a/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj.filters
+++ b/projectfiles/visualstudio-2019/fbneo_vs2019.vcxproj.filters
@@ -1465,8 +1465,8 @@
burner\win32
-
- burner\win32
+
+ burner
burner\win32
@@ -3388,6 +3388,9 @@
burner
+
+ burner\win32
+
burner\win32
@@ -3568,9 +3571,6 @@
burn\drv\pre90s
-
- burner\win32
-
burn\drv\taito
diff --git a/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj b/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj
index 0b4d45d05..4aa984fda 100644
--- a/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj
+++ b/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj
@@ -34,6 +34,7 @@
+
@@ -66,7 +67,7 @@
-
+
@@ -75,7 +76,6 @@
-
diff --git a/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj.filters b/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj.filters
index 0e7fc7c9f..33f7dfd26 100644
--- a/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj.filters
+++ b/projectfiles/visualstudio-2022/fbneo_vs2022.vcxproj.filters
@@ -1465,8 +1465,8 @@
burner\win32
-
- burner\win32
+
+ burner
burner\win32
@@ -3388,6 +3388,9 @@
burner
+
+ burner\win32
+
burner\win32
@@ -3568,9 +3571,6 @@
burn\drv\pre90s
-
- burner\win32
-
burn\drv\taito
diff --git a/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj b/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj
index e19b34f62..5f85c89b0 100644
--- a/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj
+++ b/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj
@@ -1036,6 +1036,7 @@
+
@@ -1069,7 +1070,7 @@
-
+
@@ -1078,7 +1079,6 @@
-
diff --git a/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj.filters b/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj.filters
index f880f4c9b..f20867af1 100644
--- a/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj.filters
+++ b/projectfiles/visualstudio-2026/fbneo_vs2026.vcxproj.filters
@@ -3007,6 +3007,9 @@
burner
+
+ burner\win32
+
burner
@@ -3106,8 +3109,8 @@
burner\win32
-
- burner\win32
+
+ burner
burner\win32
@@ -3133,9 +3136,6 @@
burner\win32
-
- burner\win32
-
burner\win32
diff --git a/src/burner/cdlist.cpp b/src/burner/cdlist.cpp
new file mode 100644
index 000000000..028d31a79
--- /dev/null
+++ b/src/burner/cdlist.cpp
@@ -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
diff --git a/src/burner/cdlist.h b/src/burner/cdlist.h
new file mode 100644
index 000000000..eec250792
--- /dev/null
+++ b/src/burner/cdlist.h
@@ -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
diff --git a/src/burner/neocdlist.h b/src/burner/neocdlist.h
index efcb8d924..84dadb21a 100644
--- a/src/burner/neocdlist.h
+++ b/src/burner/neocdlist.h
@@ -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
diff --git a/src/burner/pcecdlist_games.h b/src/burner/pcecdlist_games.h
new file mode 100644
index 000000000..2304a8c29
--- /dev/null
+++ b/src/burner/pcecdlist_games.h
@@ -0,0 +1,1655 @@
+// Generated by tools/cdlist/generate_pce_cd_db.py; do not edit.
+// Source: https://raw.githubusercontent.com/mamedev/mame/ab41620cf2d4bace0497922b03cb48e1d5169b50/hash/pcecd.xml
+// MAME: ab41620cf2d4bace0497922b03cb48e1d5169b50 (2026-08-12); input SHA1: 2da275959c6ca57c74e7c3f633bfd0267cda5687; license: CC0-1.0.
+
+#ifndef FBNEO_PCECD_GAMES_H
+#define FBNEO_PCECD_GAMES_H
+
+enum { PCECD_SUPPORTED = 0, PCECD_PARTIAL = 1, PCECD_UNSUPPORTED = 2, PCECD_BADDUMP = 4 };
+
+struct PceCdGame {
+ UINT8 sha1[20];
+ UINT32 shortname, description, year, publisher, region, cloneof, requirement;
+ UINT8 flags;
+};
+
+static const char pceCdGameStringData[22328] =
+ "\0"
+ "1552 Tenka Tairan (Japan)\0"
+ "1552tenk\0"
+ "1988\0"
+ "1989\0"
+ "1990\0"
+ "1991\0"
+ "1991?\0"
+ "1992\0"
+ "1993\0"
+ "1994\0"
+ "1995\0"
+ "1996\0"
+ "1997\0"
+ "1999\0"
+ "199?\0"
+ "19??\0"
+ "2002\0"
+ "2004\0"
+ "2009\0"
+ "2011\0"
+ "2012\0"
+ "2013\0"
+ "2014\0"
+ "2016\0"
+ "2018\0"
+ "2021\0"
+ "3 in 1 DUO Demo CD (USA)\0"
+ "3in1\0"
+ "3x3 Eyes - Sanjiyan Hensei (ACD, SCD)(Japan)\0"
+ "3x3eyes\0"
+ "4 in 1 Super CD (USA)\0"
+ "4in1\0"
+ "\0"
+ "A. III (Japan)\0"
+ "ASK Kodansha\0"
+ "AV Tanjou (GECD)(Japan)\0"
+ "Accolade\0"
+ "Advanced Variable Geo (Japan)\0"
+ "Adventure Quiz - Capcom World Hatena no Daibouken (Japan)\0"
+ "Aetherbyte Studios\0"
+ "Ai Chou Aniki (Japan)\0"
+ "Akumajou Dracula X - Chi no Rondo (Japan)\0"
+ "Alnam no Kiba - Juuzoku Juuni Shinto Densetsu (Japan)\0"
+ "Alshark (Japan)\0"
+ "Ane-San (Japan)\0"
+ "Angelus 2 - Holy Night (Japan, prototype)\0"
+ "Aoki Ookami to Shiroki Mejika - Genchou Hishi (Japan)\0"
+ "Artdink\0"
+ "Asia Soft Lab\0"
+ "Asuka 120% Maxima Burning Fest (Japan)\0"
+ "Atlus\0"
+ "Aurora Quest - Otaku no Seiza (Japan)\0"
+ "Avenger (Japan)\0"
+ "Babel (Japan)\0"
+ "Baby Jo (Japan)\0"
+ "Bakuden Unbalance Zone (Japan)\0"
+ "Bakuretsu Hunter (Japan)\0"
+ "Bakushou Yoshimoto no Shinkigeki (Japan)\0"
+ "Bandai\0"
+ "Banpresto\0"
+ "Basted (Japan)\0"
+ "Bazaru Degozaru no Game Degozaru (Japan)\0"
+ "Beyond Shadowgate (USA)\0"
+ "Bikini Girls (USA)\0"
+ "Bikkuriman Daijikai (Japan)\0"
+ "Bishoujo Janshi Idol Pai (GECD)(Japan)\0"
+ "Bishoujo Senshi Sailor Moon (Japan)\0"
+ "Bishoujo Senshi Sailor Moon Collection (Japan)\0"
+ "Black Hole Assault (Japan)\0"
+ "Blood Gear (Japan)\0"
+ "Bold Game Studio\0"
+ "Bomberman '94 Taikenban (Japan)\0"
+ "Bomberman - Panic Bomber (Japan)\0"
+ "Bonanza Bros. (Japan)\0"
+ "Bonk III - Bonk's Big Adventure (USA)\0"
+ "Brain Gray\0"
+ "Brandish (ACD, SCD)(Japan)\0"
+ "Browning (Japan)\0"
+ "Br\303\270derbund\0"
+ "Builderland (Japan)\0"
+ "Burai - Hachigyoku no Yuushi Densetsu (Japan)\0"
+ "Burai II - Yami Koutei no Gyakushuu (Japan)\0"
+ "Buster Bros. (USA)\0"
+ "CD Battle Hikari no Yuushatachi (Japan)\0"
+ "CD Bishoujo Pachinko Kyuuma Yon Shimai (Japan)\0"
+ "CD Denjin Rockabilly Tengoku (Japan)\0"
+ "CD Hanafuda Bishoujo Fan Club (GECD)(Japan)\0"
+ "CD Mahjong Bishoujo Chuushinha (GECD)(Japan)\0"
+ "CD Pachisuro Bishoujo Gambler (GECD)(Japan)\0"
+ "Cal II (Japan)\0"
+ "Cal III (Japan)\0"
+ "Camp California (USA)\0"
+ "Capcom\0"
+ "Cardangels (Japan)\0"
+ "Championship Rally (Japan)\0"
+ "Chiki Chiki Boys (Japan)\0"
+ "Chou Aniki (Japan)\0"
+ "Chou Eiyuu Densetsu - Dynastic Hero (Japan)\0"
+ "Choujikuu Yousai Macross 2036 (CD, SCD)(Japan)\0"
+ "Choujikuu Yousai Macross Eien no Love Song (Japan)\0"
+ "Cinemaware\0"
+ "Cobra - Kokuryuuou no Densetsu (Japan)\0"
+ "Cobra II - Densetsu no Otoko (Japan)\0"
+ "Coconuts Japan\0"
+ "Color Wars (Japan)\0"
+ "Cosmic Fantasy - Bouken Shounen Yuu (Japan)\0"
+ "Cosmic Fantasy II (USA)\0"
+ "Cosmic Fantasy II - Bouken Shounen Ban (Japan)\0"
+ "Cosmic Fantasy III - Bouken Shounen Rei (Japan)\0"
+ "Cosmic Fantasy IV - Ginga Shounen Densetsu Gekitou Hen (Japan)\0"
+ "Cosmic Fantasy IV - Ginga Shounen Densetsu Totsunyuu Hen (Japan)\0"
+ "Cotton - Fantastic Night Dreams (Japan)\0"
+ "Cotton - Fantastic Night Dreams (USA)\0"
+ "Crazy Hospital - Fushigi no Kuni no Tenshi (Japan)\0"
+ "Crest of Wolf (Japan)\0"
+ "Cyber City OEDO 808 (Japan)\0"
+ "Daisenpuu Custom (Japan)\0"
+ "Daisenryaku II - Campaign Version (Japan)\0"
+ "Data West\0"
+ "Dead of the Brain I II (Japan)\0"
+ "Death Bringer - The Knight of Darkness (Japan)\0"
+ "Deden no Den (Japan)\0"
+ "Dekoboko Densetsu - Hashire Wagamanma (Japan)\0"
+ "Dengeki\0"
+ "Dennou Tenshi - Digital Angel (Japan)\0"
+ "Develo Magazine Volume I (Japan)\0"
+ "Develo Starter Kit - Assembler (Japan)\0"
+ "Develo Starter Kit - Basic (Japan)\0"
+ "De\302\267Ja (Japan)\0"
+ "Doraemon Nobita no Dorabian Night (Japan)\0"
+ "Double Dragon II - The Revenge (Japan)\0"
+ "Doukyuusei (Japan)\0"
+ "Download II (Japan)\0"
+ "Downtown Nekketsu Monogatari (Japan)\0"
+ "Dragon Ball Z - Idainaru Son Gokuu Densetsu (Japan)\0"
+ "Dragon Half (Japan)\0"
+ "Dragon Knight & Grafitti (Japan)\0"
+ "Dragon Knight II (Japan)\0"
+ "Dragon Knight III (Japan)\0"
+ "Dragon Slayer - Eiyuu Densetsu (Japan)\0"
+ "Dragon Slayer - Eiyuu Densetsu II (Japan)\0"
+ "Dragon Slayer - The Legend of Heroes (USA)\0"
+ "Dungeon Explorer II (Japan)\0"
+ "Dungeon Explorer II (USA)\0"
+ "Dungeon Master - Theron's Quest (Japan)\0"
+ "Dungeon Master - Theron's Quest (USA)\0"
+ "Efera & Jiliora - The Emblem from Darkness (Japan)\0"
+ "Eikan ha Kimini - Koukou Yakyuu Zenkoku Taikai (ACD, SCD)(Japan)\0"
+ "Eiyuu Sangokushi (Japan)\0"
+ "Electronic Arts\0"
+ "Emerald Dragon (Japan)\0"
+ "Emerald Dragon Taikenban (Japan)\0"
+ "Excite Software\0"
+ "Exile (USA)\0"
+ "Exile - Toki no Hasama he (Japan)\0"
+ "Exile II - Janen no Jishou (Japan)\0"
+ "Exile II - Wicked Phenomenon (USA)\0"
+ "F1 Circus Special - Pole to Win (Japan)\0"
+ "F1 Team Simulation Project F (Japan)\0"
+ "FTL Games\0"
+ "FX Unit Yuki: The Henshin Engine (re-release)\0"
+ "Faceball (Japan)\0"
+ "Faceball Taikenban (Japan)\0"
+ "Faerie Dust Story - Meikyuu no Elfeene (Japan)\0"
+ "Falcom\0"
+ "Fantasy Star Soldier (USA, prototype)\0"
+ "Farjius no Jakoutei - Neo Metal Fantasy (Japan)\0"
+ "Fausset\303\251 Amour (Japan)\0"
+ "Fiend Hunter (Japan)\0"
+ "Fighting Street (Japan)\0"
+ "Fighting Street (USA)\0"
+ "Final Zone II (Japan)\0"
+ "Final Zone II (USA)\0"
+ "Flash Hiders (Japan)\0"
+ "Flash Hiders Taikenban (Japan)\0"
+ "Forgotten Worlds (Japan)\0"
+ "Forgotten Worlds (USA)\0"
+ "Formation Soccer '95 - Della Serie A (ACD, SCD)(Japan)\0"
+ "Fray CD Xak Gaiden (Japan)\0"
+ "Frozen Utopia\0"
+ "Fujicom\0"
+ "Fushigi no Umi no Nadia (Japan)\0"
+ "GS Mikami (Japan)\0"
+ "Gain Ground SX (Japan)\0"
+ "Galaxy Deka Gayvan (Japan)\0"
+ "Gambler Jikochuushinha - Gekitou 36 Janshi (Japan)\0"
+ "Gambler Jikochuushinha - Mahjong Puzzle Collection (Japan)\0"
+ "Games Express\0"
+ "Garou Densetsu II - Aratanaru Tatakai (Japan)\0"
+ "Garou Densetsu II - Aratanaru Tatakai - Sample Disc (Japan)\0"
+ "Garou Densetsu Special (Japan)\0"
+ "Gate of Thunder (Japan)\0"
+ "Genocide (Japan)\0"
+ "Gensou Tairiku Auleria (Japan)\0"
+ "Ginga Fukei Densetsu Sapphire (Japan)\0"
+ "Ginga Ojousama Densetsu Yuna (Japan, HRH310827-3FAAT)\0"
+ "Ginga Ojousama Densetsu Yuna (Japan, HRH310827-3FAFT)\0"
+ "Ginga Ojousama Densetsu Yuna HuVideo CD (Japan)\0"
+ "Ginga Ojousama Densetsu Yuna II - Eternal Princess (Japan)\0"
+ "Go! Go! Birdie Chance (Japan)\0"
+ "God Panic - Shijou Saikyou Gundan (Japan)\0"
+ "Godzilla (USA)\0"
+ "Godzilla - Bakutou Retsuden (Japan)\0"
+ "Golden Axe (Japan)\0"
+ "Gradius II - Gofer no Yabou (Japan)\0"
+ "Gulclight TDF 2 (Japan)\0"
+ "G\303\266tzendiener (Japan)\0"
+ "Hatsukoi Monogatari (Japan)\0"
+ "Hawiian Island Girls (USA)\0"
+ "Hawk F-123 (Japan)\0"
+ "Hellfire S - The Another Story (Japan)\0"
+ "Henshin Engine (demo)\0"
+ "Hi-Leg Fantasy (GECD)(Japan)\0"
+ "High Grenadier (Japan)\0"
+ "Hihou Densetsu Chris no Bouken (Japan)\0"
+ "Himitsu no Hanazono (Japan)\0"
+ "Horror Story (Japan)\0"
+ "Hu PGA Tour Power Golf 2 - Golfer (Japan)\0"
+ "Hudson\0"
+ "Hudson Soft\0"
+ "Hudson Soft / Red\0"
+ "Human\0"
+ "Human Entertainment\0"
+ "Human Sports Festival (Japan)\0"
+ "Hyaku Monogatari - Hontou ni Atta Kowai Hanashi (Japan)\0"
+ "Hyper Dyne SideArms Special (Japan)\0"
+ "Hyper Wars (Japan)\0"
+ "Hypernova Blast (USA)\0"
+ "ICOM Simulations\0"
+ "IGS\0"
+ "IQ Panic (Japan)\0"
+ "Iga Ninden Gaou (Japan)\0"
+ "Image Fight II (Japan)\0"
+ "Implode (USA)\0"
+ "Inoue Mami - Kono Hoshi ni Tatta Hitori no Kimi (Japan)\0"
+ "Insanity\0"
+ "Intec\0"
+ "Inter State\0"
+ "Irem\0"
+ "It Came from the Desert (USA)\0"
+ "J Thunder (Japan)\0"
+ "J. B. Harold Murder Club (USA)\0"
+ "J. B. Harold Satsujin Club (Japan)\0"
+ "J. League Tremendous Soccer '94 (ACD, SCD)(Japan)\0"
+ "Jack Nicklaus Turbo Golf (USA)\0"
+ "Jack Nicklaus World Tour Golf (Japan)\0"
+ "Janshin Densetsu - Quest of Jongmaster (Japan)\0"
+ "Jantei Monogatari (Japan)\0"
+ "Jantei Monogatari II - Uchuu Tantei Divan Kanketsu Hen (Japan)\0"
+ "Jantei Monogatari II - Uchuu Tantei Divan Shutsudou Hen (Japan)\0"
+ "Jantei Monogatari III - Saver Angels (Japan)\0"
+ "Japan\0"
+ "Japan/World\0"
+ "Jessie Jaeger in Cleopatra's Curse\0"
+ "Jessie Jaeger in Cleopatra's Curse (demo)\0"
+ "Jim Power - In Mutant Planet (Japan)\0"
+ "John Madden Duo CD Football (USA)\0"
+ "Juuouki (Japan)\0"
+ "KO Seiki Beast - Gaia Fukkatsu Kanketsu Hen (Japan)\0"
+ "Kagami no Kuni no Legend (Japan)\0"
+ "Kaizou Choujin Shubibinman III - Ikai no Princess (Japan)\0"
+ "Kakutou Haou Densetsu Algunos (Japan)\0"
+ "Kawa no Nushi Tsuri - Shizenha (Japan)\0"
+ "Kaze Kiri - Ninja Action (Japan)\0"
+ "Kaze no Densetsu Xanadu (Japan)\0"
+ "Kaze no Densetsu Xanadu II (Japan)\0"
+ "Kiaidan 00 (Japan)\0"
+ "Kidou Keisatsu Patlabor - Griffon Hen (Japan)\0"
+ "King Records\0"
+ "Kisou Louga (Japan)\0"
+ "Kisou Louga II - The Ends of Shangrila (Japan)\0"
+ "Koei\0"
+ "Kogado Studio\0"
+ "Konami\0"
+ "Kuusou Kagaku Sekai Gulliver Boy (Japan)\0"
+ "L-Dis (Japan)\0"
+ "Lady Phantom (Japan)\0"
+ "Langrisser - Hikari no Matsuei (Japan)\0"
+ "Laplace no Ma (Japan)\0"
+ "Laplace no Ma - Preview Disk (Japan)\0"
+ "Laser Soft\0"
+ "Laser Soft Visual Collection Volume I - Cosmic Fantasy Visual Shuu (Japan)\0"
+ "Laser Soft Visual Collection Volume II - Valis Visual Shuu (Japan)\0"
+ "Last Alert (USA)\0"
+ "Last Armageddon (Japan, BRCD0001-6-0625-R1F)\0"
+ "Last Armageddon (Japan, BRCD0001-7-0904-R1D)\0"
+ "Legion (Japan)\0"
+ "Lemmings (Japan)\0"
+ "Linda\302\263 (ACD, SCD)(Japan)\0"
+ "Lodoss Tousenki - Record of Lodoss War (Japan)\0"
+ "Lodoss Tousenki II - Record of Lodoss War II (Japan)\0"
+ "Loom (Japan)\0"
+ "Loom (USA)\0"
+ "Lord of Wars (Japan)\0"
+ "Lords of Thunder (USA)\0"
+ "Lords of the Rising Sun (USA)\0"
+ "Lucas Arts\0"
+ "Mad Stalker - Full Metal Force (Japan)\0"
+ "Mad Stalker - Full Metal Force - Sample Disc (Japan)\0"
+ "Madou Monogatari I - Honou no Sotsuenji (Japan)\0"
+ "Magical Dinosaur Tour (USA)\0"
+ "Magical Fantasy Adventure - Popful Mail (ACD, SCD)(Japan)\0"
+ "Magical Saurus Tour (Japan)\0"
+ "Magicoal (Japan)\0"
+ "Mahjong Clinic Special (Japan)\0"
+ "Mahjong Lemon Angel (Japan)\0"
+ "Mahjong Sword - Princess Quest Gaiden (ACD, SCD)(Japan)\0"
+ "Mahjong Vanilla Syndrome (CD, SCD)(Japan)\0"
+ "Mahjong on the Beach (Japan)\0"
+ "Mahou no Shoujo Silky Lip (Japan, prototype Test Wo. Ver 3.1)\0"
+ "Mahou no Shoujo Silky Lip (Japan, prototype v5.0)\0"
+ "Mamono Hunter Youko - Makai kara no Tenkousei (Japan)\0"
+ "Mamono Hunter Youko - Tooki Yobigoe (Japan)\0"
+ "Martial Champion (Japan)\0"
+ "Mashou Denki La Valeur (Japan)\0"
+ "Master of Monsters (Japan)\0"
+ "Mateki Densetsu Astralius (Japan)\0"
+ "Maxis\0"
+ "Media Rings Corporation\0"
+ "Megami Paradise (Japan)\0"
+ "Metal Angel (Japan)\0"
+ "Metal Angel II (Japan)\0"
+ "Metamor Jupiter (Japan)\0"
+ "Meteor Blaster DX (USA)\0"
+ "Meteor Blaster DX (USA, re-release)\0"
+ "Micro Cabin\0"
+ "Micro World\0"
+ "Micronet\0"
+ "Might and Magic (Japan)\0"
+ "Might and Magic III - Isles of Terra (Japan)\0"
+ "Might and Magic III - Isles of Terra (USA)\0"
+ "MindRec\0"
+ "MindRec & VodSound\0"
+ "Mine Sweeper (Japan)\0"
+ "Mirai Shonen Conan (Japan)\0"
+ "Mitsubachi Gakuen (Japan)\0"
+ "Monster Lair (USA)\0"
+ "Monster Maker - Yami no Ryuukishi (Japan)\0"
+ "Moonlight Lady (Japan)\0"
+ "Motoroader MC (Japan)\0"
+ "Motteke Tamago (Japan)\0"
+ "Mugen Senshi Valis - Legend of a Fantasm Soldier (Japan)\0"
+ "Mysterious Song\0"
+ "Mysterious Song (re-release)\0"
+ "Mystic Formula (Japan)\0"
+ "NCS\0"
+ "NEC\0"
+ "NEC Avenue\0"
+ "NEC Home Electronics\0"
+ "NEC Interchannel\0"
+ "Naxat Soft\0"
+ "Nekketsu Koukou Dodgeball Bu - Soccer Hen (Japan)\0"
+ "Nekketsu Koushinkyoku - Soreyuke Daiundoukai (Japan)\0"
+ "Nekketsu Legend Baseballer (Japan)\0"
+ "Nemurenumori no Chiisana Ohanashi (Japan)\0"
+ "Neo Nectaris (Japan)\0"
+ "New World Computing\0"
+ "Nexzr (Japan)\0"
+ "Nichibutsu\0"
+ "Nicole Express\0"
+ "Nihon Falcom\0"
+ "Nihon Telenet\0"
+ "Nishimura Kyoutarou Mystery - Hokutosei no Onna (Japan)\0"
+ "No Ri Ko (Japan)\0"
+ "Nobunaga no Yabou - Bushou Fuuunroku (Japan)\0"
+ "Nobunaga no Yabou - Zenkokuban (Japan)\0"
+ "Orion / Arm / Gregg\0"
+ "PCEngine Fan Special CD-ROM Volume I (Japan)\0"
+ "PCEngine Hyper Catalog (CD-ROM Capsule) (Japan)\0"
+ "PCEngine Hyper Catalog Duo-RX - Disc A (Japan)\0"
+ "PCEngine Hyper Catalog Duo-RX - Disc B (Japan)\0"
+ "PCEngine Hyper Catalog II (Japan)\0"
+ "PCEngine Hyper Catalog III (Japan)\0"
+ "PCEngine Hyper Catalog IV (Japan)\0"
+ "PCEngine Hyper Catalog V (Japan)\0"
+ "PCEngine Hyper Catalog VI - Disc A (Japan)\0"
+ "PCEngine Hyper Catalog VI - Disc B (Japan)\0"
+ "Pachio-kun - Maboroshi no Densetsu (Japan)\0"
+ "Pachio-kun - Warau Uchuu (Japan)\0"
+ "Pachio-kun III - Pachisuro Pachinko (Japan)\0"
+ "Pack-In-Video\0"
+ "Paradion - Auto Crusher Palladium (Japan)\0"
+ "Pastel Lime (Japan)\0"
+ "Pixel Heart\0"
+ "Police Connection (Japan)\0"
+ "Pomping World (Japan)\0"
+ "Pop'n Magic (Japan)\0"
+ "Populous - The Promised Lands (Japan)\0"
+ "Prince of Persia (Japan)\0"
+ "Prince of Persia (USA)\0"
+ "Princess Maker 1 (Japan)\0"
+ "Princess Maker 2 (ACD, SCD)(Japan)\0"
+ "Princess Minerva (Japan)\0"
+ "Private eye dol (ACD, SCD)(Japan)\0"
+ "Psychic Detective Series Vol. III - Aya (Japan)\0"
+ "Psychic Detective Series Vol. III - Aya - Auto Demo (Japan)\0"
+ "Psychic Detective Series Vol. IV - Orgel (Japan)\0"
+ "Psychic Storm (Japan)\0"
+ "Psygnosis\0"
+ "Puyo Puyo CD (Japan)\0"
+ "Puyo Puyo CD Tsuu (Japan)\0"
+ "Pyramid Plunder\0"
+ "Quiz Avenue (Japan)\0"
+ "Quiz Avenue II (Japan)\0"
+ "Quiz Avenue III (Japan)\0"
+ "Quiz Caravan Cult Q (Japan)\0"
+ "Quiz Marugoto The World II - Time Machine ni Onegai! (Japan)\0"
+ "Quiz Marugoto the World (Japan)\0"
+ "Quiz Tonosama no Yabou (Japan)\0"
+ "Quiz de Gakuensai (Japan)\0"
+ "Quiz no Hoshi (Japan)\0"
+ "R-Type Complete CD (Japan)\0"
+ "Rainbow Islands (Japan)\0"
+ "Ranma \302\275 (Japan)\0"
+ "Ranma \302\275 - Datou, Ganso Musabetsu Kakutou-Ryuu! (CD, SCD)(Japan)\0"
+ "Ranma \302\275 - Toraware no Hanayome (Japan)\0"
+ "Ray Force\0"
+ "Rayxanber II (Japan)\0"
+ "Rayxanber III (Japan)\0"
+ "Red Alert (Japan)\0"
+ "Renny Blaster (Japan)\0"
+ "Revival Chase\0"
+ "Revival Games\0"
+ "Right Stuff\0"
+ "Riot Zone (USA)\0"
+ "Rising Sun (Japan)\0"
+ "Riverhill Soft\0"
+ "Riverhill Software\0"
+ "Road Spirits (Japan)\0"
+ "Rom Rom Stadium (Japan)\0"
+ "Rom\302\262 Karaoke - Volume I (Japan)\0"
+ "Rom\302\262 Karaoke - Volume I - Suteki ni Standard (Japan)\0"
+ "Rom\302\262 Karaoke - Volume II (Japan)\0"
+ "Rom\302\262 Karaoke - Volume II - Nattoku Idol (Japan)\0"
+ "Rom\302\262 Karaoke - Volume III (Japan)\0"
+ "Rom\302\262 Karaoke - Volume III - Yappashi Band (Japan)\0"
+ "Rom\302\262 Karaoke - Volume IV (Japan)\0"
+ "Rom\302\262 Karaoke - Volume IV - Choito Otona! (Japan)\0"
+ "Rom\302\262 Karaoke - Volume V (Japan)\0"
+ "Rom\302\262 Karaoke - Volume V - Maku no Uchi (Japan)\0"
+ "Ruin - Kami no Isan (Japan)\0"
+ "Ryuuko no Ken (Japan)\0"
+ "Ryuuko no Ken - Sample Disc (Japan)\0"
+ "Sangokushi Eiketsu - Tenka ni Nozomu (Japan)\0"
+ "Sangokushi III (Japan)\0"
+ "Seirei Senshi Spriggan (Japan)\0"
+ "Seiryuu Densetsu Monbit (Japan)\0"
+ "Seisenshi Denshou - Jantaku no Kishi (Japan)\0"
+ "Seiya Monogatari - Anearth Fantasy Stories (Japan)\0"
+ "Seiya Monogatari - Anearth Fantasy Stories (Japan, debug prototype)\0"
+ "Seiya Monogatari - Anearth Fantasy Stories Taikenban (Japan)\0"
+ "Sengoku Kantou Sangokushi (Japan)\0"
+ "Seta\0"
+ "Sexy Idol Mahjong (Japan)\0"
+ "Sexy Idol Mahjong - Fashion Monogatari (ACD, SCD)(Japan)\0"
+ "Sexy Idol Mahjong - Yakyuuken no Uta (Japan)\0"
+ "Shadow of the Beast (USA)\0"
+ "Shadow of the Beast - Majou no Okite (Japan)\0"
+ "Shanghai II (Japan)\0"
+ "Shanghai III - Dragon's Eye (Japan)\0"
+ "Shape Shifter (USA)\0"
+ "Shapeshifter - Makai Eiyuu Den (Japan)\0"
+ "Sherlock Holmes Consulting Detective (USA)\0"
+ "Sherlock Holmes Consulting Detective Volume II (CD, SCD)(USA)\0"
+ "Sherlock Holmes no Tantei Kouza (Japan)\0"
+ "Sherlock Holmes no Tantei Kouza II (Japan)\0"
+ "Shiawase Usagi - Nureta Bishoujo Ichi Hajimete na no ni (Japan)\0"
+ "Shiawase Usagi II - Toraware Usagi Sailor Z (Japan)\0"
+ "Shin Megami Tensei (Japan)\0"
+ "Shin Nihon Pro Wrestling Kounin - '94 Battlefield in Tokyo Dome (Japan)\0"
+ "Shin Onryou Senki (Japan)\0"
+ "Shin Sangokushi - Tenka ha Ware ni (Japan)\0"
+ "Shinsetsu Shiawase Usagi (Japan)\0"
+ "Shinsetsu Shiawase Usagi 2 - Kairaku e no Invitation (Japan)\0"
+ "Shinsetsu Shiawase Usagi f - Yuujou Yori mo Aiyoku (Japan)\0"
+ "Shogakukan\0"
+ "Shougi Database Kiyuu (Japan)\0"
+ "Sim Earth - The Living Planet (Japan)\0"
+ "Sim Earth - The Living Planet (USA)\0"
+ "Sleuth Publications\0"
+ "Slime World (Japan)\0"
+ "Slot Shoubushi (Japan)\0"
+ "Snatcher (Japan)\0"
+ "Snatcher - Pilot Disk (Japan)\0"
+ "Sofix\0"
+ "Sol Bianca (Japan)\0"
+ "Sol Moonarge (Japan)\0"
+ "Solid Force (Japan)\0"
+ "Sony Music Entertainment\0"
+ "Sorcerian (Japan)\0"
+ "Sotsugyou - Graduation (Japan)\0"
+ "Sotsugyou II - Neo Generation (ACD, SCD)(Japan)\0"
+ "Sotsugyou Shashin - Miki (Japan)\0"
+ "Space Ava 201: Quantum Field Theory\0"
+ "Space Fantasy Zone (CD, SCD)(Japan, prototype)\0"
+ "Space Invaders - The Original Game (Japan)\0"
+ "Splash Lake (Japan)\0"
+ "Splash Lake (USA)\0"
+ "Spriggan Mark II - Re Terraform Project (Japan)\0"
+ "Star Breaker (Japan)\0"
+ "Star Mobile (Japan)\0"
+ "Star Parodia (Japan)\0"
+ "Startling Odyssey (Japan)\0"
+ "Startling Odyssey II - Makyou Sensou (Japan)\0"
+ "Steam Heart's (Japan)\0"
+ "Strider Hiryuu (Japan)\0"
+ "Success\0"
+ "Sugoroku '92 Nari Tore Nariagari Trendy (Japan)\0"
+ "Summer Carnival '92 - Alzadick (Japan)\0"
+ "Summer Carnival '93 - Nexzr Special (Japan)\0"
+ "SunSoft\0"
+ "Sunsoft\0"
+ "Super Air Zonk (USA)\0"
+ "Super Albatross (Japan)\0"
+ "Super CD-ROM\302\262 Taiken Soft-shuu (Japan)\0"
+ "Super Daisenryaku (Japan)\0"
+ "Super Darius (Japan)\0"
+ "Super Darius II (Japan)\0"
+ "Super Mahjong Taikai (Japan)\0"
+ "Super Raiden (Japan)\0"
+ "Super Real Mahjong P II III Custom (ACD, SCD)(Japan)\0"
+ "Super Real Mahjong P IV Custom (Japan)\0"
+ "Super Real Mahjong P V Custom (ACD, SCD)(Japan)\0"
+ "Super Real Mahjong Special - Miki Kasumi Shoko no Omoide (Japan)\0"
+ "Super Schwartzschild (CD, SCD)(Japan)\0"
+ "Super Schwartzschild II (Japan)\0"
+ "Sword Master (Japan)\0"
+ "Syd Mead\0"
+ "Syd Mead's Terra Forming (CD, SCD)(USA)\0"
+ "Sylphia (Japan)\0"
+ "System Soft\0"
+ "TGL\0"
+ "Tadaima Yuusha Boshuuchuu (Japan)\0"
+ "Tadaima Yuusha Boshuuchuu - Sample Disc (Japan)\0"
+ "Taiheiki (Japan)\0"
+ "Taito\0"
+ "Tanjou Debut (ACD, SCD)(Japan)\0"
+ "Tecmo World Cup Super Soccer (Japan)\0"
+ "Teichiku Records\0"
+ "Tekipaki Working Love (Japan)\0"
+ "Telenet Japan\0"
+ "Tenchi Muyou! Ryououki (Japan)\0"
+ "Tenchi wo Kurau (Japan)\0"
+ "Tengai Makyou - Fuu'un Kabuki Den Shutsugeki no Sho (Japan)\0"
+ "Tengai Makyou - Kabuki Ittou Ryoudan (Japan)\0"
+ "Tengai Makyou - Ziria (Japan)\0"
+ "Tengai Makyou - Ziria Hibaihin (Japan)\0"
+ "Tengai Makyou II - Manji Maru (Japan)\0"
+ "Tenshi no Uta (Japan)\0"
+ "Tenshi no Uta II - Datenshi no Uta (Japan)\0"
+ "Terraforming (CD, SCD)(Japan)\0"
+ "The Addams Family (USA)\0"
+ "The Atlas - Renaissance Voyager (ACD, SCD)(Japan)\0"
+ "The Davis Cup Tennis (Japan)\0"
+ "The Dynastic Hero (USA)\0"
+ "The Kick Boxing (Japan)\0"
+ "The Local Girls of Hawaii (USA)\0"
+ "The Manhole (Japan)\0"
+ "The Pro Yakyuu (Japan)\0"
+ "The Pro Yakyuu Super '94 (Japan)\0"
+ "The Pro Yakyuu Super (Japan)\0"
+ "The Sarumaru Company\0"
+ "The TV Show (Japan)\0"
+ "Toho\0"
+ "Tokimeki Memorial (Japan, HRKM70414-1FAAT)\0"
+ "Tokimeki Memorial (Japan, HRKM70701-2FAAT)\0"
+ "Tokimeki Memorial (Japan, HRKM71014-3FAAT)\0"
+ "Tokuma Shoten\0"
+ "Tonkin House\0"
+ "Top wo Nerae! GunBuster Volume I (Japan)\0"
+ "Top wo Nerae! GunBuster Volume II (Japan)\0"
+ "Travel Epuru (Japan)\0"
+ "Travelers! Densetsu wo Buttobase (Japan)\0"
+ "USA\0"
+ "Uchuu Senkan Yamato (Japan)\0"
+ "Ultimate Rally Club\0"
+ "Ultrabox II Gou (Japan)\0"
+ "Ultrabox III Gou (Japan)\0"
+ "Ultrabox IV Gou (Japan)\0"
+ "Ultrabox Sohkan Gou (Japan)\0"
+ "Ultrabox V Gou (Japan)\0"
+ "Ultrabox VI Gou (Japan)\0"
+ "Urusei Yatsura - Stay With You (Japan)\0"
+ "Valis II (USA)\0"
+ "Valis II - The Fantasm Soldier (Japan)\0"
+ "Valis III (USA)\0"
+ "Valis III - The Fantasm Soldier (Japan)\0"
+ "Valis IV - The Fantasm Soldier (Japan)\0"
+ "Vasteel (Japan)\0"
+ "Vasteel (USA)\0"
+ "Vasteel II (ACD, SCD)(Japan)\0"
+ "Victor Entertainment\0"
+ "Victor Musical Industries\0"
+ "Virgin Dream (Japan)\0"
+ "Westone\0"
+ "Where in the World is Carmen Sandiego? (Japan)\0"
+ "Winds of Thunder (Japan)\0"
+ "Wizardry I II (Japan)\0"
+ "Wizardry III IV (Japan)\0"
+ "Wizardry V - Heart of the Maelstrom (Japan)\0"
+ "Wonder Boy III - Monster Lair (Japan)\0"
+ "World\0"
+ "World Heroes II (Japan)\0"
+ "World Heroes II - Sample Disc (Japan)\0"
+ "Wrestling Angels - Double Impact (ACD, SCD)(Japan)\0"
+ "Wrestling Universe - Fire Pro Joshi - Dome Choujo Taisen - WOWOW vs. JWP (Japan)\0"
+ "Xak I & II (Japan)\0"
+ "Xak III - The Eternal Recurrence (Japan)\0"
+ "Yamamura Misa Suspense - Kinsenka Kyou Ezara Satsujin Jiken (Japan)\0"
+ "Yami no Ketsuzoku Harukanaru Kioku (Japan)\0"
+ "Yawara! (Japan)\0"
+ "Yawara! II (Japan)\0"
+ "Yazawa Science Office\0"
+ "Ys Book I II (Japan)\0"
+ "Ys Book I II (USA)\0"
+ "Ys III - Wanderers from Ys (Japan)\0"
+ "Ys III - Wanderers from Ys (USA)\0"
+ "Ys IV - The Dawn of Ys (Japan, HCD3051-4-1108-R1F)\0"
+ "Ys IV - The Dawn of Ys (Japan, HCD3051-5-1116-R1P)\0"
+ "Yu Yu Hakusho (Japan)\0"
+ "Zan - Kagerou no Toki (Japan)\0"
+ "Zero 4 Champ II (Japan)\0"
+ "Zero Wing (Japan)\0"
+ "addfam\0"
+ "advquiz\0"
+ "aichoan\0"
+ "aiii\0"
+ "algunos\0"
+ "alkiba\0"
+ "alshark\0"
+ "anesan\0"
+ "angels2\0"
+ "asuka120\0"
+ "atlas\0"
+ "auleria\0"
+ "auroraq\0"
+ "avenger\0"
+ "avgeo\0"
+ "avtanjo\0"
+ "babel\0"
+ "babyjo\0"
+ "bakuhunt\0"
+ "bakushou\0"
+ "bakuzone\0"
+ "basted\0"
+ "bazaru\0"
+ "bbros\0"
+ "beast\0"
+ "beastj\0"
+ "beyshadg\0"
+ "bikini\0"
+ "bikkurid\0"
+ "blackh\0"
+ "blodgear\0"
+ "bnzabros\0"
+ "bombmn94\0"
+ "bonk3\0"
+ "brandish\0"
+ "browning\0"
+ "buildlnd\0"
+ "burai\0"
+ "burai2\0"
+ "cal2\0"
+ "cal3\0"
+ "campcali\0"
+ "cardangl\0"
+ "carmnwld\0"
+ "cdbattle\0"
+ "cddenjin\0"
+ "cdsys\0"
+ "chiki\0"
+ "choaniki\0"
+ "chrally\0"
+ "chrisbkn\0"
+ "cobra\0"
+ "cobra2\0"
+ "colorwar\0"
+ "conan\0"
+ "cosmfn4g\0"
+ "cosmfn4t\0"
+ "cosmfnt\0"
+ "cosmfnt2\0"
+ "cosmfnt2j\0"
+ "cosmfnt3\0"
+ "cotton\0"
+ "cottonj\0"
+ "crazyhos\0"
+ "crestwlf\0"
+ "cyber808\0"
+ "daisenpu\0"
+ "daisenr2\0"
+ "daviscup\0"
+ "dbz\0"
+ "ddragon2\0"
+ "deathbrn\0"
+ "dedbrain\0"
+ "dedenden\0"
+ "deja\0"
+ "dekoboko\0"
+ "dennoten\0"
+ "devbasic\0"
+ "devmag1\0"
+ "devstart\0"
+ "dknight2\0"
+ "dknight3\0"
+ "dknightg\0"
+ "dmaster\0"
+ "dmasterj\0"
+ "dokyusei\0"
+ "doraemon\0"
+ "downld2\0"
+ "downtown\0"
+ "draculax\0"
+ "draghalf\0"
+ "dslayed2\0"
+ "dslayedj\0"
+ "dslaylh\0"
+ "dungexp2\0"
+ "dungexp2j\0"
+ "dynhero\0"
+ "dynheroj\0"
+ "eferajil\0"
+ "eikankim\0"
+ "eiyu3gok\0"
+ "elfeen\0"
+ "emeraldd\0"
+ "emeralddt\0"
+ "exile\0"
+ "exile2\0"
+ "exile2j\0"
+ "exilej\0"
+ "f1circus\0"
+ "f1team\0"
+ "faceball\0"
+ "faceballt\0"
+ "fanspc1\0"
+ "faussete\0"
+ "fiendhun\0"
+ "fireproj\0"
+ "flashhid\0"
+ "flashhidt\0"
+ "forgottn\0"
+ "forgottnj\0"
+ "fraycd\0"
+ "fsoccr95\0"
+ "fssoldr\0"
+ "fstreet\0"
+ "fstreetj\0"
+ "fzone2\0"
+ "fzone2j\0"
+ "galaxyde\0"
+ "gambler\0"
+ "gamblrpz\0"
+ "garou2\0"
+ "garou2s\0"
+ "garousp\0"
+ "gatethun\0"
+ "genchohi\0"
+ "genocide\0"
+ "gground\0"
+ "godpanic\0"
+ "godzilla\0"
+ "godzillaj\0"
+ "gogobird\0"
+ "goldnaxe\0"
+ "gotzendi\0"
+ "gradius2\0"
+ "gsmikami\0"
+ "gulcligh\0"
+ "gulliver\0"
+ "gunbust1\0"
+ "gunbust2\0"
+ "hanafuda\0"
+ "hatsukoi\0"
+ "hawaiiu\0"
+ "hawiian\0"
+ "hawkf123\0"
+ "hellfire\0"
+ "henshin\0"
+ "henshin_d\0"
+ "highgrnd\0"
+ "hilegfan\0"
+ "himitsu\0"
+ "holmes\0"
+ "holmes2\0"
+ "holmes2j\0"
+ "holmesj\0"
+ "horrorst\0"
+ "humanspt\0"
+ "hupga2\0"
+ "hyakumon\0"
+ "hypercap\0"
+ "hyperdyn\0"
+ "hypernov\0"
+ "hyperwar\0"
+ "hyprcat2\0"
+ "hyprcat3\0"
+ "hyprcat4\0"
+ "hyprcat5\0"
+ "hyprcata\0"
+ "hyprcatb\0"
+ "hyprct6a\0"
+ "hyprct6b\0"
+ "idolpai\0"
+ "iganin\0"
+ "imagef2\0"
+ "implode\0"
+ "inouemam\0"
+ "insanity\0"
+ "iqpanic\0"
+ "itcame\0"
+ "jantei\0"
+ "jantei2k\0"
+ "jantei2s\0"
+ "jantei3\0"
+ "jbharold\0"
+ "jbharoldj\0"
+ "jimpower\0"
+ "jjcleopa\0"
+ "jjcleopa_d\0"
+ "jleagt94\0"
+ "jongmstr\0"
+ "jthunder\0"
+ "juuouki\0"
+ "kagami\0"
+ "karao1ss\0"
+ "karao2ni\0"
+ "karao3yb\0"
+ "karao4co\0"
+ "karao5mu\0"
+ "karaoke1\0"
+ "karaoke2\0"
+ "karaoke3\0"
+ "karaoke4\0"
+ "karaoke5\0"
+ "kawanus\0"
+ "kazekiri\0"
+ "kiaidan\0"
+ "kickbox\0"
+ "kisoulo2\0"
+ "kisoulou\0"
+ "koseikib\0"
+ "ladyphan\0"
+ "langriss\0"
+ "laplace\0"
+ "laplacep\0"
+ "lastarmg\0"
+ "lastarmg2\0"
+ "lavaleur\0"
+ "ldis\0"
+ "legion\0"
+ "lemmings\0"
+ "linda3\0"
+ "lodoss\0"
+ "lodoss2\0"
+ "loom\0"
+ "loomj\0"
+ "lordrsun\0"
+ "lordthun\0"
+ "lordwars\0"
+ "lsoft1\0"
+ "lsoft2\0"
+ "lstalert\0"
+ "macr2036\0"
+ "macrosls\0"
+ "madden\0"
+ "madoum\0"
+ "madstlkr\0"
+ "madstlkrs\0"
+ "magdino\0"
+ "magicoal\0"
+ "magsaurs\0"
+ "mahjong\0"
+ "mamonoht\0"
+ "mamonohu\0"
+ "manhole\0"
+ "mastmons\0"
+ "matekida\0"
+ "megamipa\0"
+ "metalan2\0"
+ "metalang\0"
+ "metamorj\0"
+ "meteorbl\0"
+ "meteorbl_10\0"
+ "metlfant\0"
+ "mightmag\0"
+ "mightmg3\0"
+ "mightmg3j\0"
+ "mineswep\0"
+ "mitsubac\0"
+ "mjbeach\0"
+ "mjclinic\0"
+ "mjlemang\0"
+ "mjsword\0"
+ "mlair\0"
+ "mlairj\0"
+ "monbit\0"
+ "monstmkr\0"
+ "moonligh\0"
+ "motoroad\0"
+ "motteke\0"
+ "mtlchamp\0"
+ "mysticf\0"
+ "mystsong\0"
+ "mystsong_a\0"
+ "nadia\0"
+ "neklegbb\0"
+ "neksoccr\0"
+ "nemurenu\0"
+ "neonectr\0"
+ "nexzr\0"
+ "nicklaus\0"
+ "nicklausj\0"
+ "nkhokuon\0"
+ "nobubufu\0"
+ "nobuzenk\0"
+ "noriko\0"
+ "pachikn2\0"
+ "pachikn3\0"
+ "pachikun\0"
+ "pachinko\0"
+ "pachislt\0"
+ "panicbom\0"
+ "paradion\0"
+ "pastelli\0"
+ "patlabor\0"
+ "pce:acardpro\0"
+ "pce:gecd\0"
+ "policeco\0"
+ "pompingw\0"
+ "popful\0"
+ "popnmagi\0"
+ "populous\0"
+ "ppersia\0"
+ "ppersiaj\0"
+ "princesm\0"
+ "prinmak\0"
+ "prinmak2\0"
+ "priveyed\0"
+ "proyak94\0"
+ "proyaks\0"
+ "proyakyu\0"
+ "psycdet3\0"
+ "psycdet3d\0"
+ "psycdet4\0"
+ "psychics\0"
+ "puyopuy2\0"
+ "puyopuyo\0"
+ "pyrplund\0"
+ "quizaven\0"
+ "quizavn2\0"
+ "quizavn3\0"
+ "quizcara\0"
+ "quizgaku\0"
+ "quizmar2\0"
+ "quizmaru\0"
+ "quiznoho\0"
+ "quiztono\0"
+ "ranma\0"
+ "ranmadat\0"
+ "ranmator\0"
+ "rayxan2\0"
+ "rayxan3\0"
+ "rbisland\0"
+ "redalert\0"
+ "rennybla\0"
+ "revchase\0"
+ "riotzone\0"
+ "risingsn\0"
+ "roadspir\0"
+ "romstad\0"
+ "rtype\0"
+ "ruin\0"
+ "ryukoken\0"
+ "ryukokens\0"
+ "sailormc\0"
+ "sailormn\0"
+ "sangoku\0"
+ "sangoku3\0"
+ "sapphire\0"
+ "scdrpgs\0"
+ "scdsys\0"
+ "sdarius\0"
+ "sdarius2\0"
+ "seisensh\0"
+ "seiyamon\0"
+ "seiyamonp\0"
+ "seiyamont\0"
+ "sengokuk\0"
+ "sexyidof\0"
+ "sexyidol\0"
+ "sexyidoy\0"
+ "shangh2\0"
+ "shangh3\0"
+ "shapesh\0"
+ "shapeshj\0"
+ "shiawas2\0"
+ "shiawase\0"
+ "shinmt\0"
+ "shinonry\0"
+ "shinsang\0"
+ "shinset2\0"
+ "shinsetf\0"
+ "shinsets\0"
+ "shougidb\0"
+ "shubibi3\0"
+ "silkylip\0"
+ "silkylipo\0"
+ "simearth\0"
+ "simearthj\0"
+ "slimew\0"
+ "slotshou\0"
+ "snatcher\0"
+ "snatcherpd\0"
+ "solbianc\0"
+ "solidfrc\0"
+ "solmoona\0"
+ "sorcer\0"
+ "soreyukd\0"
+ "sotsugy2\0"
+ "sotsugym\0"
+ "sotsugyo\0"
+ "spaceava\0"
+ "spaceinv\0"
+ "spcfzone\0"
+ "splashl\0"
+ "splashlj\0"
+ "spriggan\0"
+ "spriggn2\0"
+ "sprowr94\0"
+ "sraiden\0"
+ "srmp23\0"
+ "srmp4\0"
+ "srmp5\0"
+ "srmspec\0"
+ "starbrkr\0"
+ "starmobi\0"
+ "starparo\0"
+ "startod2\0"
+ "startody\0"
+ "steamhea\0"
+ "strider\0"
+ "sugoroku\0"
+ "summer92\0"
+ "summer93\0"
+ "supdaisn\0"
+ "superair\0"
+ "superalb\0"
+ "supermjt\0"
+ "supersc2\0"
+ "supersch\0"
+ "swordmst\0"
+ "sylphia\0"
+ "tadaima\0"
+ "tadaimas\0"
+ "taiheiki\0"
+ "tanjodeb\0"
+ "tecmowc\0"
+ "tekiwork\0"
+ "tenchi\0"
+ "tenchiku\0"
+ "tengaim2\0"
+ "tengaima\0"
+ "tengaims\0"
+ "tengaimz\0"
+ "tengaimzh\0"
+ "tenshiu2\0"
+ "tenshiut\0"
+ "terrafor\0"
+ "terraforj\0"
+ "tokimeki\0"
+ "tokimekib\0"
+ "tokimekic\0"
+ "travelep\0"
+ "traveler\0"
+ "tvshow\0"
+ "ultrago2\0"
+ "ultrago3\0"
+ "ultrago4\0"
+ "ultrago5\0"
+ "ultrago6\0"
+ "ultrasgo\0"
+ "urclub\0"
+ "uruseiya\0"
+ "valis\0"
+ "valis2\0"
+ "valis2j\0"
+ "valis3\0"
+ "valis3j\0"
+ "valis4\0"
+ "vanilla\0"
+ "vasteel\0"
+ "vasteel2\0"
+ "vasteelj\0"
+ "virgindr\0"
+ "wh2\0"
+ "wh2s\0"
+ "windthun\0"
+ "wizard12\0"
+ "wizard34\0"
+ "wizardr5\0"
+ "wrestang\0"
+ "xak12\0"
+ "xak3\0"
+ "xanadu\0"
+ "xanadu2\0"
+ "yamamura\0"
+ "yamato\0"
+ "yamikets\0"
+ "yawara\0"
+ "yawara2\0"
+ "ys12\0"
+ "ys12j\0"
+ "ys3\0"
+ "ys3j\0"
+ "ys4\0"
+ "ys4a\0"
+ "yuna\0"
+ "yuna2\0"
+ "yunaa\0"
+ "yunahv\0"
+ "yuyu\0"
+ "zan\0"
+ "zero4c2\0"
+ "zerowing\0"
+;
+
+static const PceCdGame pceCdGames[504] = {
+ {{0x00,0x83,0xf1,0x5f,0x77,0x63,0x02,0x73,0xa3,0x97,0x78,0x3a,0xf0,0x34,0x40,0x74,0xc1,0x71,0x6f,0x35},18414,1877,67,6140,16652,0,21138,2},
+ {{0x00,0xae,0x7b,0xad,0xc2,0x41,0xf9,0x2a,0x7a,0x36,0x2f,0xd4,0xc7,0x51,0x95,0xf8,0x1d,0x58,0xbf,0xa7},18834,3471,62,5914,6805,0,21138,0},
+ {{0x00,0xe5,0x61,0x7b,0xb5,0x0d,0x9d,0x27,0xd1,0xef,0x5c,0x14,0xc6,0xfa,0x5f,0xc2,0xbe,0x57,0x9d,0x76},19462,5851,67,9652,6805,0,21138,0},
+ {{0x01,0x99,0x18,0xbf,0xa9,0xfb,0xb5,0x0e,0xc3,0x86,0x84,0x6f,0x42,0xa1,0x3d,0x94,0xa8,0x1d,0xc2,0xbb},22008,16828,62,17099,6805,0,18459,0},
+ {{0x02,0x72,0xc7,0xc9,0x46,0x45,0x1b,0xcc,0x51,0x36,0xaf,0x32,0xa0,0x91,0x10,0x44,0xb6,0xa8,0xc4,0x68},18150,563,72,17099,6805,0,21138,0},
+ {{0x02,0x74,0xac,0x68,0xec,0x08,0x2e,0xbd,0x34,0xab,0x66,0xcb,0x12,0xac,0x29,0xbd,0x94,0xce,0xbb,0xfc},20357,8450,67,9701,6805,0,21138,0},
+ {{0x03,0xa0,0xfd,0x68,0x59,0x53,0x5e,0x80,0xad,0x70,0xd4,0x94,0xef,0x9d,0x9f,0x1d,0xc3,0x22,0xad,0x59},19568,10270,102,13847,6805,0,21138,0},
+ {{0x04,0xb1,0x28,0x12,0xdb,0x56,0x50,0xe4,0x0b,0x05,0x6e,0x72,0x42,0x0a,0x6e,0xb2,0x11,0xe2,0x85,0xf0},19047,4483,67,11880,6805,0,21138,1},
+ {{0x05,0x06,0x4b,0x59,0x9c,0xcf,0xe5,0xe8,0x6f,0x3d,0x25,0xa4,0x6e,0xab,0xc0,0x12,0x26,0xc4,0x16,0xba},21741,15249,51,7457,6805,0,18459,0},
+ {{0x05,0x12,0xda,0x6b,0x6c,0xf4,0x77,0x3b,0xd8,0xfa,0xda,0x01,0xfe,0xe1,0xde,0x44,0x92,0xf3,0x70,0x9a},21853,15710,67,5914,6805,0,21138,0},
+ {{0x06,0x9b,0x40,0x2f,0xa1,0xd9,0xdb,0x6e,0xb0,0xc3,0x62,0x37,0x18,0x1f,0x4c,0xfc,0x2c,0xa5,0xf2,0xe2},21678,14739,62,9701,6805,0,18459,0},
+ {{0x06,0xa0,0x11,0x38,0x8f,0xf2,0xa2,0x43,0xc2,0xd2,0x2a,0x2c,0x92,0x02,0x28,0x16,0xac,0xb0,0x53,0x6b},19729,6823,152,1251,17375,0,21138,0},
+ {{0x07,0x64,0x08,0x52,0x4f,0xd1,0xb9,0xce,0xc8,0x67,0x14,0x41,0x88,0x65,0xbf,0xa9,0x54,0xdf,0x76,0x32},20167,8433,67,9663,6805,0,21138,0},
+ {{0x07,0xc8,0x85,0x0f,0xe1,0xef,0xa4,0x77,0x5a,0x5f,0x5f,0x9d,0x6b,0x81,0x1a,0x27,0x94,0x57,0x8c,0x09},20447,9621,67,9144,6805,0,21138,0},
+ {{0x08,0x58,0xc0,0xd7,0x92,0x05,0x3a,0x24,0xed,0x2d,0xf9,0xcc,0xf3,0x4c,0x6f,0xb1,0xfb,0xe9,0xe9,0xf2},19109,4419,41,1899,16652,0,18459,0},
+ {{0x08,0x5e,0xca,0xb0,0xe1,0x6b,0x7e,0x1f,0x74,0x84,0x3d,0x14,0xa4,0xf8,0xff,0xe3,0x6a,0x63,0x56,0x7d},20099,7805,46,15641,16652,0,18459,4},
+ {{0x08,0xdd,0x0f,0x25,0xd9,0x00,0xac,0xbb,0xbb,0xf3,0x37,0xbc,0x73,0x4c,0xb3,0xe3,0x96,0xa5,0xfc,0x48},20349,8607,67,9652,6805,0,21138,0},
+ {{0x09,0x87,0xaa,0xdb,0x3d,0xad,0x46,0x4d,0x8a,0xc1,0xbb,0x22,0x2b,0x9a,0xf6,0xb4,0xe7,0x68,0xb6,0x28},21236,13107,46,5914,6805,0,18459,0},
+ {{0x09,0xdb,0xf4,0xe7,0xea,0xae,0xe5,0x26,0x29,0x49,0x62,0x59,0x17,0xb7,0x3a,0xe1,0x12,0x47,0x8a,0x38},20009,7912,46,9986,6805,0,18459,0},
+ {{0x0a,0x21,0x90,0x0d,0xec,0xba,0x97,0x70,0xc9,0x66,0xdb,0x03,0x58,0xc1,0xb1,0x6d,0xe1,0x39,0xc7,0x22},19776,6971,41,9652,6805,0,18459,1},
+ {{0x0b,0x1e,0xac,0xf8,0x30,0xc2,0x2e,0x85,0x19,0xce,0x7c,0x8c,0x7c,0x82,0x1a,0x16,0x74,0x3e,0x44,0xed},18280,1570,67,1899,16652,0,18459,0},
+ {{0x0b,0xd2,0x12,0xfa,0xe9,0x0c,0xec,0x9a,0xa6,0x4a,0xe2,0x29,0x8d,0xa3,0x3d,0xbc,0x63,0xcf,0x2a,0xdc},18720,2997,82,16480,6805,0,21138,2},
+ {{0x0c,0x02,0x06,0x28,0x2e,0x52,0xce,0x25,0x31,0x9a,0xbf,0x2f,0x71,0xde,0xa6,0x1d,0x42,0xf1,0x36,0x6e},19437,13265,67,13962,16652,0,18459,2},
+ {{0x0c,0x82,0xe3,0x47,0x30,0x82,0xc4,0x5a,0xd7,0x50,0x0d,0xf2,0x7c,0xb7,0x5e,0x68,0xa9,0x97,0xa8,0xd7},18239,873,72,2951,6805,0,21138,0},
+ {{0x0c,0x8d,0x8c,0x95,0xb9,0x5c,0xc4,0xf3,0x6a,0xe7,0x1f,0x7b,0x68,0xe6,0x59,0x1c,0x22,0x55,0xc0,0xd7},21190,12808,77,5914,6805,21171,21138,0},
+ {{0x0e,0xbc,0x33,0x1c,0x4d,0x7d,0x96,0x3f,0x4a,0x65,0x53,0xe6,0xf2,0x02,0x0f,0xa5,0xa1,0x03,0x17,0x53},21844,15770,77,5914,6805,0,20657,0},
+ {{0x0e,0xdc,0x8e,0x94,0x81,0x44,0x63,0x5d,0x4b,0xb2,0xd1,0xa9,0xcf,0x07,0x75,0x54,0xed,0x53,0x73,0x34},21003,11830,77,9652,6805,0,21138,2},
+ {{0x0f,0x5c,0x54,0x0f,0x56,0xfb,0x16,0x4c,0x23,0x86,0x7a,0xcb,0xf1,0x36,0xc2,0x3a,0x39,0x34,0x78,0x76},22318,18089,62,9701,6805,0,18459,0},
+ {{0x0f,0x75,0x69,0xbe,0x19,0x83,0x77,0x74,0xa8,0xb4,0x9c,0x86,0x23,0x05,0x55,0xff,0xad,0x4c,0xd6,0x37},21871,15845,62,5914,6805,21862,21138,0},
+ {{0x0f,0xd9,0x6d,0x24,0xad,0xd0,0x88,0xd1,0xfe,0xa9,0x3e,0x60,0x0b,0xab,0x7d,0xe7,0x24,0xd2,0x14,0x79},21012,11852,132,11866,16652,0,21138,0},
+ {{0x10,0xcf,0xd9,0xc5,0x84,0x1d,0xa3,0xc5,0xbc,0xab,0x80,0x73,0xd2,0x98,0x2a,0x3f,0xe0,0xbf,0xde,0x9e},21965,16326,77,11880,6805,0,21138,0},
+ {{0x11,0x0a,0x81,0xe2,0xe4,0x2c,0x1f,0xba,0x95,0x64,0xc0,0xd6,0x84,0x41,0x8a,0xd9,0x50,0x41,0xb8,0xe0},22093,17056,67,5951,16652,0,18459,0},
+ {{0x11,0x8f,0x98,0x40,0x45,0x4a,0xf1,0x72,0x2d,0x79,0x04,0xd4,0xd2,0x4b,0xca,0x09,0x2f,0xfd,0x23,0x09},19404,5761,51,9986,6805,0,18459,0},
+ {{0x12,0x0d,0x77,0x53,0x93,0xaa,0x14,0x35,0xa0,0x39,0x42,0xab,0x55,0x07,0x82,0x7a,0x94,0xe4,0xae,0xc8},21339,13858,77,12903,6805,0,21138,0},
+ {{0x12,0x18,0x2e,0x87,0xa0,0x57,0xee,0x33,0x7a,0xe3,0xd9,0x55,0xf1,0x82,0xf2,0x4f,0x48,0x18,0x9d,0x1b},20748,10948,77,9663,6805,0,21138,0},
+ {{0x12,0xfd,0xad,0xc8,0x5f,0xc1,0x2e,0x2a,0x36,0x26,0x38,0xed,0xbd,0xd8,0x7f,0x19,0x29,0xe9,0xd5,0x8d},22263,17843,51,5914,6805,22259,18459,0},
+ {{0x13,0x05,0x80,0x6c,0x0a,0xda,0xa7,0x01,0xe1,0xbc,0x29,0x6b,0xe7,0x22,0x61,0x8b,0x59,0xfe,0x02,0x22},18648,3276,72,939,6805,0,21138,1},
+ {{0x13,0x8a,0x59,0x9e,0x7d,0xdf,0xef,0x31,0x25,0xcf,0xf7,0x42,0x39,0xd1,0x9c,0xa0,0x9e,0x70,0x3b,0x23},18711,3069,82,16480,6805,0,21138,2},
+ {{0x13,0xc0,0x23,0x48,0x0f,0xff,0xb9,0xba,0xc3,0xa8,0x82,0x34,0x3f,0xfd,0x61,0x27,0x6e,0xb5,0x5a,0xef},20085,7663,67,9986,6805,0,18459,0},
+ {{0x14,0x3f,0x84,0xc1,0x8d,0x43,0xad,0xd0,0xc7,0xb6,0x4a,0xa1,0xb6,0x08,0x7e,0xb1,0xf5,0x83,0x84,0xe1},21357,8698,72,9986,6805,0,21138,0},
+ {{0x14,0x5e,0x81,0x40,0x9c,0xec,0xba,0xff,0x6f,0x10,0x30,0xb9,0x9a,0x26,0x0d,0x6d,0xe4,0x10,0x77,0x42},20032,7970,62,5914,6805,0,18459,1},
+ {{0x14,0xc5,0xc2,0x94,0xc5,0xa3,0xfb,0xa2,0x20,0x92,0xa0,0x1e,0x5e,0xc4,0xc8,0x51,0x2f,0x45,0x83,0xce},19075,4535,62,9652,6805,19066,21138,0},
+ {{0x14,0xfb,0x3b,0x1e,0xd0,0x09,0xbc,0xbe,0x48,0x93,0x57,0x8f,0x22,0x4c,0xfd,0xb0,0xcf,0xc5,0x0b,0xc9},20679,10794,67,9986,6805,0,21138,0},
+ {{0x15,0xa0,0xc0,0x3e,0xce,0xeb,0x78,0x0a,0x73,0x44,0x8b,0x86,0x52,0xd0,0x62,0x2c,0xa0,0xc4,0xc1,0xc2},20481,9815,77,10706,6805,0,21138,0},
+ {{0x15,0xf8,0x2c,0x44,0xce,0xae,0xe8,0x16,0xa1,0x28,0x26,0xf6,0x80,0x94,0xe5,0xfd,0x4c,0x12,0x0d,0x10},20255,9017,67,10706,6805,0,21138,0},
+ {{0x16,0x2b,0xbd,0x4b,0x20,0x92,0xaa,0x9f,0x0d,0xac,0x4d,0xae,0x9e,0xdd,0x7d,0x38,0x6a,0x28,0x55,0x3a},19635,6239,62,5914,6805,0,21138,0},
+ {{0x17,0x90,0x83,0x78,0xb7,0x77,0x2f,0x9d,0x75,0x44,0xad,0x2b,0x97,0x56,0xfa,0x5f,0x16,0x51,0xc6,0x12},21162,12644,72,9947,6805,0,21138,0},
+ {{0x18,0x21,0xcc,0x3f,0xee,0xb3,0xf3,0x04,0xdb,0xd1,0x02,0x85,0x5b,0x4a,0xac,0x6f,0x17,0x41,0xad,0x78},20228,8929,51,6157,6805,0,18459,0},
+ {{0x18,0x70,0xec,0xb7,0xb2,0x0b,0xaa,0x51,0x12,0x75,0x80,0x92,0x17,0xfb,0x9f,0x29,0xdd,0x62,0x66,0x66},18728,3030,82,16480,6805,0,21138,2},
+ {{0x18,0xb3,0xf9,0xbf,0xd2,0x0c,0x93,0x47,0x29,0x29,0x39,0x73,0x5e,0x44,0xf1,0xb9,0x63,0xf9,0xeb,0xf5},19872,12346,46,9652,6805,0,18459,0},
+ {{0x1a,0x0d,0x1d,0xbe,0x9b,0x7f,0x56,0x5d,0xfd,0x5b,0xfb,0x09,0xcb,0xa0,0xf6,0xdc,0xad,0x54,0xb7,0xcc},19217,4737,62,9652,6805,0,21138,0},
+ {{0x1a,0x43,0xb2,0x68,0xc5,0x1f,0xa5,0xce,0xaa,0x1a,0x32,0x88,0x72,0xa7,0xa5,0xef,0x10,0x6d,0xf0,0xfe},18324,1205,67,9168,6805,0,21138,0},
+ {{0x1a,0x9e,0xdd,0xc5,0x32,0xb9,0x1b,0x68,0x60,0xb8,0x33,0x8c,0x63,0x71,0x75,0x7b,0x55,0x80,0x79,0xfb},18869,3556,67,5914,6805,18860,21138,0},
+ {{0x1a,0xdf,0xc8,0x31,0xb8,0x58,0xb6,0xe9,0x23,0x08,0x7e,0x92,0xaa,0x49,0x49,0x93,0x98,0x19,0x57,0x43},21554,14457,62,9701,6805,0,21138,0},
+ {{0x1b,0x0e,0xc3,0x1a,0x67,0xf0,0xce,0x25,0xdc,0x11,0x7d,0x8b,0x69,0x1d,0x3f,0x19,0xb8,0xc8,0xf6,0x83},20331,9316,62,10706,6805,0,18459,0},
+ {{0x1b,0x81,0x9a,0x66,0x35,0xc7,0xd9,0x6e,0xd2,0xbe,0xdc,0x43,0xc4,0x6c,0x13,0xe4,0xaa,0x01,0xc7,0x7f},20560,10118,67,7452,6805,0,21138,1},
+ {{0x1b,0xab,0x1a,0x0e,0x1b,0xb8,0x36,0xba,0xe6,0x2f,0xf1,0xd8,0x00,0xb8,0x9a,0x75,0xaa,0x9a,0x23,0x7d},22294,5266,77,5914,6805,0,21138,2},
+ {{0x1b,0xd2,0xb1,0xa0,0xe6,0x09,0x70,0xc1,0xdc,0x69,0xe9,0x68,0x10,0x9b,0x03,0xb4,0x02,0x95,0x70,0x78},18212,338,72,15417,6805,0,21138,0},
+ {{0x1c,0x2a,0x66,0x3e,0xfd,0x72,0x14,0xd2,0x74,0xf8,0xcd,0xd3,0x3c,0x36,0x78,0x9b,0xb0,0x3c,0x99,0x6e},20909,11414,62,752,6811,0,18459,0},
+ {{0x1c,0xb2,0x40,0x0f,0xb2,0x5e,0xd6,0xc0,0x9f,0x86,0x4f,0xb9,0x0f,0x29,0x7c,0x84,0x4e,0x66,0xf7,0x66},19881,7168,62,10706,6805,0,18459,0},
+ {{0x1c,0xf2,0x00,0x24,0x17,0x3f,0x0a,0xf2,0x1b,0x8a,0x37,0xc4,0x96,0xea,0xb3,0x8f,0x83,0x8b,0x77,0x39},21826,15686,72,9652,6805,0,21138,0},
+ {{0x1d,0x40,0x3b,0x3e,0x77,0xca,0xcf,0xf6,0x20,0x89,0x43,0xea,0x16,0x0a,0x50,0x65,0xfb,0x9f,0x35,0x2a},19668,6607,46,9986,6805,0,18459,0},
+ {{0x1d,0xfd,0x3e,0xf2,0x1d,0x76,0x5d,0x4b,0x44,0x30,0xdd,0x52,0xf5,0x8e,0xb9,0x2d,0x96,0x2d,0xfc,0x85},22155,17269,72,9701,6805,0,21138,0},
+ {{0x1e,0x48,0x80,0xe0,0x18,0x59,0xc6,0x3f,0xfc,0x20,0x20,0xbb,0x2f,0x42,0x99,0xd9,0xc8,0xca,0x7d,0xbf},20396,12612,51,5914,6805,0,18459,0},
+ {{0x1f,0x13,0xc7,0xac,0x13,0x2d,0x7f,0xc6,0x69,0xc1,0x38,0x2b,0xd9,0x9c,0xa1,0xbb,0x5a,0x25,0x79,0x04},18807,3239,67,9701,6805,0,21138,0},
+ {{0x1f,0x24,0x83,0xc9,0x48,0x12,0x98,0x08,0x31,0xa6,0x2f,0xdf,0x6f,0xd3,0xda,0x60,0xce,0xff,0xd6,0x1f},21990,16753,51,17099,6805,0,18459,0},
+ {{0x20,0x08,0xa7,0x39,0xc9,0x99,0x43,0x09,0xe7,0xcb,0x5b,0x60,0xa8,0x0e,0xf9,0x24,0x9f,0x43,0x9f,0xd4},21145,14949,46,9652,6805,0,18459,0},
+ {{0x21,0x0c,0xbc,0x71,0x1f,0x82,0x0d,0xbe,0x1a,0x7e,0x1b,0xb0,0x53,0xe8,0xd1,0x1a,0x94,0xde,0xd1,0xe0},20846,11256,72,9652,6805,0,21138,0},
+ {{0x21,0xe1,0x6d,0x8a,0x26,0x7a,0xe2,0x09,0xba,0x56,0x81,0x65,0x28,0xcf,0xad,0x82,0x1c,0x26,0xc5,0x87},20800,11067,62,2796,6805,0,21138,0},
+ {{0x24,0x51,0xd9,0xa7,0x25,0xc3,0xc6,0xc5,0x02,0xd1,0xad,0x0f,0x46,0x9e,0x99,0xfc,0xd2,0x70,0xda,0xae},21385,13888,67,5914,6805,21376,21138,0},
+ {{0x24,0x54,0xdb,0x7d,0xa7,0xb9,0x6b,0xf1,0x40,0xb4,0x9a,0xa9,0xe7,0xf3,0xb5,0xd8,0xf6,0x0b,0x00,0x39},18423,1906,72,4679,6805,0,21138,0},
+ {{0x24,0x8e,0x96,0x7c,0x40,0x69,0xbf,0x04,0x7b,0x1a,0x11,0x4a,0x77,0x68,0xbb,0x21,0x10,0xf4,0x30,0xa4},21593,15136,77,9701,6805,0,20657,0},
+ {{0x24,0xfe,0xef,0x69,0xcf,0x75,0x2d,0x22,0x29,0xb5,0x79,0x1c,0xc6,0x2b,0xdd,0xc7,0x55,0x54,0xe0,0xeb},18165,595,102,9648,6805,0,21138,0},
+ {{0x25,0xa9,0xfb,0x58,0x99,0x7f,0x60,0x69,0xfa,0xba,0xbe,0x46,0xc4,0xe0,0x9d,0xec,0xb7,0x90,0xe6,0x29},18799,3219,51,9652,6805,0,18459,0},
+ {{0x26,0x2a,0xd1,0x28,0x89,0x1d,0xd9,0x7a,0xaa,0x59,0xba,0xf2,0xf8,0x05,0xee,0x91,0x15,0xa1,0x27,0x7d},18373,1431,62,9986,6805,0,21138,0},
+ {{0x26,0x33,0x26,0x66,0x1e,0xd7,0x7d,0x88,0xec,0x17,0x0d,0xdb,0xb2,0xb4,0xdc,0x7a,0xfb,0x25,0xd3,0x5d},18755,3348,77,9652,6805,0,21138,0},
+ {{0x26,0x35,0x95,0x6c,0x51,0x2e,0xc0,0x8f,0x44,0xb6,0xdd,0xa8,0xa6,0xdc,0x01,0x9e,0x86,0x8e,0x10,0xe2},20193,8748,62,9644,6805,0,18459,0},
+ {{0x26,0x6e,0xb1,0x2d,0x8d,0x47,0xc8,0x2a,0xd6,0x7e,0x85,0xb8,0x07,0x64,0x53,0x02,0x0e,0xed,0xcc,0x9a},19818,12296,46,17120,6805,0,18459,0},
+ {{0x26,0xfb,0xa2,0xcb,0x2c,0x37,0xe7,0x8e,0x98,0x7b,0x8a,0x03,0xc9,0x14,0x0a,0x51,0x40,0xde,0xa9,0xdd},21030,11908,62,17099,6805,20058,18459,0},
+ {{0x27,0x53,0xe9,0xa6,0x41,0x5b,0x1a,0xb5,0xc0,0x70,0x29,0x0d,0x44,0x8c,0x49,0x15,0x29,0x45,0x1c,0x1f},18914,3804,67,6322,6805,0,21138,0},
+ {{0x27,0x98,0xbb,0x11,0x4f,0xcb,0x3b,0x2f,0x1e,0x63,0x36,0x06,0x63,0x91,0xa1,0xba,0x5a,0x0c,0xc6,0x9a},20052,8070,62,17099,6805,20047,21138,0},
+ {{0x27,0xbb,0x73,0xa3,0x37,0x2a,0x01,0x89,0xad,0x95,0x97,0xfc,0x8d,0x9f,0xb5,0x46,0xcc,0x46,0x6e,0xef},18173,713,77,9652,6805,0,21138,0},
+ {{0x28,0x7a,0x0f,0x98,0x9a,0x59,0xb4,0x48,0x60,0x23,0xd8,0x44,0x94,0xb8,0x62,0xe1,0x49,0xed,0x99,0x02},20211,16200,51,14830,6805,0,18459,0},
+ {{0x29,0x04,0x8f,0x59,0x0d,0xfa,0x9c,0x29,0x65,0xa6,0x9a,0x3a,0x9b,0xc3,0xd6,0xc9,0x99,0xcb,0xc2,0x9f},19298,5551,51,10706,6805,0,18459,0},
+ {{0x29,0x75,0x82,0x42,0xbd,0xf0,0xfa,0x0b,0x1e,0x01,0x93,0xee,0x8a,0xc7,0x78,0x1e,0xfa,0x8e,0xc3,0x0b},18594,2628,87,699,6805,0,21138,1},
+ {{0x29,0x93,0xce,0xf0,0xcf,0xb9,0x97,0xc3,0x46,0x33,0xfe,0x91,0x31,0xbc,0xa0,0x89,0x35,0xd3,0xdf,0xa1},19377,5671,51,9652,6805,0,18459,0},
+ {{0x2b,0x3c,0xc8,0x2c,0x63,0x78,0x94,0xd9,0x09,0x6b,0xc6,0xa5,0xc9,0xf5,0xad,0x58,0x09,0x85,0x25,0x2b},19932,6987,72,10706,6805,0,21138,1},
+ {{0x2c,0x6e,0x16,0xfd,0xec,0x3a,0xaa,0x22,0xab,0x27,0x6d,0x50,0xd9,0x4d,0xb6,0x50,0x83,0x65,0xb3,0x18},20855,11303,132,426,16652,0,21138,0},
+ {{0x2c,0x9b,0xe3,0x92,0x6d,0x7c,0xb5,0xe5,0xd4,0x6e,0x54,0x18,0xbe,0x8f,0xd0,0xc0,0x1d,0xeb,0x30,0x9f},22259,17878,51,4257,16652,0,18459,0},
+ {{0x2d,0x30,0x57,0x8a,0x99,0xe6,0x67,0xac,0xa8,0x2b,0x20,0x22,0xb1,0xb4,0x62,0x27,0xa9,0xd8,0x71,0xce},20340,9364,46,5914,6805,0,18459,0},
+ {{0x2d,0x50,0x59,0xfc,0x38,0xba,0x24,0xd9,0xee,0x43,0x4a,0x33,0xeb,0x76,0xbf,0x3d,0x3a,0x91,0x9b,0x02},19514,6118,137,9297,16652,0,21138,0},
+ {{0x2d,0xa1,0xea,0x9a,0x6a,0x83,0xf7,0xc8,0xc8,0x30,0x83,0x67,0x79,0xab,0x00,0x68,0x38,0x75,0x9f,0xb9},22233,17746,62,14072,6805,0,21138,0},
+ {{0x2e,0x6e,0x3d,0xee,0x64,0x07,0x53,0xc4,0x75,0x8e,0x2b,0x27,0xb6,0x32,0x2f,0xaf,0x51,0x72,0x88,0xf8},22055,16906,41,9986,6805,22048,18459,0},
+ {{0x2e,0xce,0x49,0xb1,0x29,0x13,0x33,0xa7,0x46,0x0f,0xaa,0x03,0xfc,0x69,0x59,0xc3,0x01,0xf2,0xd2,0x38},21312,13727,82,267,6805,0,21138,0},
+ {{0x2e,0xf1,0xab,0xf5,0x97,0xff,0x31,0x23,0x72,0x2e,0x8d,0x3f,0xe3,0x84,0x75,0x6b,0x1b,0x01,0x4e,0x96},18299,1012,67,6140,16652,0,21138,0},
+ {{0x2f,0x70,0x2c,0xfb,0x44,0x08,0xef,0x5b,0xcc,0xc6,0x43,0xe5,0x93,0x74,0xf0,0x55,0x02,0x53,0xa4,0x5b},21395,13982,62,9156,6811,0,21138,0},
+ {{0x31,0x3c,0x0b,0xf7,0x94,0x5d,0x0f,0x90,0xb2,0x10,0xad,0x83,0x03,0xf8,0xb5,0x1a,0x89,0xe8,0x56,0xda},21599,15184,62,9701,6805,0,21138,0},
+ {{0x31,0x53,0x72,0xab,0x10,0x0e,0xc1,0x46,0x34,0xb2,0x23,0xb9,0xce,0x23,0xce,0xdf,0xcb,0xfa,0x84,0x61},20594,10586,51,2225,6805,0,18459,0},
+ {{0x31,0xa9,0x8a,0x47,0x76,0x83,0xcc,0x50,0x38,0x17,0xb4,0x40,0x32,0x13,0x25,0x1d,0x4b,0x64,0xa1,0x89},19738,6858,152,1251,0,19729,21138,0},
+ {{0x31,0xbd,0x94,0xf7,0x57,0x6f,0x7f,0x38,0xd8,0x50,0x53,0x60,0x35,0xaa,0x29,0xef,0x0a,0xff,0x71,0x6f},19368,5652,62,10706,6805,0,21138,0},
+ {{0x32,0x09,0x4d,0x6b,0x42,0x50,0x10,0x68,0x98,0x82,0x9c,0x5e,0xee,0x01,0xde,0x5d,0x4a,0x4b,0xf7,0x8a},20076,8094,51,15405,6805,0,18459,0},
+ {{0x32,0x20,0x79,0xd1,0xc9,0x31,0xe3,0x5d,0x85,0xc3,0x23,0x47,0x91,0xd0,0x4e,0x22,0x09,0x1e,0x5a,0xa0},20542,10000,46,9701,6805,0,18459,0},
+ {{0x32,0x31,0x0a,0xa4,0x9e,0xed,0x1c,0x6c,0xdf,0x12,0x19,0x60,0x64,0x46,0xbb,0x6d,0x0e,0xad,0x7b,0xcd},20455,9592,137,4665,16652,0,21138,0},
+ {{0x33,0x96,0x37,0x09,0xf2,0xfa,0x43,0xc0,0x5c,0x7a,0x71,0x96,0xe2,0x06,0x0c,0x9f,0x53,0x36,0xfc,0x83},21750,15319,67,11880,6805,0,21138,0},
+ {{0x34,0x4f,0xe3,0x1a,0x83,0x46,0x3d,0x10,0x6f,0xc8,0xca,0x1b,0x27,0x4e,0x6f,0xf0,0x76,0x49,0xf0,0x8b},20421,9474,62,9644,6805,0,21138,0},
+ {{0x34,0x5a,0x83,0x39,0xb2,0xc8,0xad,0xfb,0xcd,0x05,0x55,0x13,0xa6,0x2c,0x3a,0x4e,0x8a,0xe8,0xe7,0x5a},21492,14181,67,9652,6805,0,21138,0},
+ {{0x35,0x5d,0xa6,0xd2,0x7f,0x23,0xa2,0xa8,0x1d,0x29,0x64,0x41,0x22,0x99,0x31,0x0d,0xb3,0xed,0x86,0x89},20612,1802,72,4897,6805,0,20670,2},
+ {{0x35,0xc0,0x1f,0x0f,0x2b,0x63,0xe7,0xfb,0x72,0xe0,0x89,0x67,0x63,0x72,0x58,0x0a,0x31,0x4e,0x85,0xd8},18248,898,72,5914,6805,0,21138,0},
+ {{0x35,0xe4,0x4e,0x73,0x1c,0x70,0x69,0x5c,0x9d,0xed,0x9a,0x94,0xc3,0x9e,0x24,0x78,0xb3,0xc8,0x1e,0xe4},19950,7554,67,9644,6805,0,21138,0},
+ {{0x36,0x5b,0x60,0xa0,0xec,0x27,0xdb,0xe1,0xf3,0x32,0xd0,0xac,0x80,0xe8,0xcb,0x71,0xcc,0x78,0xf8,0xfc},19784,7039,41,17099,6805,0,18459,0},
+ {{0x36,0xde,0xa1,0x31,0xd1,0x72,0x1d,0xa1,0xd8,0x16,0xe4,0x0c,0x82,0x47,0x78,0x69,0x8e,0x35,0x42,0x89},19995,8871,51,7457,6805,0,18459,0},
+ {{0x36,0xec,0x3d,0x80,0x05,0x32,0x17,0x2a,0x6c,0xa7,0x89,0x72,0x11,0x2b,0xd6,0xa6,0x87,0xa3,0x20,0xcc},20176,8405,46,17099,6805,20159,18459,0},
+ {{0x37,0x26,0xe6,0xcf,0x1e,0x03,0x03,0xcd,0x3f,0x0c,0x19,0x68,0x38,0xa9,0x04,0xda,0xb5,0x78,0xfd,0x23},18480,1925,67,6304,6805,0,21138,0},
+ {{0x37,0xa9,0x82,0xcb,0x7d,0xc8,0x73,0x60,0x84,0xd2,0x51,0xe3,0xdd,0xb6,0x6b,0x9e,0x4a,0xea,0xe8,0xe3},21048,11982,41,9644,6805,0,18459,0},
+ {{0x39,0x1c,0xe8,0xde,0x33,0xda,0xd9,0x36,0x88,0xb5,0x43,0x9a,0x8a,0xf7,0xfd,0x01,0x95,0xdc,0x9b,0xcc},21200,12869,51,6304,6805,0,18459,0},
+ {{0x39,0xb5,0x24,0xdb,0xd0,0x1d,0x1a,0x4a,0x61,0xf0,0x59,0x8b,0x68,0x67,0x57,0xe6,0xd3,0x4c,0x21,0x76},18661,2837,46,9986,6805,0,18459,0},
+ {{0x39,0xe7,0xfe,0xa1,0xe1,0x84,0xb8,0x91,0x71,0xf9,0x2b,0x2c,0xed,0x2f,0xf1,0x53,0x42,0x29,0x14,0xc6},20264,9060,67,9663,6805,0,21138,0},
+ {{0x3a,0x98,0x8e,0x3f,0xfe,0xae,0x46,0x76,0x93,0x79,0x6d,0x2f,0x9c,0xf7,0xd5,0x88,0x17,0xbb,0xc0,0x31},19289,4719,72,946,6805,0,21138,0},
+ {{0x3a,0x9f,0xfa,0x55,0x3b,0x24,0x10,0x47,0xae,0x5d,0xbb,0x2f,0xf8,0xf2,0x49,0x1d,0x8a,0x0f,0x1a,0xb6},20576,10629,62,2225,6805,0,21138,0},
+ {{0x3a,0xed,0x61,0x4f,0x6c,0xe9,0x06,0x07,0x0a,0x35,0xa4,0x54,0xc1,0x4e,0x59,0xe9,0x8a,0xb7,0x72,0x9a},22033,16852,46,5914,6805,0,18459,0},
+ {{0x3b,0x8d,0xe4,0xf1,0xd4,0x59,0xda,0x98,0x01,0xa8,0xc3,0x0f,0xd5,0xf6,0x71,0xad,0xe7,0xfd,0x2f,0x87},21775,15455,67,5957,6805,21767,21138,0},
+ {{0x3b,0x94,0x68,0x23,0x0c,0xb1,0x58,0x41,0x07,0x07,0x44,0x39,0x6b,0x4f,0x3d,0x63,0xaa,0x1c,0xac,0x07},20403,9409,72,9652,6805,0,21138,0},
+ {{0x3c,0x6c,0x9c,0xf7,0x13,0x4a,0x20,0xc3,0x6c,0x19,0xdf,0xcb,0x6b,0x10,0xc3,0x2d,0x4a,0x05,0x95,0xf7},21937,16437,72,7471,6805,21918,21138,0},
+ {{0x3d,0x43,0xa9,0xd5,0x9e,0x3a,0x89,0x45,0x80,0xa4,0xbb,0xab,0xc8,0x5e,0xe0,0x75,0x7b,0x09,0xd8,0x4a},19182,5017,72,5914,6805,0,20657,0},
+ {{0x3d,0x55,0x94,0x3b,0x6a,0x22,0x41,0xbc,0xcc,0x49,0xd4,0x3a,0x3d,0x1a,0x04,0x4e,0xd1,0xb7,0x43,0x7f},22164,17293,62,9701,6805,0,21138,0},
+ {{0x3e,0xe9,0xdd,0x98,0xaa,0x62,0xda,0xc6,0x38,0xdc,0x20,0xf2,0x2f,0x67,0x02,0x91,0x20,0xa1,0xd6,0xd6},20149,8218,72,9663,6805,20140,20657,0},
+ {{0x3f,0x3b,0x4e,0x7c,0x5c,0x2a,0xe0,0xfa,0xab,0xf1,0x39,0xeb,0x95,0xe5,0xe6,0x00,0x21,0x62,0x92,0x8b},21580,15044,72,9701,6805,0,20657,0},
+ {{0x3f,0xc1,0xcc,0xec,0x5a,0x31,0x37,0x73,0xbc,0x88,0x44,0x86,0xcd,0xf9,0xa5,0x4c,0x29,0xab,0xb1,0xc1},22277,5158,62,5914,6805,0,21138,0},
+ {{0x3f,0xc6,0xbf,0xf6,0x6d,0x6b,0x93,0xb6,0xf4,0x1f,0x74,0xd2,0x6b,0x38,0xa8,0xdd,0xc3,0xa5,0x2b,0xba},18772,3610,62,17099,6805,18764,21138,0},
+ {{0x3f,0xf3,0xe7,0xd6,0x78,0x85,0xb0,0x94,0xd1,0x49,0x54,0xff,0x07,0x84,0x69,0x5a,0x5d,0xf4,0xcb,0x11},19271,5575,72,9663,6805,0,21138,0},
+ {{0x40,0x36,0x16,0x5a,0x03,0xb9,0xeb,0xf9,0xa1,0x50,0xaf,0xff,0x43,0x7b,0x5e,0x92,0x99,0x6f,0xcb,0x78},18737,3381,62,9652,6805,0,21138,0},
+ {{0x40,0x4a,0x5a,0x8b,0x73,0xad,0x1b,0x77,0x71,0x4c,0xb6,0xf6,0x5b,0x20,0xbe,0x22,0x5a,0xe1,0x83,0xff},19413,5732,72,4897,6805,0,20670,2},
+ {{0x40,0x6c,0x22,0x2c,0x6b,0x16,0xaf,0x09,0x7e,0x08,0x81,0x28,0xe0,0x3c,0x06,0x5f,0x22,0x7a,0x15,0x00},21956,16611,72,17099,6805,0,21138,1},
+ {{0x41,0x07,0x03,0x95,0xf8,0x0d,0x59,0x60,0x18,0x84,0x01,0x9d,0xc0,0x80,0xd7,0x6a,0x11,0x00,0xba,0x08},20927,11564,62,14830,6805,0,21138,0},
+ {{0x41,0xda,0x84,0x13,0x9e,0x47,0x1a,0x0f,0x5c,0x74,0xec,0xf0,0x27,0xa7,0x28,0xbc,0xc7,0x4d,0x2a,0xe6},21723,14994,62,7452,6805,0,21138,0},
+ {{0x42,0xf4,0x90,0xa1,0xee,0xc3,0xd7,0x20,0x0d,0x89,0xb0,0x06,0x3e,0x40,0xb9,0xe4,0x9a,0x7d,0x5a,0x7c},22017,16777,46,17099,6805,0,18459,0},
+ {{0x43,0xfb,0x5b,0x21,0x6d,0xb3,0xd8,0xac,0x38,0x7b,0x07,0xec,0x50,0x54,0x16,0x94,0xa7,0xa5,0x40,0x37},20039,8017,72,5914,6805,0,21138,0},
+ {{0x44,0x34,0x83,0xa7,0x59,0x92,0x84,0xc7,0xd4,0xce,0x22,0x84,0x64,0xc7,0x92,0xdb,0xc2,0x2b,0xad,0xa0},20047,8083,62,8168,16652,0,21138,0},
+ {{0x45,0x3e,0xef,0x88,0x7f,0x04,0xad,0x98,0x30,0xf3,0x4c,0xde,0x40,0xba,0xa3,0xfa,0xeb,0x42,0xb4,0xd4},18196,758,67,10706,6805,0,21138,0},
+ {{0x45,0x74,0xc1,0x57,0x66,0x85,0x85,0x12,0xe0,0x3c,0x16,0x10,0xa6,0x7d,0x3f,0x48,0xd5,0x04,0xaa,0x1e},18497,2149,41,5914,6805,0,18459,0},
+ {{0x45,0xc5,0x57,0xd0,0x39,0x47,0xa9,0x39,0x49,0x5c,0x00,0x1d,0x10,0x0a,0x2d,0x3a,0x32,0x5b,0xef,0xed},21086,1158,72,946,6805,0,21138,0},
+ {{0x46,0x2a,0x43,0xd0,0x92,0x5b,0x44,0x22,0xad,0xf8,0x4b,0x12,0x71,0x51,0xa1,0x7b,0xc3,0x7b,0x2a,0x0a},20985,11613,67,9652,6805,0,18459,0},
+ {{0x46,0xcd,0x07,0xcd,0x5f,0x07,0xa3,0xa2,0x64,0x56,0x13,0xd2,0xc5,0xb0,0xac,0x36,0x67,0xdf,0x38,0x92},19020,4350,67,9701,6805,0,21138,2},
+ {{0x48,0x02,0x21,0xe8,0x74,0xd2,0xe3,0x68,0x95,0x54,0xd6,0xe8,0x01,0x75,0x65,0x34,0x3e,0x10,0xf6,0x9e},22048,16891,46,15641,16652,0,18459,0},
+ {{0x48,0x5b,0xd5,0x61,0xf0,0x72,0x5f,0x85,0x2d,0xfe,0x76,0x2b,0xed,0x01,0xf7,0x0c,0x93,0xb9,0xe3,0xd9},18349,1268,67,5914,6805,0,21138,0},
+ {{0x48,0x60,0x45,0x92,0x29,0xe3,0x1d,0xbb,0x66,0xcf,0xfb,0x1f,0xe2,0x70,0x51,0xc5,0xbe,0x35,0x6c,0x0a},21616,14526,62,9701,6805,0,18459,0},
+ {{0x48,0xd2,0x33,0x07,0x05,0xfc,0x75,0x96,0xf5,0x96,0x00,0x95,0xc9,0x94,0xca,0x7d,0xea,0x1a,0xb0,0xb0},19360,5625,97,3901,16652,0,18459,0},
+ {{0x49,0x20,0xb8,0x7a,0x8e,0xe8,0x1a,0xba,0xfc,0xdf,0x56,0x8f,0xfa,0x3a,0x67,0x61,0xd7,0xc9,0x7a,0xc8},18905,3739,72,691,6805,0,20657,0},
+ {{0x4c,0xaa,0x8f,0xdf,0xbb,0x83,0x9c,0x16,0x89,0x82,0xf5,0xeb,0x5f,0x35,0xf7,0xb4,0xbf,0xa7,0x3c,0xed},21810,15611,87,9663,6805,0,21138,0},
+ {{0x4c,0xc5,0x70,0x65,0xbd,0x83,0x3a,0x46,0xb5,0xc5,0xd4,0xb3,0xc3,0x8f,0xaf,0x8a,0x32,0xab,0xc6,0x55},20837,11277,82,9684,6805,0,21138,0},
+ {{0x4c,0xe0,0x06,0x44,0xe4,0x9b,0x7e,0x0e,0x7b,0xbb,0xd9,0xc7,0x3b,0xff,0x50,0x00,0x68,0xf9,0xaa,0x30},20282,9084,112,9289,16652,20273,21138,0},
+ {{0x4c,0xe6,0x8c,0xc3,0xb8,0x65,0x17,0x41,0xdf,0xb2,0xf3,0x00,0xa4,0x8d,0x8b,0xab,0xb8,0x1a,0x67,0x42},19845,12093,41,9652,6805,0,18459,0},
+ {{0x4d,0xd7,0x26,0xcf,0xd7,0xdc,0x6a,0x4e,0x1d,0x2b,0x05,0xe0,0xd4,0x2d,0x89,0xe3,0x1f,0x2e,0x6a,0xa2},21732,15287,62,7457,6805,0,21138,0},
+ {{0x4e,0x68,0x12,0xae,0x03,0x0e,0xb1,0xb0,0x9e,0xf5,0x15,0xba,0xa6,0x5d,0xce,0xe2,0x61,0x3e,0xe8,0xed},19619,6202,62,6322,6805,0,21138,0},
+ {{0x4e,0x74,0x2f,0x76,0x96,0x8b,0x20,0xd1,0x84,0x2e,0xa4,0xcb,0xa9,0xcd,0x9e,0x02,0x31,0x59,0x8e,0x17},18693,2905,46,9986,6805,0,18459,0},
+ {{0x4f,0x59,0x32,0xd1,0x3d,0x5c,0x17,0x8c,0xfb,0xc0,0x66,0xe2,0x5f,0x5c,0xf5,0x35,0x58,0xce,0x80,0x23},20809,11115,62,2796,6805,20800,21138,2},
+ {{0x4f,0xae,0x26,0x90,0x24,0x1f,0x81,0x98,0x30,0xfa,0xcb,0x30,0xfa,0x7c,0x47,0x35,0xfd,0xc7,0x11,0x3f},21449,14097,72,6322,6805,0,21138,0},
+ {{0x4f,0xda,0x5a,0xd3,0x61,0x3d,0x05,0x69,0x4d,0x7d,0x2c,0x0c,0x1d,0x30,0xa8,0xec,0x3e,0x65,0x4a,0x0f},18852,3513,62,4257,16652,0,21138,0},
+ {{0x50,0x1a,0x11,0x3e,0xe8,0xec,0xb5,0x58,0x0d,0xce,0x1a,0x91,0x49,0xe7,0xd7,0x1a,0x8b,0xf4,0x63,0x91},18939,3868,72,9663,6805,18930,21138,0},
+ {{0x50,0x39,0x65,0xf6,0x89,0xe0,0x12,0xa1,0x28,0x3a,0x13,0x37,0xff,0x05,0x9c,0x4a,0xf4,0xa9,0x43,0x10},18879,16120,67,17167,16652,0,21138,0},
+ {{0x50,0x87,0x8c,0x5d,0x63,0xb2,0x5b,0x96,0xab,0x73,0xf9,0x77,0x49,0x13,0xdb,0x15,0x6b,0x1a,0xe1,0x39},21669,14691,51,9986,6805,0,18459,0},
+ {{0x50,0xc2,0xa6,0x8d,0x3b,0x1a,0xb9,0x98,0x02,0xec,0x86,0x5a,0xf9,0x01,0xe8,0x45,0x4d,0xf6,0x2f,0xc4},21067,12455,72,5914,6805,0,20657,0},
+ {{0x50,0xc3,0x76,0xdd,0xcc,0x73,0x84,0x28,0xd1,0x97,0x1a,0x22,0x08,0xee,0xc2,0x13,0xa5,0xf3,0x31,0xc4},20273,9108,132,9289,16652,0,21138,0},
+ {{0x51,0x00,0xdb,0x1a,0xbb,0x77,0x45,0x95,0x08,0xcf,0xbe,0xb4,0x3a,0x86,0x92,0x0c,0x0e,0x91,0x3a,0xcf},262,240,62,5933,16652,0,21138,1},
+ {{0x52,0x40,0x96,0x54,0x2b,0xf3,0xdd,0x25,0x17,0x87,0xfc,0xc7,0x81,0x8b,0x62,0xa5,0x3a,0xd8,0xbe,0x3b},21062,12427,67,17099,6805,0,21138,0},
+ {{0x52,0x58,0x76,0x64,0xe6,0xc1,0x6c,0x5b,0xb8,0x27,0x87,0xea,0x04,0x40,0x69,0x5e,0xe6,0x39,0x7a,0x8e},20819,11175,67,2796,6805,0,21138,0},
+ {{0x52,0x70,0x2f,0x07,0x6c,0x14,0x3d,0x1d,0x3e,0x8d,0x63,0x03,0x19,0xad,0xa5,0x38,0x84,0x05,0xc7,0xe1},21802,15557,62,8969,6811,0,21138,0},
+ {{0x52,0xdb,0x76,0x82,0x3e,0xa5,0x7c,0x4e,0xf6,0xcd,0x1e,0x9b,0x1c,0xd1,0xa3,0xc4,0x70,0x46,0x98,0xf7},20730,10900,51,11942,6805,20722,21138,0},
+ {{0x53,0x2a,0xe0,0xb0,0x2f,0xdd,0xef,0x06,0x0c,0xc4,0x50,0x0f,0x5a,0xf2,0x6c,0xd9,0x30,0x8b,0x73,0x3b},19243,5460,72,16346,6805,19234,21138,0},
+ {{0x53,0x47,0x3d,0x2e,0xb1,0x3f,0xb9,0x1b,0xcd,0x96,0x6f,0x12,0x53,0xc7,0x74,0x85,0x63,0xe7,0xbc,0x92},19158,4838,62,15520,6805,0,18459,0},
+ {{0x53,0xb2,0xda,0xb8,0x07,0x2c,0x23,0x41,0x68,0x71,0xbe,0x71,0x61,0x35,0xa0,0xcd,0xcf,0xa9,0x5f,0x16},20219,8902,51,9144,6805,0,18459,0},
+ {{0x54,0x47,0x92,0xf0,0xd6,0x09,0xf2,0x0c,0xa9,0xe7,0xb4,0xd3,0xf5,0xf0,0xbc,0x29,0x5c,0x2e,0x9c,0xa9},22288,5212,62,5914,6805,22277,21138,0},
+ {{0x55,0x55,0xf1,0xeb,0x3b,0x21,0x3b,0x71,0x0e,0x19,0xa6,0x2c,0x66,0xc9,0x5b,0xde,0xd1,0x74,0x68,0xec},19280,5515,62,7471,6805,0,21138,0},
+ {{0x55,0x73,0x0f,0xca,0x43,0x66,0x7b,0x79,0xca,0x69,0xa2,0x20,0x92,0xdd,0xeb,0x9e,0x47,0xf8,0xea,0xc4},21661,14660,72,9652,6805,0,20657,0},
+ {{0x56,0x9e,0x93,0x75,0xfa,0xa5,0x86,0x96,0xb7,0xeb,0x75,0x93,0x28,0xcd,0x64,0xcb,0x91,0x19,0xe1,0xdc},19505,6063,41,9652,6805,0,18459,1},
+ {{0x56,0xc1,0x4e,0x1a,0x17,0xd1,0xc4,0x55,0xd5,0xca,0x5f,0xb7,0x07,0x26,0x2e,0x79,0x70,0xe8,0xef,0xa5},20891,11386,67,5914,6805,0,18459,0},
+ {{0x56,0xef,0x1e,0xcd,0xb4,0xc1,0x3a,0xae,0x23,0x02,0x86,0xd1,0x48,0xc4,0x38,0x8e,0x87,0xbe,0x21,0x6b},20312,9246,67,9913,16652,0,21138,0},
+ {{0x57,0x47,0x23,0x6d,0x03,0x7d,0x3e,0x7d,0x93,0x1e,0x6c,0x68,0x29,0xb0,0xfa,0xf9,0x8e,0xdc,0x9f,0x47},22200,7272,77,9973,6805,0,21138,0},
+ {{0x58,0x43,0xc7,0xad,0x36,0xe6,0x48,0x46,0x83,0x40,0x8f,0x0a,0x51,0xe8,0x79,0xd7,0xea,0xca,0xe3,0xe1},20828,11224,62,9986,6805,0,21138,0},
+ {{0x58,0x94,0x4f,0xc7,0xc2,0xf2,0xa1,0xda,0x65,0x28,0xe9,0x5b,0x46,0xd7,0x3a,0xde,0xad,0x35,0x5e,0x71},18702,2959,72,16480,6805,0,21138,0},
+ {{0x58,0xbc,0x6a,0xf8,0xae,0x5b,0xca,0x7b,0xd2,0x72,0x6a,0xfe,0x04,0xc8,0xf1,0xec,0x19,0xe8,0xd2,0x4b},19985,7867,46,1393,6805,19976,18459,0},
+ {{0x5a,0xa2,0xce,0x24,0xe9,0x3b,0x02,0x50,0x06,0x9a,0x43,0xd9,0x9f,0x1b,0x9b,0xe9,0x30,0x6b,0x7c,0x25},21465,9762,62,9701,6805,0,21138,0},
+ {{0x5a,0xcd,0xd7,0x41,0xb0,0x6c,0x40,0x44,0x69,0x4d,0xfe,0xb1,0xb7,0xd8,0x4a,0xbd,0xb6,0x91,0x49,0x4d},19487,6007,77,5914,6805,0,21138,0},
+ {{0x5c,0x22,0x5a,0x59,0xb4,0x9a,0x08,0xf8,0xeb,0x7d,0xd5,0x19,0x37,0x90,0x0d,0x18,0x84,0xf4,0x46,0x40},20202,8802,67,9644,6805,0,21138,0},
+ {{0x5c,0xa6,0xce,0x8f,0xd1,0xea,0x7a,0x76,0x69,0xe3,0xe1,0xa0,0xa0,0x81,0x54,0x97,0x6f,0x2f,0x9d,0x6f},22033,16852,46,5914,6805,0,18459,0},
+ {{0x5c,0xba,0x0b,0x94,0xb6,0x97,0xdc,0x9f,0x9f,0x45,0x7a,0x1f,0xeb,0x09,0x8f,0xd1,0xec,0xbe,0xb0,0xde},19117,4395,36,5914,6805,19109,18459,0},
+ {{0x5d,0x80,0xe4,0xb3,0xb4,0x00,0x2d,0xac,0xd0,0x6e,0xdb,0xbd,0xdc,0xe5,0x5d,0x4a,0xe2,0x0b,0x8e,0x16},21972,16704,46,17099,6805,0,18459,0},
+ {{0x5d,0x81,0xcf,0x1a,0xba,0x41,0x18,0x01,0xb3,0x76,0x55,0x10,0xbf,0x84,0x6d,0xab,0x74,0xfc,0x74,0xc3},21519,14329,56,9652,6805,0,18459,0},
+ {{0x5f,0x08,0x89,0x52,0xd1,0x62,0xeb,0xc3,0xe7,0x2c,0x72,0x84,0x6f,0xe2,0x72,0xb1,0x03,0xad,0xd9,0x05},18135,7130,72,6304,6805,0,21138,1},
+ {{0x5f,0x26,0x4e,0x9c,0xb0,0x1c,0x63,0xdc,0x34,0xfd,0x72,0x63,0x4a,0xd3,0xd8,0xfb,0x8c,0x0e,0xc0,0x60},21130,14883,51,5914,6805,0,21138,0},
+ {{0x5f,0xe3,0xb4,0x77,0x28,0x6a,0x60,0xe4,0x7c,0x36,0x7f,0x8d,0xd4,0xd6,0x62,0x55,0x7a,0x62,0x58,0x8b},21121,5120,77,5914,6805,0,20657,0},
+ {{0x61,0x94,0x34,0x31,0x34,0xfe,0x1d,0xd7,0x4d,0x84,0x03,0x81,0x70,0x82,0xc0,0xe8,0x7c,0x03,0xb6,0xd1},20688,10820,51,5914,6811,18280,18459,0},
+ {{0x62,0x0c,0x24,0xf7,0x51,0xec,0xff,0x52,0xe3,0x36,0x3e,0x30,0xd4,0xdb,0xa8,0xb1,0xc3,0x75,0x57,0xeb},20569,10056,36,5914,6805,0,18459,0},
+ {{0x63,0x43,0x6e,0xae,0x82,0x53,0x6a,0x46,0x0f,0x76,0x34,0x32,0x31,0x70,0x44,0xde,0x10,0xcc,0x3b,0xb5},18986,4073,62,9986,6805,0,21138,1},
+ {{0x63,0x47,0x12,0x84,0xc5,0xda,0x06,0x1e,0x2a,0x67,0xd8,0xd5,0x47,0x22,0x55,0x13,0x26,0x5c,0x25,0x97},22306,18035,51,15520,6805,0,18459,0},
+ {{0x64,0x08,0x41,0xe7,0xda,0x66,0xd6,0xf7,0x32,0x8d,0x58,0xaa,0xce,0xca,0xeb,0xcf,0x13,0x5a,0xc2,0x1b},21287,13526,67,752,6805,0,21138,0},
+ {{0x65,0x1c,0xa2,0xae,0x55,0xa7,0x9f,0x72,0xf2,0x92,0x7f,0xa0,0xf0,0x43,0xd3,0x9d,0x83,0xc7,0x4d,0xe7},18114,368,62,5914,6811,0,21138,0},
+ {{0x65,0x34,0x47,0x19,0xbb,0x02,0xfe,0x8d,0xfc,0x5b,0x1f,0x72,0x03,0x4a,0x01,0x1a,0x54,0x14,0xc4,0x12},19604,1083,77,4897,6805,0,20670,2},
+ {{0x66,0x2b,0x27,0x55,0xa4,0x12,0x17,0xca,0xde,0x5d,0x8c,0xb1,0xea,0x54,0x67,0x40,0x06,0x88,0xfe,0x09},20873,11339,51,9652,6805,0,18459,0},
+ {{0x66,0x5f,0x10,0xc0,0x1a,0x17,0x0e,0x1d,0xe0,0xf7,0xdb,0x9b,0x3f,0xe6,0x29,0x5e,0x5b,0xca,0x86,0x48},18226,812,62,9986,6805,0,21138,0},
+ {{0x66,0xca,0x24,0x33,0xb5,0x6e,0xe4,0xf3,0x8c,0x81,0xba,0xa7,0xa7,0x50,0x38,0x2c,0xe5,0x4b,0x13,0x42},19586,10500,72,13847,6805,0,21138,0},
+ {{0x66,0xee,0x76,0x12,0xd6,0xe8,0x17,0xa2,0x77,0x77,0x8e,0x77,0xb5,0xda,0x2e,0xc4,0xc3,0xc7,0xf5,0x06},20523,6491,46,329,16652,0,18459,0},
+ {{0x67,0x10,0x2d,0xdd,0xf6,0x4e,0xc7,0xb1,0xb5,0xbb,0x77,0x61,0x27,0x38,0xa3,0xf2,0xc9,0x1c,0x66,0xff},18266,956,72,9652,6805,0,21138,0},
+ {{0x67,0xe7,0xc5,0x59,0xc1,0xbe,0x20,0x34,0x50,0x2c,0xb6,0x3e,0xfe,0xa6,0x88,0x1f,0xcc,0x6b,0x8e,0x5a},22128,17381,72,5914,6811,0,20657,0},
+ {{0x68,0x1b,0x70,0x4b,0x79,0x87,0x0a,0x6f,0xdf,0x69,0x18,0x71,0x8a,0x2f,0x46,0x40,0x07,0x9e,0x6f,0xc1},19809,12211,46,17120,6805,0,18459,0},
+ {{0x68,0x2d,0xc0,0xc1,0x82,0x32,0xac,0xb5,0xa5,0x99,0x81,0x30,0x37,0xff,0x21,0xcb,0x0b,0xfe,0x48,0x15},20882,11362,72,9652,6805,0,21138,0},
+ {{0x68,0x69,0x5c,0xf1,0x21,0xe9,0x3d,0xe1,0xf4,0x15,0x94,0xf1,0x4b,0xeb,0xb8,0x0f,0x8d,0x95,0x3c,0xf9},20126,6937,67,3829,16652,0,21138,2},
+ {{0x68,0x75,0x33,0xa2,0x25,0x53,0xdd,0xf9,0x4e,0x10,0x24,0x4c,0xb9,0x2b,0xc2,0xf8,0x2c,0x25,0x7f,0x0b},27,1,67,292,6805,0,21138,0},
+ {{0x69,0x8b,0x7d,0x5b,0x4a,0xb0,0x37,0xe9,0x27,0xa5,0xc6,0xb7,0x69,0xb0,0xab,0x61,0x8d,0xf7,0x3e,0x00},21643,14567,67,11759,6805,0,21138,0},
+ {{0x6a,0x2b,0x06,0x33,0x93,0x5f,0x42,0x1c,0x16,0xfb,0x77,0x19,0x25,0xca,0x59,0x7d,0xb4,0xb8,0x50,0x91},22137,17222,67,5914,6805,20067,21138,0},
+ {{0x6a,0xa2,0xc9,0x91,0x49,0x6a,0x68,0x30,0x2d,0xaf,0x29,0x7f,0x23,0xb9,0x68,0x19,0xd6,0x3e,0xbe,0xfa},20756,10973,77,9663,6805,0,20657,0},
+ {{0x6b,0x0c,0x59,0x25,0xf8,0x9a,0x2c,0x54,0x13,0xe4,0xcb,0x36,0xae,0x81,0xbf,0x8a,0x5e,0xe5,0x4a,0x07},19334,1713,72,4897,6805,0,20670,2},
+ {{0x6b,0xb9,0x15,0x09,0xc4,0x8e,0xbc,0xef,0xe7,0x02,0x57,0xc1,0xfb,0xb3,0x18,0x2f,0xb4,0x07,0xf2,0x99},20303,9177,62,9652,6805,0,18459,0},
+ {{0x6c,0x7c,0x52,0x2e,0x8e,0xd8,0xdc,0x03,0x9a,0x0c,0x9d,0x18,0x51,0x2a,0x88,0x54,0x26,0xaf,0xc1,0xc5},19710,6406,46,5914,6805,19701,18459,0},
+ {{0x6c,0x86,0x25,0x55,0x54,0x5f,0x26,0x6a,0xc2,0x88,0x83,0x6a,0xab,0x7f,0x9d,0xa1,0xbd,0xd4,0xe6,0xf5},21112,12558,67,7452,6805,0,21138,1},
+ {{0x6c,0xe6,0x56,0x1a,0x7f,0x6b,0xf2,0xc2,0x50,0x8e,0x1c,0x1c,0x44,0x2f,0xc3,0x81,0x0a,0xd7,0xdb,0x71},20375,8509,77,9701,6805,0,20657,0},
+ {{0x6d,0x4e,0x3c,0xb1,0x13,0xda,0xcf,0x15,0x8d,0x93,0x92,0xa1,0x8d,0xaa,0x41,0x3c,0x0f,0x5a,0x03,0x60},21862,15815,41,5914,6805,0,18459,0},
+ {{0x6d,0xe5,0x53,0x4c,0x9c,0x3a,0xfb,0x59,0x9b,0x77,0xd1,0xd7,0xa9,0x72,0xf7,0x47,0x9b,0xe2,0xf8,0xf5},20016,7927,62,14822,6805,0,21138,0},
+ {{0x6e,0x04,0x5d,0xee,0x47,0xba,0xe8,0x76,0x63,0xc6,0x09,0x4c,0x6f,0x2b,0xb6,0xff,0x3c,0x4d,0x76,0xb8},19701,6375,51,11927,16652,0,18459,0},
+ {{0x6e,0x31,0x5d,0x57,0x77,0xfb,0x5d,0x43,0x67,0x5a,0xa1,0x27,0x62,0x82,0x7a,0xdd,0xfa,0xd7,0x8f,0x76},19967,7615,67,5957,6805,19959,21138,0},
+ {{0x6e,0x82,0xb7,0x82,0xbf,0x38,0x24,0x1e,0xda,0x0c,0x26,0xb8,0x3c,0x90,0x5c,0x82,0x3d,0x66,0xe9,0xcf},20630,10720,72,10706,6805,0,21138,0},
+ {{0x6e,0xe7,0x85,0x6c,0xc9,0xcc,0x85,0x73,0x86,0x49,0x1a,0xef,0x1d,0xcb,0xca,0x4c,0xd5,0xf2,0x8f,0x55},21269,13474,77,267,6805,0,21138,0},
+ {{0x70,0x24,0xf7,0x0d,0x85,0x7e,0x11,0xa1,0x1a,0x53,0xac,0x76,0x33,0x5b,0xf4,0x66,0x71,0x81,0x1a,0x90},21890,15922,51,9986,6805,0,21138,0},
+ {{0x71,0x38,0xea,0xc0,0x99,0x9e,0xba,0x52,0xf0,0x0f,0x91,0xdd,0xe9,0x40,0x00,0x6d,0x87,0xab,0x03,0x23},18534,2485,72,9986,6805,0,21138,1},
+ {{0x72,0x56,0x41,0x09,0x1b,0xcc,0x13,0x81,0x29,0x8f,0x20,0x12,0x6e,0x22,0xfd,0x2d,0x89,0xee,0x41,0x01},21294,13625,77,4679,6805,0,21138,0},
+ {{0x72,0xd8,0x36,0x15,0xd4,0x30,0x19,0xcd,0x7d,0xd4,0x13,0xaf,0xa4,0x57,0xd5,0x25,0x89,0x3a,0xfe,0x2f},21767,15421,67,5957,6805,0,21138,0},
+ {{0x72,0xfb,0x99,0x51,0xa0,0xef,0xef,0xdc,0xa2,0xb6,0x36,0x07,0x3f,0x47,0xb2,0x27,0x51,0x29,0xde,0x72},18409,1861,72,9652,6805,0,21138,0},
+ {{0x72,0xff,0xbf,0x7c,0x41,0x18,0xf7,0xba,0xf1,0x83,0x16,0x28,0x4f,0x94,0xc9,0x53,0x35,0xe4,0xba,0xc0},20639,10762,62,9701,6805,0,21138,0},
+ {{0x74,0x5b,0x55,0xb4,0x33,0xe8,0xdc,0x7c,0x6c,0x58,0x30,0x08,0x7d,0xb8,0xe8,0x13,0x35,0x19,0xec,0xd0},22248,17824,46,4257,16652,0,18459,0},
+ {{0x74,0xaa,0xf1,0x58,0x41,0xf8,0x02,0x43,0x94,0x49,0x5f,0x37,0xfd,0xae,0xe0,0x36,0xfd,0x3d,0x22,0x3c},20704,10842,62,9986,6805,0,21138,0},
+ {{0x75,0x40,0xdd,0xae,0x6b,0x0f,0xd2,0x39,0xfd,0x52,0xfa,0xc2,0x60,0xad,0xe8,0xfb,0x1c,0x57,0xf4,0xcc},18679,2884,72,5914,6805,0,21138,0},
+ {{0x75,0x7a,0xe6,0x88,0xd5,0xd2,0xe5,0xe4,0x6c,0xe4,0xa3,0x29,0x3e,0xc8,0xd1,0x3a,0xe0,0x3f,0x77,0x2a},18896,3688,51,1393,6805,0,18459,0},
+ {{0x76,0x05,0xc6,0x20,0x73,0xd2,0x10,0x70,0x8f,0x1e,0x84,0x70,0x47,0xb2,0x77,0x63,0x06,0x03,0x90,0x8f},18955,3998,67,15641,16652,0,21138,0},
+ {{0x77,0x0e,0xff,0x89,0xa4,0xb2,0xde,0x3a,0x7f,0x62,0x01,0x32,0x6d,0x3c,0x38,0x46,0x13,0xe7,0xd1,0x50},22070,16961,46,9986,6805,22063,18459,0},
+ {{0x77,0x21,0xa3,0xc2,0x34,0x7f,0x84,0x7b,0xf5,0x3a,0x61,0xb0,0x7b,0xb5,0xb0,0xaa,0x3d,0x03,0x9a,0xb0},19133,4441,46,9986,6805,19126,18459,4},
+ {{0x77,0x6c,0x17,0x08,0xb3,0x59,0x21,0x4a,0x12,0x97,0x46,0x94,0xc0,0x27,0x34,0x3b,0x1f,0xef,0xd5,0x24},21321,13788,87,267,6805,0,21138,0},
+ {{0x78,0xbd,0x59,0x64,0x24,0x1f,0x33,0xdb,0x13,0x26,0x71,0x6b,0xb3,0x46,0x58,0x63,0x23,0x0a,0x63,0x5d},21981,16728,46,17099,6805,0,18459,0},
+ {{0x7a,0xb7,0xa9,0x01,0x61,0x62,0x86,0xad,0x5e,0x67,0x00,0xe3,0xb0,0x42,0x6d,0x25,0x60,0x92,0x60,0x6a},21153,14970,67,9652,6805,0,21138,0},
+ {{0x7a,0xe9,0x4f,0x6d,0xc4,0x8a,0x3e,0x63,0x68,0x3e,0xb7,0x65,0xf8,0xc2,0x38,0x19,0xab,0x9f,0x30,0x1b},19253,5373,82,9663,6805,0,21138,0},
+ {{0x7a,0xf0,0xf2,0xd1,0x3b,0x0e,0xc9,0x4e,0x81,0x8c,0x2e,0xcf,0x1a,0xdc,0x95,0xc8,0xcb,0xa5,0x05,0xe6},21278,13410,102,267,6805,0,21138,0},
+ {{0x7b,0x3d,0x81,0x3b,0x62,0x23,0x93,0x46,0xdd,0x35,0x18,0x2c,0x88,0x13,0x69,0x62,0xc4,0x5f,0x02,0xa2},19422,5823,67,16480,6805,0,21138,0},
+ {{0x7b,0xab,0x37,0x7c,0x7b,0xc3,0xa2,0x02,0xe9,0x66,0x75,0x0b,0x21,0x8a,0x12,0x53,0xd2,0x5d,0x89,0x23},20791,16220,46,6304,6805,0,18459,1},
+ {{0x7d,0x73,0xee,0xa0,0x1e,0x37,0x20,0xe8,0xdf,0x5b,0xef,0x20,0xd4,0x39,0x85,0x6d,0x22,0x0f,0x0a,0x0e},18273,971,82,9663,6805,0,21138,0},
+ {{0x7e,0x94,0xd3,0xcc,0xcf,0xbd,0x0f,0x43,0x93,0xd3,0xf2,0x1b,0x48,0x6c,0xa3,0xfb,0x86,0x50,0xac,0xbb},19141,4760,67,6304,6805,0,21138,0},
+ {{0x7f,0x27,0xe9,0x85,0xac,0xf4,0xea,0x34,0xa2,0xf3,0x62,0x06,0xa8,0x96,0xd6,0x00,0x7d,0x7d,0x9d,0x83},18612,2701,51,9644,6805,0,18459,0},
+ {{0x7f,0x6a,0x4f,0xf5,0x02,0x2e,0x81,0x14,0x86,0x53,0x41,0x50,0xb3,0xd5,0xa1,0x02,0xa3,0x68,0xed,0xc7},19914,7405,77,9663,6805,0,21138,0},
+ {{0x80,0x4b,0x8e,0x05,0xba,0x22,0x20,0xe0,0x1a,0x1d,0x28,0xe0,0xea,0xc4,0xf3,0xdd,0x00,0xc4,0x36,0xb9},21510,14376,77,9652,6805,0,21138,2},
+ {{0x80,0x84,0x6f,0xf8,0x2b,0x58,0x4c,0x92,0x3e,0x49,0xc0,0xd4,0x1a,0x2a,0x78,0x87,0xab,0x41,0xc6,0x60},20551,10073,67,7452,6805,0,21138,1},
+ {{0x80,0xf5,0x3b,0xa3,0x44,0xb1,0xa6,0x81,0x74,0x8f,0x8e,0x3f,0xac,0x66,0xc8,0xc3,0x0a,0x88,0xba,0xeb},18107,16017,51,6140,16652,0,18459,1},
+ {{0x81,0x61,0x11,0x7d,0xb5,0x3a,0xe1,0x49,0x93,0x69,0x18,0xb6,0x32,0x80,0x65,0x21,0x95,0x07,0x0b,0xa2},19675,6633,62,752,6805,0,18459,0},
+ {{0x82,0x03,0x45,0x16,0xba,0x04,0x1a,0x36,0x34,0xb0,0xed,0xbe,0xd6,0x42,0x51,0x83,0x08,0xc1,0x03,0x09},19316,16507,62,11942,6805,0,21138,0},
+ {{0x83,0x80,0x54,0x2f,0x6a,0x49,0x08,0xa4,0x4a,0xe5,0x27,0xc5,0x89,0xae,0xeb,0x05,0x2b,0xc5,0x93,0xbf},20517,9933,62,9701,6805,0,21138,0},
+ {{0x84,0xde,0xac,0xbf,0x62,0x83,0xb2,0xbd,0x96,0xb1,0x51,0xcd,0x34,0x15,0x50,0xa2,0x88,0x1c,0xec,0xbe},19225,5403,62,15594,6805,0,21138,0},
+ {{0x85,0x90,0x60,0xb5,0xad,0xa8,0x50,0x83,0xf5,0xe2,0x62,0x30,0x9f,0x5f,0x1b,0x7e,0xc7,0xe3,0x99,0x8c},21793,15526,72,9652,6805,0,20657,0},
+ {{0x85,0xe7,0x06,0xd4,0xba,0xf6,0x07,0x86,0x05,0xf5,0xc3,0xd6,0xa9,0xe1,0x09,0x8c,0x34,0x61,0x1c,0x41},18130,277,67,691,6805,0,21138,0},
+ {{0x86,0x43,0x5b,0xb5,0x32,0x9d,0xdd,0xa9,0x1e,0x76,0x29,0xaa,0xe8,0x29,0xf6,0x5e,0xd8,0xcd,0x41,0x8c},21947,16590,62,9986,6805,0,21138,0},
+ {{0x86,0x6e,0x90,0xf0,0x8c,0xee,0x3c,0x58,0x20,0xb1,0x48,0xf6,0xc2,0xc0,0x79,0x1f,0x59,0x72,0xff,0x51},21563,13553,72,4679,6805,0,20657,0},
+ {{0x86,0xd8,0xa3,0x56,0x53,0x8f,0x44,0xf8,0x91,0xae,0x98,0x5a,0x6f,0x52,0x74,0x02,0x50,0x33,0xbe,0xf5},21899,15349,67,15340,16652,0,18459,0},
+ {{0x87,0x1f,0x5d,0x9c,0xe0,0x5f,0x25,0x02,0x4a,0x16,0x70,0x0a,0xb4,0x88,0x1b,0x65,0x75,0x87,0x4e,0xa4},18397,1526,62,11942,6805,0,21138,0},
+ {{0x87,0x63,0x0a,0x36,0xc3,0x5b,0x46,0x6f,0xfe,0x42,0xe2,0x32,0xa3,0x08,0xc9,0x61,0x66,0x2f,0x15,0x80},19827,12379,46,17120,6805,0,18459,0},
+ {{0x87,0xec,0x13,0x2c,0x7c,0x23,0x36,0x3f,0x7c,0x41,0x1f,0x9a,0xb0,0x97,0xd6,0x60,0xbc,0x7d,0xb5,0xf7},20159,8319,46,17781,16652,0,18459,0},
+ {{0x88,0x51,0x44,0xde,0x10,0x7d,0x9b,0x65,0xc1,0x0e,0x37,0x37,0x32,0x26,0x34,0xa5,0xa3,0x2c,0x2f,0x9c},22253,17803,41,5914,6805,22248,18459,0},
+ {{0x88,0xd8,0xb6,0xa0,0x84,0xb4,0xde,0x97,0x2b,0x4c,0x51,0x02,0x63,0x72,0x33,0x28,0xca,0x93,0xb1,0xbf},20499,9850,67,9663,6805,0,21138,0},
+ {{0x8a,0x28,0xaf,0x48,0xbb,0xda,0x28,0xfa,0x78,0x2c,0x22,0x75,0x3e,0xb5,0x04,0x40,0x6f,0xe6,0x53,0x14},21021,11892,67,17167,16652,0,21138,1},
+ {{0x8b,0x3f,0x9a,0x23,0xd2,0x07,0x71,0x84,0x4f,0x0c,0xf9,0xd1,0xc3,0x90,0x31,0x14,0x5f,0xf6,0x5d,0x2b},20412,9451,67,9663,6805,0,21138,0},
+ {{0x8c,0x4d,0xea,0x9e,0xe6,0xb0,0x80,0xbd,0x37,0x51,0xdc,0xfa,0xda,0x64,0x35,0x5b,0x5d,0x48,0x0c,0x75},18970,3929,51,9986,6805,18949,18459,0},
+ {{0x8c,0xdb,0xf9,0x88,0x15,0x58,0x61,0x40,0x8e,0x3f,0xbb,0x89,0x45,0x30,0x0b,0xc2,0x0d,0xd4,0x45,0x19},21411,14025,62,7471,6805,0,21138,0},
+ {{0x8d,0x25,0xbb,0xfb,0xc5,0x68,0x18,0x72,0xe9,0x96,0xe2,0xa6,0x6d,0xdd,0x36,0xf0,0xe0,0xb3,0x5d,0x16},21705,14838,67,5933,16652,0,21138,0},
+ {{0x8d,0x3b,0x7d,0x1a,0x81,0x17,0xb0,0x3a,0x72,0xd3,0x27,0x03,0x14,0xe0,0xff,0x08,0x33,0xf6,0xdf,0xf0},18639,16091,62,9156,6805,0,21138,0},
+ {{0x8d,0x81,0x7d,0xd8,0x5d,0x8e,0xd8,0x27,0xce,0x49,0xc1,0xa1,0x61,0xbe,0xfe,0xf7,0x86,0xcf,0xf9,0x62},20389,17337,41,5914,6805,20383,18459,0},
+ {{0x8d,0xc4,0xf4,0xc9,0x16,0x03,0x22,0x05,0x30,0xd3,0xf2,0x83,0xe7,0x88,0x64,0x66,0x94,0x88,0x96,0x82},20117,2087,62,9644,6805,0,21138,0},
+ {{0x8d,0xc9,0xdd,0x1f,0x5d,0x2c,0x63,0x98,0x4d,0x44,0x52,0x9b,0xc6,0xb5,0xa8,0xa6,0x04,0x4d,0x82,0x35},20321,9201,67,5914,6805,20312,21138,0},
+ {{0x8d,0xd0,0xae,0x2c,0xaa,0x84,0xac,0x70,0x22,0x14,0x54,0x5d,0x6f,0xbe,0x19,0x1c,0x66,0xb3,0xd7,0x7f},21056,11586,51,6322,6805,0,21138,0},
+ {{0x8d,0xe8,0xa6,0x7b,0x7e,0x4a,0x7e,0x6e,0xb5,0xa0,0xca,0xe5,0xf0,0xfd,0xa8,0xe3,0xc6,0xd5,0x41,0x4e},182,157,97,5933,16652,0,21138,0},
+ {{0x8d,0xe9,0xdc,0xb8,0x85,0x02,0xf2,0x98,0xa6,0x71,0x12,0x86,0xf0,0x6c,0x25,0x33,0xbd,0x16,0x3b,0x27},21458,14163,62,17099,6805,0,21138,0},
+ {{0x8e,0x5b,0x83,0xda,0x25,0x84,0xab,0x8e,0x0a,0x4e,0x00,0x47,0x58,0xca,0x7b,0x79,0x36,0xe7,0x05,0x6d},20294,4302,62,5957,6805,0,21138,0},
+ {{0x8f,0xd0,0x3b,0x0b,0x8c,0xc7,0x96,0x2d,0x6b,0xb8,0x89,0xb7,0x58,0x68,0xab,0xb7,0xaa,0x1f,0xf7,0x0d},22110,17040,46,5957,6805,22093,18459,0},
+ {{0x90,0x79,0x5a,0xc8,0x1c,0xf0,0xd8,0x55,0x47,0xa8,0x4b,0x7c,0x01,0xc6,0x89,0xe0,0x35,0x00,0x90,0xa0},20603,1629,77,4897,6805,0,20670,2},
+ {{0x91,0x39,0x9f,0xe8,0x9e,0xd5,0xec,0x2d,0xa6,0xc0,0x41,0x0e,0xe9,0x7d,0x28,0x09,0x74,0x12,0x76,0xd1},19394,5710,142,16305,16652,19386,21138,0},
+ {{0x91,0x71,0x3a,0xf6,0x68,0xed,0x7e,0x5d,0x91,0x27,0x88,0x14,0x0d,0x8e,0x38,0x08,0xcf,0x9a,0x04,0x9f},18488,5784,51,10706,6805,0,18459,0},
+ {{0x92,0x2a,0xc0,0x88,0x24,0xa1,0xbf,0xf6,0x9f,0x47,0x6a,0x66,0xc4,0x33,0xd1,0xda,0x38,0xd1,0x32,0xc3},20977,11790,62,2796,6805,0,21138,0},
+ {{0x92,0x6e,0x94,0x11,0x98,0xdb,0x68,0xee,0x86,0x49,0x05,0xd1,0xa3,0x67,0xa8,0x16,0x93,0x67,0x3d,0x4a},18450,1676,67,5914,6805,0,21138,0},
+ {{0x93,0x8a,0xe6,0xf8,0x5f,0xa3,0xf8,0x81,0xea,0xbd,0xc1,0xe0,0x1b,0x5f,0x3f,0x10,0x93,0x45,0xa7,0xfe},20490,9712,51,9701,6805,0,21138,0},
+ {{0x93,0xa7,0xc1,0xa4,0xc8,0x5e,0x86,0xd6,0x6a,0xe9,0xc5,0x52,0xd5,0xf7,0x06,0xb2,0xe1,0x22,0xf3,0xbc},21607,14505,72,11759,6805,0,21138,0},
+ {{0x96,0x07,0xcc,0xf6,0x3d,0xe1,0x20,0x2d,0x1c,0x79,0xa8,0x6a,0xf6,0xd6,0x08,0xb5,0x89,0x37,0x35,0xc5},21171,12689,77,5914,6805,0,21138,0},
+ {{0x96,0x6a,0xc0,0x79,0x94,0x93,0xda,0x8e,0x48,0x71,0xff,0xa3,0x46,0x1b,0x9e,0x71,0xef,0x24,0xca,0xc2},19523,6099,72,5914,6805,0,21138,0},
+ {{0x97,0x87,0x20,0xb4,0x88,0x73,0x68,0x28,0xbf,0xf3,0xd7,0xec,0xf2,0xf7,0x38,0xae,0xc4,0xaa,0x3f,0x36},19174,4957,72,5914,6805,19167,20657,0},
+ {{0x97,0xc6,0x76,0xac,0x0b,0xd0,0xdd,0x60,0xb0,0x5a,0xa0,0x20,0xc4,0x8c,0x2f,0xb1,0xe2,0xb1,0x8c,0x05},18621,2729,51,9652,6805,0,18459,0},
+ {{0x99,0x33,0xa4,0x67,0x0f,0x20,0x77,0x84,0x5e,0xc1,0xa0,0xea,0x81,0xa0,0xc0,0x0c,0x68,0xe4,0x07,0x2e},18143,509,72,11880,6805,0,21138,0},
+ {{0x99,0xd0,0x80,0x12,0x70,0x24,0xb2,0xdb,0xc0,0x85,0x16,0xa2,0x2c,0xfe,0xf3,0xef,0xdc,0x58,0x61,0x2d},19012,10177,82,16480,6805,0,21138,0},
+ {{0x99,0xe2,0xc7,0x3a,0xb7,0xdc,0x69,0x30,0xd3,0x37,0x9e,0xe4,0x3f,0xa3,0x34,0x2b,0x26,0xe9,0xb4,0xad},20960,11719,51,9644,6805,0,18459,0},
+ {{0x9a,0x53,0xa3,0xd1,0x45,0x8f,0x15,0x32,0xea,0x50,0x8e,0x43,0x31,0x8e,0x9c,0x2b,0x4a,0xa1,0x10,0xad},22193,7240,72,9663,6805,0,21138,2},
+ {{0x9b,0x11,0xe9,0x3e,0x42,0xea,0x5b,0x72,0x76,0x76,0x38,0xbf,0x66,0x82,0xd5,0x59,0x85,0x0f,0xba,0x72},22119,17146,82,16480,6805,0,21138,0},
+ {{0x9b,0xb8,0x16,0x09,0x55,0xff,0xf2,0xa4,0x03,0x68,0xa8,0x2a,0x3b,0x38,0x79,0x08,0x83,0x79,0x64,0xb4},22078,17001,51,9986,6805,0,18459,0},
+ {{0x9c,0x46,0xa0,0xcc,0xdc,0x9c,0xba,0xeb,0x8d,0x85,0x6c,0x80,0x1e,0x67,0xfd,0xbb,0x26,0x28,0x0a,0xf6},22240,17762,72,14072,6805,0,21138,0},
+ {{0x9c,0x80,0xa4,0x8a,0x5c,0x3e,0xf7,0x19,0x02,0x89,0xf4,0x6b,0x50,0x23,0x55,0x0d,0xfe,0x8f,0xbb,0xd4},20722,10925,62,1448,16652,0,21138,0},
+ {{0x9e,0xea,0x2a,0x1d,0x02,0x36,0xa1,0x2c,0xfa,0x35,0x6e,0x6c,0xde,0x3e,0x64,0xe3,0xcf,0x33,0x4f,0x1a},19325,16548,67,11942,6805,0,21138,0},
+ {{0x9f,0xab,0x62,0xa6,0xd3,0x13,0x85,0x1a,0x8b,0xa1,0xdc,0xc2,0x4f,0xf4,0xd5,0x34,0x66,0x36,0x44,0x64},19199,637,67,7452,6805,0,21138,1},
+ {{0x9f,0xd0,0x2d,0xbf,0x78,0xa1,0xff,0xa4,0xaf,0x67,0xac,0x2e,0xf2,0xea,0x3c,0xd2,0x9e,0x41,0x37,0x3c},20237,8993,72,9663,6805,0,21138,0},
+ {{0xa0,0x24,0x59,0xfc,0xa4,0x18,0x80,0x5d,0x96,0x58,0x44,0x7c,0xd8,0x67,0x57,0xf3,0xeb,0xa2,0x21,0x58},19066,4560,62,1899,16652,0,21138,0},
+ {{0xa0,0x27,0xc4,0x1b,0x2e,0x3e,0x35,0xcd,0xae,0xe7,0xfd,0x3c,0x7e,0xa2,0xd0,0x9b,0x5e,0xcf,0x7f,0x9f},19002,4183,67,11942,6805,18993,21138,0},
+ {{0xa0,0x48,0x3f,0xee,0x2b,0xf6,0x5b,0x49,0x60,0x0d,0x15,0xb3,0x94,0x5f,0xb6,0x65,0x58,0x9b,0xbf,0x3e},18188,5089,67,15520,6805,0,18459,0},
+ {{0xa0,0x80,0x42,0x9a,0xf8,0x21,0xcd,0x37,0xff,0xb7,0xa5,0xc0,0x16,0xdc,0x63,0xdf,0xc5,0xa5,0x11,0x91},19208,5072,62,1393,6805,0,21138,0},
+ {{0xa0,0xf7,0x3f,0x14,0x6b,0xfa,0x64,0x55,0xef,0x91,0x6c,0xbe,0x6c,0x76,0xb9,0x3b,0x7d,0xf7,0xf9,0x99},21784,15503,51,6304,6805,0,18459,0},
+ {{0xa1,0x16,0x03,0xae,0xc3,0x13,0xeb,0xb1,0x69,0xe0,0x3b,0x59,0x4c,0xa4,0x1a,0x0d,0xed,0xcd,0xbf,0x40},21927,16394,72,7471,6805,21918,21138,0},
+ {{0xa1,0x79,0x77,0xb3,0x3a,0x87,0xe3,0x7e,0xb1,0xe8,0x58,0xd7,0x78,0x54,0x97,0xfc,0x4a,0xd3,0x4d,0x66},21908,15987,62,11880,6805,21899,18459,0},
+ {{0xa1,0x9c,0x5f,0xa5,0x05,0x09,0x8c,0xe6,0xa1,0x1b,0x77,0x8f,0x10,0xb9,0x0d,0x58,0x21,0xf6,0xf0,0xae},18746,3406,72,9652,6805,0,21138,0},
+ {{0xa1,0xf6,0xc2,0x0a,0x72,0x94,0x7c,0x38,0x0c,0xbd,0x52,0x19,0x9e,0x4e,0x50,0x0d,0x51,0x9f,0x12,0xa8},20648,7326,67,11927,6805,0,21138,0},
+ {{0xa2,0x16,0x66,0xff,0x45,0xb6,0x73,0x20,0x43,0xda,0x46,0x8d,0xe7,0xac,0xbe,0x1d,0xbc,0xa1,0xd5,0xab},18232,826,62,9156,6805,0,21138,0},
+ {{0xa2,0xa2,0xe4,0x10,0x8e,0xed,0x45,0x3e,0x95,0xf0,0x80,0xb7,0x46,0xb0,0x79,0x71,0x17,0xb8,0x86,0xe9},19038,17494,77,5957,6805,0,20657,0},
+ {{0xa2,0xbd,0xfd,0x8e,0xd6,0x05,0xa5,0x73,0x02,0xee,0xc5,0x23,0xca,0x9b,0x23,0xc2,0x38,0x81,0xbc,0x66},20994,11812,41,9986,6805,20099,18459,0},
+ {{0xa2,0xc6,0x9b,0xbe,0x0c,0xab,0x5c,0xa9,0xc6,0xf8,0x8f,0x61,0xef,0x46,0xe4,0x7d,0x6a,0x54,0x65,0x72},22217,16656,62,5957,6805,0,21138,0},
+ {{0xa3,0xb7,0xb4,0x55,0x50,0xee,0xf3,0x7f,0x2f,0x85,0xfe,0x2d,0x98,0x33,0x43,0x41,0xcc,0xd6,0x78,0x40},18182,16041,72,691,6805,0,20657,0},
+ {{0xa3,0xfe,0xaf,0x6a,0x44,0xce,0xa5,0x5e,0x8c,0x34,0x58,0xae,0x19,0xeb,0x3a,0x6d,0xeb,0x12,0xb0,0xb8},19471,5977,62,5957,6805,0,21138,0},
+ {{0xa4,0x1e,0x89,0xc3,0x03,0x72,0x19,0x04,0x29,0x8a,0x36,0x9b,0x6a,0xea,0x5c,0x42,0xbc,0x5a,0xea,0xc3},21303,13651,62,9701,6805,0,18459,0},
+ {{0xa4,0x4c,0x2e,0x48,0x09,0x24,0x20,0x2e,0xae,0x9d,0xf3,0xb1,0x9a,0x01,0x62,0x0d,0x7b,0xc0,0xef,0x2c},19343,5597,72,16480,6805,0,21138,0},
+ {{0xa5,0x06,0x8f,0xeb,0x9b,0x69,0x7d,0x7f,0x6a,0xe7,0x88,0x51,0x4a,0xf0,0xa1,0x81,0x2f,0x29,0x3f,0x7b},20383,9390,41,17167,16652,0,18459,0},
+ {{0xa5,0x1e,0x34,0x86,0x93,0x40,0x0a,0x51,0x44,0x3b,0x45,0xe2,0x63,0x2a,0xcc,0xae,0xb5,0x61,0xab,0xd8},20621,1300,72,5914,6805,0,21138,0},
+ {{0xa5,0xed,0x92,0x5b,0xc8,0x80,0xab,0x8a,0x95,0x46,0x97,0x3b,0x88,0xe8,0xcb,0x32,0xbf,0xac,0x50,0xde},19749,6441,72,9663,6805,0,20657,0},
+ {{0xa6,0x40,0xc7,0x24,0x1a,0x0c,0x04,0x1e,0xb2,0x5f,0x73,0x65,0x65,0x45,0xb3,0x2d,0xa3,0x10,0xd0,0x20},21209,12934,72,9947,6805,0,20657,0},
+ {{0xa6,0x7b,0xe4,0x3f,0x8e,0x0d,0x45,0x3b,0x17,0x8c,0x08,0x7a,0x7d,0xcf,0x77,0xd2,0x09,0xdc,0xef,0xef},18292,13062,62,17099,6805,18286,21138,0},
+ {{0xa8,0x0b,0x9c,0x91,0x78,0xb6,0x0e,0xfd,0x84,0xa9,0xec,0x5d,0xe4,0xdd,0xdc,0x59,0xe8,0xf6,0x21,0xe3},20765,11033,77,9663,6805,0,20657,0},
+ {{0xa8,0x84,0x6a,0x72,0xf5,0xeb,0x81,0x9c,0x6e,0x9b,0x69,0x47,0xea,0xa2,0x15,0x97,0x44,0x6f,0x2e,0x85},19126,4463,46,15641,16652,0,18459,6},
+ {{0xa8,0x91,0x13,0x42,0x63,0xf2,0x7d,0xe7,0x7d,0x2b,0xa2,0xdd,0x51,0x2c,0x52,0x95,0xe7,0x14,0x8b,0x69},19661,6327,62,2138,16652,0,18459,2},
+ {{0xa8,0xdc,0x13,0x7d,0xd0,0xdd,0x80,0x25,0x9d,0xca,0xac,0xc1,0x32,0xcc,0x56,0xe6,0xd7,0x31,0xd4,0x4e},21572,15023,62,5914,6805,0,21138,0},
+ {{0xa9,0x2d,0x73,0x6e,0x83,0x2b,0x4e,0x88,0x01,0x09,0xa4,0x4b,0x9c,0xc0,0x9e,0x81,0x85,0x1c,0x5c,0x14},18204,796,46,9986,6805,0,18459,0},
+ {{0xa9,0x8a,0x92,0x07,0x42,0xf2,0xf2,0x39,0x9c,0x58,0x8c,0x70,0x2a,0x14,0xfd,0x83,0xc7,0xf0,0x3d,0x46},21366,8636,72,9986,6805,21357,21138,0},
+ {{0xa9,0xdf,0x7e,0xa9,0x3b,0x26,0x8b,0x72,0x26,0xca,0x9f,0x38,0x51,0x04,0x9c,0x82,0xaa,0x11,0x5f,0x90},21696,14923,46,9144,6805,0,18459,0},
+ {{0xaa,0x37,0x2a,0x72,0x9b,0xb9,0x1d,0x73,0x08,0x6e,0x84,0x5e,0xfb,0x30,0x7d,0xa0,0x61,0x21,0xdc,0x72},22182,17575,62,9986,6805,0,21138,0},
+ {{0xaa,0xae,0x3b,0xd2,0x25,0xa4,0x3d,0xc6,0xf7,0x30,0x01,0xa6,0x56,0xe4,0x6e,0x9c,0x5a,0xf2,0xe6,0xc3},19307,7478,77,5914,6805,0,21138,2},
+ {{0xab,0xfc,0x4f,0x06,0xd4,0x92,0xf5,0x3c,0xf7,0x3e,0xeb,0x5c,0x36,0xdb,0x23,0x61,0xf6,0xe8,0x89,0xa5},21330,13694,77,267,6805,0,21138,0},
+ {{0xac,0x03,0x3b,0x09,0xb9,0x58,0x55,0x63,0xd7,0x30,0x0e,0xa6,0xb7,0xcc,0x53,0x49,0x4f,0x06,0x33,0xb5},20108,2040,62,9644,6805,0,18459,0},
+ {{0xad,0x0e,0x36,0xfc,0xac,0xec,0xeb,0x0d,0x15,0x3f,0xf2,0x72,0x83,0x96,0x1d,0x75,0x7a,0x53,0x34,0x33},18993,4166,67,11942,6805,0,21138,0},
+ {{0xad,0x51,0xf8,0x48,0xd8,0xd7,0xb0,0xf3,0xad,0x62,0xa7,0x4d,0xb5,0x4d,0xf4,0x08,0x3e,0x25,0xa1,0xf8},18630,2754,62,9144,6805,0,21138,0},
+ {{0xaf,0xad,0xe5,0xdd,0x16,0x1d,0x71,0xae,0x64,0x6f,0x3d,0x23,0x61,0xae,0xf5,0x61,0x00,0x36,0x21,0x60},19758,6560,77,9663,6805,0,20657,0},
+ {{0xaf,0xcc,0x82,0x69,0xfd,0x2a,0xba,0x58,0x08,0x44,0x53,0x24,0x9f,0x74,0x7f,0xd3,0x68,0x30,0x7c,0xe6},21625,14546,62,5914,6805,0,21138,0},
+ {{0xb0,0x35,0x87,0x42,0xfc,0x78,0x93,0xb1,0xf0,0x94,0x9c,0x81,0xda,0x91,0x9d,0x10,0x9b,0x5d,0xef,0xe8},18923,4210,46,9986,6805,0,18459,0},
+ {{0xb0,0xaf,0x74,0xf3,0x66,0xca,0x52,0x84,0xfb,0x94,0x47,0xdf,0x1a,0x45,0x6e,0x7f,0x62,0x42,0x50,0xf0},20133,8271,82,9652,6805,0,20657,0},
+ {{0xb1,0x60,0xd9,0xbb,0x9d,0x93,0x89,0xfa,0x78,0x50,0xb0,0x8e,0x23,0x6b,0xe4,0xd1,0xec,0xda,0xf8,0x85},19532,10364,67,13847,6805,0,21138,0},
+ {{0xb1,0xd9,0xea,0x7d,0x1e,0x3e,0xc6,0x56,0x6b,0xf7,0xc8,0x99,0xf6,0xea,0xfc,0x87,0xfa,0xce,0x7f,0xd4},18158,579,77,9652,6805,0,21138,0},
+ {{0xb1,0xe4,0x2a,0x5f,0x72,0xe4,0x64,0x28,0xb8,0x1e,0x6d,0x1d,0x43,0xab,0x96,0x6e,0x6d,0x51,0x11,0x0a},22146,17247,67,9701,6805,0,21138,0},
+ {{0xb1,0xe5,0x9c,0x9e,0xa6,0xa5,0x3e,0xb6,0x40,0x35,0xef,0x5c,0x56,0x20,0x17,0xe9,0x6c,0x95,0xb4,0x6f},18930,3845,72,9663,6805,0,21138,0},
+ {{0xb2,0xa9,0x75,0xb5,0xd6,0x09,0x00,0x9b,0xec,0x8a,0x89,0xc5,0xc9,0x1e,0x42,0xe2,0x04,0x9c,0x98,0x2f},19612,6178,67,9947,6805,0,21138,1},
+ {{0xb2,0xc3,0x6f,0x37,0x7d,0x0f,0xef,0xa7,0x98,0xe3,0xf5,0xda,0x59,0x95,0xc7,0x69,0xda,0x84,0x41,0xfa},18790,3119,62,5914,6805,0,21138,0},
+ {{0xb3,0x1e,0xf6,0x82,0x53,0x4f,0x8b,0xfe,0xe6,0x4f,0x6b,0x90,0x72,0x34,0xb2,0xad,0x3b,0x6e,0x09,0xe5},19854,12176,41,9652,6805,0,18459,0},
+ {{0xb3,0x5d,0x11,0xe0,0xde,0x73,0xfd,0x19,0x13,0x88,0x64,0xbe,0xb7,0x04,0x14,0xbc,0x5f,0x3b,0xba,0xc3},19101,4264,97,6310,16652,21625,21138,0},
+ {{0xb3,0x8d,0x63,0x31,0xfd,0x00,0x74,0x8d,0x65,0xae,0x1d,0x1f,0xac,0x3d,0xdf,0x31,0xc2,0x90,0xeb,0x9e},21881,15944,67,9986,6805,0,21138,0},
+ {{0xb3,0xb8,0xbc,0xd6,0x6f,0x58,0xee,0x57,0xf0,0xe7,0x47,0x3d,0xf1,0x54,0x9f,0x51,0xe9,0x09,0x6a,0xde},22132,17405,72,5914,6811,22128,20657,0},
+ {{0xb3,0xd3,0xeb,0xea,0x20,0xe3,0x7e,0xac,0x9c,0x76,0xa0,0xb8,0xaa,0x97,0xd7,0x69,0xf1,0x18,0x8c,0xe4},19445,13367,67,17099,6805,19437,18459,2},
+ {{0xb4,0x5f,0xa3,0x54,0x03,0xc7,0xd5,0x36,0xa1,0x10,0xca,0xa5,0x36,0xa0,0x59,0xdf,0xdb,0x0f,0x8a,0xf3},21431,14078,46,9644,6805,0,18459,0},
+ {{0xb4,0x81,0x37,0xf4,0xeb,0x68,0xac,0xfd,0x4e,0x00,0x04,0xf7,0xaa,0xbb,0xa4,0xdd,0x17,0xc6,0xa6,0x9e},18781,3200,77,9652,6805,0,21138,0},
+ {{0xb4,0x9f,0xf2,0x23,0xc9,0x30,0x65,0x3b,0xb8,0xf8,0xc1,0xbe,0xec,0xae,0xdd,0xfd,0x36,0xe4,0x54,0xa2},19906,16144,62,9156,6805,0,21138,0},
+ {{0xb5,0xc9,0x04,0x8c,0x60,0xdf,0x6b,0x53,0xae,0x45,0x1a,0xbe,0x18,0x5b,0xc2,0x99,0xb3,0x90,0x66,0x6c},18688,3104,82,9684,6805,0,21138,0},
+ {{0xb5,0xd2,0xde,0xdf,0x90,0xa5,0xb9,0x0c,0x4d,0x2b,0x58,0x8e,0x5f,0x69,0x85,0xb8,0xf3,0x8e,0x18,0xb5},19167,4911,72,5914,6805,0,20657,0},
+ {{0xb6,0xdd,0x43,0x5d,0x43,0x78,0x89,0xe9,0xf4,0xdf,0x6f,0x06,0x94,0x14,0x9d,0x52,0x33,0xc7,0xa6,0x5e},20058,8138,62,2138,16652,0,18459,0},
+ {{0xb7,0x43,0x17,0x48,0x1e,0xf2,0x01,0x52,0x74,0xbc,0x09,0x1e,0x2c,0xf2,0x3f,0xed,0x08,0xa7,0x12,0x1e},19262,5496,46,9986,6805,0,18459,0},
+ {{0xb7,0x47,0x5b,0x26,0x17,0x32,0xfe,0x57,0xfa,0x4f,0xa2,0xb3,0x9f,0xc5,0x37,0x20,0xe2,0xd8,0x2a,0x48},20004,7519,51,9644,6805,0,18459,0},
+ {{0xb7,0x8f,0x8b,0xd1,0x06,0x30,0x2a,0xa1,0x70,0x5e,0x7c,0x14,0xd6,0x92,0x52,0xb5,0x20,0x1b,0xd3,0x06},20918,11475,51,752,6811,0,18459,0},
+ {{0xb7,0xde,0x22,0xa4,0x20,0xdf,0x3b,0x94,0x3a,0xa5,0xd3,0x29,0x78,0x66,0x83,0xd0,0xb9,0xa6,0xdd,0x66},21227,12991,77,9947,6805,0,21138,0},
+ {{0xb8,0x4b,0x97,0x76,0x3c,0xb1,0x73,0x42,0x67,0xef,0xb3,0x1f,0x37,0x01,0xc8,0x53,0xd0,0xe8,0x52,0xbf},19430,13222,51,13962,16652,0,18459,2},
+ {{0xb8,0xf6,0x96,0xe6,0x0f,0x5a,0xdb,0x3e,0xd9,0x68,0x88,0x45,0x74,0xf2,0x18,0xf4,0x16,0xb3,0x44,0xee},22063,16945,62,15641,16652,0,18459,0},
+ {{0xb9,0xfe,0x47,0x9e,0x56,0xf5,0xde,0x00,0x71,0x9d,0xd1,0xd7,0x45,0xea,0x9a,0x93,0xaf,0xe5,0x90,0x27},19496,10222,62,13847,6805,0,21138,0},
+ {{0xba,0xa6,0xd0,0x2d,0x43,0x5d,0xec,0x6d,0x21,0x19,0x62,0x8a,0x18,0x20,0xf3,0x51,0xa2,0x46,0x42,0x58},21536,14419,51,9652,6805,21528,18459,0},
+ {{0xbb,0x0a,0x3c,0x91,0x0f,0xfe,0x4a,0xb6,0xa3,0x75,0x40,0x19,0x4b,0xa3,0x55,0x7a,0x85,0x6d,0x86,0x91},18122,445,77,9644,6805,0,21138,0},
+ {{0xbb,0x3b,0xe2,0x10,0x32,0x45,0xd0,0x45,0x2c,0xdf,0x93,0xee,0x4f,0x44,0x35,0x7e,0x74,0xda,0xf7,0x65},18579,2590,67,14683,16652,0,21138,0},
+ {{0xbb,0x80,0x36,0x34,0x87,0xd0,0x87,0xbe,0x66,0xf4,0x33,0x33,0xcc,0x9c,0x7d,0xe5,0xdc,0x06,0x54,0x15},18286,13036,62,11246,16652,0,21138,0},
+ {{0xbb,0x82,0x81,0x10,0x3f,0x60,0x8f,0x79,0x8d,0x03,0x46,0xde,0xc7,0x46,0xf1,0x16,0x5b,0x83,0x5b,0xa3},18331,1232,72,5914,6805,0,21138,0},
+ {{0xbb,0xb6,0x61,0xe3,0x02,0x5f,0x67,0x02,0x47,0x0f,0x55,0xb9,0xcb,0x03,0x31,0x2d,0x19,0x7a,0x23,0x07},21244,13127,62,292,6805,0,18459,1},
+ {{0xbc,0x81,0x6c,0xf3,0xa6,0xba,0x32,0xe8,0xaa,0xe2,0x0e,0x76,0x9f,0x84,0x75,0x83,0x2c,0x66,0x99,0x31},19577,10317,102,13847,6805,0,21138,0},
+ {{0xbc,0xcd,0x9b,0xbe,0x17,0x3a,0xe1,0x7c,0x04,0x85,0xa2,0xa7,0x53,0x75,0xab,0x01,0x26,0xbe,0x82,0xfb},21819,15655,77,9652,6805,0,21138,0},
+ {{0xbe,0x12,0x1f,0x1b,0x42,0x68,0x58,0x99,0x26,0xa8,0x25,0x1c,0x03,0x46,0xb6,0x4c,0x05,0xf3,0x85,0x92},21348,7072,62,9644,6805,0,18459,0},
+ {{0xbf,0xe2,0x8b,0xfa,0x08,0x2b,0x20,0x75,0x91,0x57,0xa5,0x04,0x22,0x82,0xe3,0x21,0x6d,0xf6,0xb5,0x43},18570,2374,62,9986,6805,0,21138,0},
+ {{0xbf,0xf0,0x1c,0x94,0x9a,0xe6,0x6b,0x51,0x79,0x7e,0xc8,0x91,0xbe,0xfd,0x91,0x00,0x95,0x91,0xfb,0xc1},18816,467,67,7471,6805,0,21138,1},
+ {{0xc0,0x2b,0x28,0x28,0x8a,0x06,0x12,0xbf,0x52,0xd5,0xd5,0x79,0x3e,0x19,0x3d,0x92,0x6a,0x90,0x1b,0x56},18843,3432,51,5914,6805,18852,21138,0},
+ {{0xc0,0x33,0xd9,0x28,0x35,0xf0,0x4f,0x3b,0xaf,0xb6,0x2b,0xb3,0x79,0x8c,0x5e,0xb6,0xfc,0x54,0x69,0x0b},20713,10862,51,5914,6805,0,21138,0},
+ {{0xc0,0x76,0xf4,0x7e,0xa0,0x6f,0x68,0x9e,0x8f,0x77,0xd6,0x60,0x7c,0x21,0xf4,0xe5,0xb4,0xb4,0xf3,0x68},20508,9892,72,5914,6805,0,21138,0},
+ {{0xc1,0xae,0x36,0x8c,0xa0,0x20,0x33,0xf5,0x65,0x57,0x1c,0xdc,0xac,0xb4,0x0c,0x1e,0x5f,0x51,0x05,0xb4},21402,14002,77,9947,6805,0,21138,0},
+ {{0xc1,0xce,0x05,0xb1,0x6e,0xf1,0xc4,0x49,0xca,0xc7,0xe5,0x71,0x6b,0xa8,0x45,0xa1,0x1d,0x1e,0xe6,0xb9},20739,11008,72,11942,6805,0,21138,0},
+ {{0xc1,0xe6,0x6f,0x43,0x22,0x72,0x5b,0xda,0x15,0xe1,0xd6,0x59,0x41,0xbe,0x63,0xf7,0x82,0x8a,0x24,0x64},20585,10662,72,2225,6805,0,21138,0},
+ {{0xc1,0xf2,0x1b,0xc4,0x71,0xf2,0x27,0x92,0x10,0xc6,0x0d,0x1c,0x03,0xf0,0x15,0x91,0x06,0x13,0x1e,0x96},21180,12740,77,5914,6805,21171,21138,0},
+ {{0xc2,0xc1,0xfd,0xb9,0x35,0x06,0x84,0x05,0x15,0x4e,0xca,0x2a,0xb6,0xa4,0xed,0x68,0x98,0x53,0x53,0xdd},20140,8179,72,9663,6805,0,20657,1},
+ {{0xc3,0x39,0x2b,0x42,0x38,0xb7,0xd5,0xf4,0xa4,0x0e,0x4b,0x3d,0x24,0xd6,0xed,0x0d,0x5f,0xd0,0x38,0xdf},18670,2806,92,9663,6805,0,21138,0},
+ {{0xc3,0xca,0x89,0xcf,0xa1,0xd1,0x1a,0x64,0x9c,0xe1,0xf2,0x56,0x5a,0x1a,0xa2,0xfb,0x3d,0xda,0x9a,0x07},20936,11507,62,5914,6805,0,18459,0},
+ {{0xc4,0x3c,0xa0,0x0c,0xb4,0x6a,0x53,0x00,0xda,0x6d,0xbb,0x85,0x33,0xff,0x52,0xca,0xa9,0x2b,0xdc,0xbc},21835,15884,62,5914,6805,0,21138,0},
+ {{0xc5,0x02,0x69,0xa7,0x70,0x64,0x83,0x55,0x2b,0x03,0xca,0xc0,0x7c,0x06,0xd1,0xdd,0x2b,0x21,0xa8,0x6b},18315,1055,36,5914,6805,0,18459,0},
+ {{0xc5,0xbf,0x0e,0x98,0x15,0x9e,0x57,0x29,0x5a,0xad,0x65,0x5b,0x34,0x0a,0xcc,0xc5,0xd5,0xff,0xdf,0xc2},18308,1036,97,3901,16652,0,18459,0},
+ {{0xc8,0x99,0x62,0x8c,0xad,0x20,0x7b,0x43,0x33,0xca,0x14,0x19,0xf0,0xaa,0x35,0x52,0x74,0xe4,0x83,0x1d},21999,16805,51,17099,6805,0,18459,0},
+ {{0xc8,0x9f,0x4e,0xcb,0x16,0x6f,0xc3,0x46,0xd4,0x48,0x9f,0x05,0x6c,0x7d,0x9d,0x11,0xf8,0x56,0x81,0x3e},19941,7533,51,7652,6805,0,21138,0},
+ {{0xc8,0xcf,0xad,0x52,0x93,0xdc,0xf2,0xd2,0x08,0x7c,0xa0,0x36,0x49,0x01,0x2a,0x20,0xd0,0xf6,0x89,0x7a},19352,16168,97,3901,16652,0,18459,0},
+ {{0xcb,0x1c,0x39,0x87,0xec,0x85,0xf5,0x5a,0x21,0x53,0x3b,0x5e,0xad,0x58,0x16,0x92,0xbd,0x06,0xa3,0xa9},19541,10398,67,13847,6805,0,21138,0},
+ {{0xcb,0xbf,0xde,0x36,0x85,0x7e,0xb3,0xa7,0x8f,0x91,0x8a,0x3e,0xa8,0xb8,0x10,0x9b,0xe3,0x58,0xd1,0x51},19898,7307,62,9986,6805,0,21138,0},
+ {{0xcb,0xd8,0x79,0x23,0x48,0xd2,0x6d,0x5e,0xe0,0x4e,0xb0,0x71,0x87,0xcb,0x17,0xcc,0xb7,0xcb,0x5e,0xed},20464,9576,127,4665,16652,20455,21138,0},
+ {{0xcc,0x1b,0xb9,0xc2,0x26,0x2a,0xbe,0xe9,0x0a,0xda,0xe8,0x06,0xb5,0x4f,0xc2,0xaa,0x85,0xde,0x4f,0x9a},21376,13926,67,8963,16652,0,21138,0},
+ {{0xcc,0x53,0x65,0x7f,0xd7,0xf2,0xa8,0xfa,0x8e,0x7c,0xa0,0x17,0x96,0xeb,0x37,0x78,0x54,0xfd,0x50,0x14},21501,14293,152,9958,0,0,21138,0},
+ {{0xcc,0x6a,0x2d,0x0a,0x48,0x26,0xeb,0x98,0xb5,0xfd,0xe9,0x99,0xed,0xa5,0x25,0xc4,0xb1,0x22,0xe3,0x49},21252,13163,62,6140,16652,0,21138,0},
+ {{0xcc,0xd5,0x6b,0x03,0xb2,0x1d,0xc3,0xda,0xd1,0x56,0xe8,0x28,0x51,0xe7,0x35,0x7a,0x7b,0x66,0xdc,0x48},19150,4787,41,5914,6805,0,18459,0},
+ {{0xcd,0x16,0xc4,0xd9,0xc4,0xea,0xf6,0x9f,0xf8,0xef,0x05,0x49,0x6a,0x98,0xb4,0xc8,0xeb,0xd5,0x58,0xfb},21528,14439,62,9652,16652,0,18459,0},
+ {{0xcd,0x96,0x23,0xeb,0x74,0x24,0x35,0x21,0x34,0xec,0x75,0x14,0x53,0x05,0x4d,0x44,0xcb,0x49,0x9f,0x5b},19595,10543,72,13847,6805,0,21138,0},
+ {{0xcd,0x99,0xce,0x7f,0x8b,0xf5,0x17,0x17,0x7e,0x0d,0xbf,0xd2,0x43,0x1a,0x72,0x67,0xcd,0x3d,0x59,0xdf},21759,15389,67,16494,6805,0,21138,0},
+ {{0xcd,0xb1,0xec,0x8d,0x3a,0x03,0x2f,0xb4,0xef,0x3d,0x63,0xe2,0xf8,0x5a,0xf1,0x5d,0x21,0x79,0xb4,0xbb},21652,14638,82,15417,6805,0,21138,2},
+ {{0xcd,0xde,0xcd,0x29,0x14,0xb4,0x21,0xdc,0xb4,0x56,0x9b,0x13,0xbd,0x12,0x74,0x36,0x1f,0x72,0x12,0x98},22310,18065,67,8969,6805,0,21138,0},
+ {{0xce,0xdb,0x89,0x2d,0x84,0x12,0xa3,0x35,0x48,0x0a,0xf0,0x77,0x5e,0xb7,0x6b,0x67,0x9f,0x77,0xd0,0x63},19234,5445,67,16346,16652,0,21138,0},
+ {{0xd0,0x92,0x51,0xbb,0xcc,0x78,0xe2,0xa1,0x96,0xcf,0xd1,0x23,0x4f,0xe7,0xa9,0xe8,0x4e,0x53,0xe3,0x94},18391,1480,51,11942,6805,0,18459,0},
+ {{0xd0,0xb8,0x37,0xb0,0x4c,0xca,0x8a,0xb3,0xdd,0xe7,0x2e,0xea,0xe3,0xc2,0xcc,0x5e,0x10,0xdb,0x8e,0x73},20532,6522,46,17099,6811,20523,18459,0},
+ {{0xd0,0xb8,0x57,0xba,0xa8,0x88,0xb0,0x1a,0xdd,0x75,0x91,0x59,0x6e,0x20,0x93,0xfa,0x8d,0x3d,0x59,0x8e},19056,4504,67,11880,6805,19047,21138,0},
+ {{0xd0,0xbd,0xaf,0x93,0xcc,0xea,0x98,0x89,0x93,0x34,0xcd,0xfc,0xcc,0xae,0xb6,0xc5,0x9d,0x78,0x99,0x80},18764,3650,67,4110,16652,0,21138,0},
+ {{0xd1,0x19,0x9d,0x24,0x2b,0x67,0xc4,0x01,0x02,0x01,0xb6,0xc3,0x64,0xf2,0x2f,0x55,0xec,0x67,0xbb,0xa0},22282,5314,77,5914,6805,0,21138,0},
+ {{0xd1,0x36,0xfe,0x98,0x24,0x0d,0xba,0xf5,0xbb,0x30,0x16,0xd8,0x7d,0xd2,0x0e,0xb6,0x5e,0x13,0xe8,0xc5},22026,16684,122,10157,0,0,21138,0},
+ {{0xd1,0x6b,0xab,0x64,0x45,0x5f,0x20,0x6f,0x9b,0x71,0xa2,0x74,0xc4,0xa2,0xf7,0xcb,0x43,0xc9,0x8a,0x18},21714,14859,41,9986,6805,0,18459,0},
+ {{0xd1,0xc5,0xf3,0x65,0x92,0x56,0x5e,0x32,0x84,0xbd,0xc9,0x70,0xb6,0x73,0xfd,0x7b,0x57,0x7a,0xd7,0x84},21076,12477,72,5914,6805,21067,20657,0},
+ {{0xd3,0x52,0xb7,0xaf,0xa1,0xb0,0xd7,0x63,0x30,0x50,0x4b,0x3e,0xbd,0x81,0x2e,0xa6,0xd7,0x6b,0x16,0x26},18404,1846,67,9652,6805,0,21138,0},
+ {{0xd3,0x7a,0xdd,0xaf,0x2c,0xc3,0xa3,0x7c,0x84,0x30,0x84,0x25,0x70,0xe1,0x84,0x6e,0xa6,0xaf,0xe0,0x2a},20951,11654,62,9644,6805,0,18459,0},
+ {{0xd3,0xa0,0x71,0xfc,0xe1,0xf5,0x0d,0x5b,0xaf,0x67,0xd3,0x21,0x0a,0x00,0xc5,0xbd,0x0e,0xe0,0x3c,0x1a},20246,9037,77,10706,6805,0,21138,0},
+ {{0xd7,0x66,0x42,0x86,0xc3,0xf2,0x2d,0x5b,0xbd,0x01,0xb3,0x38,0xbc,0x4b,0x97,0x29,0x27,0xf6,0x34,0xf3},21440,14118,77,9663,6805,0,21138,0},
+ {{0xd7,0x70,0x23,0x30,0x35,0x50,0x53,0xc3,0x16,0x69,0xd3,0xdc,0xff,0x65,0xb4,0x2e,0xae,0x4b,0x07,0xb7},21687,14778,67,9701,6805,0,21138,0},
+ {{0xd7,0x9c,0xe7,0x68,0x84,0x9f,0x21,0xa9,0x01,0x0c,0x22,0x1d,0x8d,0xd7,0x81,0x7a,0x4a,0x1b,0x94,0xf9},22173,17443,77,9663,6805,0,20657,0},
+ {{0xd7,0xcc,0x23,0x68,0x64,0x76,0xb7,0xe0,0x2a,0x32,0x2e,0xa3,0xbc,0xd7,0x61,0x82,0xf8,0x31,0xdd,0x1e},18977,4033,62,9947,6805,0,21138,0},
+ {{0xd8,0x3a,0x6b,0x22,0x18,0xbf,0xb9,0x58,0x37,0xb9,0xfa,0x8e,0x43,0x96,0x3c,0xff,0xbc,0x20,0xdc,0x17},18257,842,72,14138,6805,0,21138,0},
+ {{0xd8,0x59,0xaa,0x50,0xd9,0xe1,0x84,0x73,0x4c,0xd5,0x23,0xe2,0x3d,0x0f,0x1e,0xc7,0x1d,0x4b,0x56,0xcc},21545,12581,51,9701,6805,0,18459,0},
+ {{0xd8,0x75,0xfe,0xdd,0x27,0xe1,0xee,0xa4,0x69,0x6f,0x68,0x61,0x87,0x30,0x37,0x45,0x11,0x0c,0x5a,0xf3},20092,7738,67,9986,6805,0,18459,0},
+ {{0xd9,0x21,0x98,0xbb,0x9f,0x3a,0xb1,0x46,0x3b,0xa3,0xf3,0x54,0x4d,0x1b,0x35,0x7c,0x9c,0xda,0xd5,0xef},19386,4120,147,10782,16652,0,21138,0},
+ {{0xda,0x07,0x34,0xab,0x6d,0x82,0xdd,0x0a,0xd9,0x36,0xbe,0x8b,0xa1,0xbc,0xe9,0x32,0x2d,0x1b,0xda,0x6a},18441,1589,67,7372,6805,0,21138,0},
+ {{0xda,0x6a,0x48,0x26,0x29,0x6b,0xed,0x48,0x83,0x4a,0xde,0xda,0xd2,0x87,0x83,0xca,0x84,0x8d,0xa8,0xc8},20185,1757,67,4897,6805,0,20670,2},
+ {{0xda,0xb9,0xe6,0x86,0x7e,0x39,0x2b,0xf0,0xfd,0xed,0xd8,0x34,0x73,0x48,0x67,0x8a,0x32,0x4e,0x19,0x86},20945,11637,46,9644,6805,0,18459,0},
+ {{0xda,0xbb,0x3f,0x3e,0x9d,0x04,0xb5,0xdd,0xaa,0xf2,0x10,0xcc,0xd4,0xc7,0x66,0xae,0x6d,0x19,0xd1,0x98},20774,16243,72,6304,6805,0,21138,0},
+ {{0xda,0xbc,0xd3,0xb1,0x9c,0x75,0x1a,0x23,0xa6,0x80,0x4e,0x79,0xe4,0x66,0xc0,0xe2,0xdc,0xcc,0x43,0x94},20366,8481,72,9701,6805,0,21138,0},
+ {{0xdb,0xe5,0x1d,0xe4,0xcd,0x9c,0xfc,0x1b,0xbd,0x72,0x36,0xc5,0x13,0x78,0x89,0x22,0x0f,0xe2,0xa4,0x6a},20969,11769,51,2796,6805,0,18459,0},
+ {{0xdc,0x0a,0xe1,0x07,0x10,0xaa,0x7b,0xa4,0xf4,0x9a,0x3e,0x26,0x06,0xd9,0x39,0x23,0x08,0x91,0xa3,0x40},20025,7944,77,9663,6805,0,20657,0},
+ {{0xdc,0x0d,0x06,0xc1,0xb3,0x53,0x33,0x0e,0x0e,0xde,0x74,0xba,0x6a,0x5d,0xcb,0x8a,0x0d,0x12,0x54,0x80},19684,6696,62,752,6805,0,18459,0},
+ {{0xdc,0x68,0x31,0x2f,0xf5,0xa4,0x5f,0xf6,0x6a,0xfe,0x23,0x16,0x3b,0xbd,0xd5,0x1d,0x9c,0x18,0x6b,0x18},22188,17594,72,9663,6805,0,21138,0},
+ {{0xdd,0x66,0x93,0xf7,0xdb,0x94,0xb8,0x31,0xf3,0x92,0x1d,0xe0,0x14,0x56,0xf7,0x2e,0x43,0x23,0x36,0x5e},18860,3584,67,5921,16652,0,21138,0},
+ {{0xdd,0x72,0x05,0x0d,0x2c,0xa5,0x3c,0x21,0x33,0x05,0x33,0x8e,0x24,0xbd,0x6c,0xcb,0xce,0x7e,0x20,0xf5},21918,16351,72,7471,6805,0,21138,0},
+ {{0xde,0x8d,0x36,0xd8,0x8c,0xff,0x75,0x8d,0x94,0x33,0x39,0x0c,0x2e,0x6f,0xfc,0x12,0xc9,0xae,0x78,0xae},20475,4687,67,5914,6805,0,21138,0},
+ {{0xde,0xdf,0xfa,0x3d,0x7b,0x3e,0x27,0x9e,0x4a,0x49,0x8a,0x9e,0xc4,0x27,0x86,0xee,0xd9,0x39,0x31,0x6c},19029,4374,67,11880,6805,0,21138,0},
+ {{0xdf,0x09,0xe3,0x86,0x50,0x2d,0xc0,0x40,0xc1,0xfe,0xa8,0x60,0x25,0xa3,0xf7,0xda,0x4f,0x38,0xf6,0x82},21474,14212,72,11942,6805,0,20657,0},
+ {{0xdf,0x13,0x72,0x87,0x22,0x21,0xb4,0x09,0xf1,0xf4,0x0f,0xe3,0xec,0xaa,0x2c,0x6f,0x36,0x73,0xb8,0x7f},18603,2679,67,5914,6805,0,21138,0},
+ {{0xdf,0xa6,0xb1,0x21,0xfb,0x38,0xc2,0xb2,0x6a,0x96,0xbc,0x53,0xf8,0x6c,0xe0,0x9f,0x44,0x7f,0xbd,0xb5},21039,11961,51,10706,6805,0,18459,0},
+ {{0xdf,0xa9,0xd9,0x9f,0x51,0xa5,0xc1,0x48,0x8e,0xeb,0x44,0x89,0xb1,0x2c,0x78,0x93,0x56,0x61,0xd7,0x37},18962,3963,62,9986,6805,18955,21138,0},
+ {{0xdf,0xfb,0x91,0xae,0x82,0xff,0x96,0xa6,0x28,0x2a,0x9f,0x4d,0x9f,0x86,0x01,0x0c,0x24,0x1a,0x42,0xa4},21634,14593,72,11759,6805,0,21138,0},
+ {{0xe0,0x52,0xde,0xea,0x6d,0x41,0x59,0x4b,0x45,0x42,0x0c,0x9d,0xc1,0xe4,0x67,0xb6,0x6d,0x3e,0x06,0x05},18586,2550,67,5914,6805,18579,21138,0},
+ {{0xe0,0x5f,0x90,0x0c,0x71,0x35,0xde,0x67,0xb4,0x52,0x3f,0xcd,0x42,0x5e,0xc7,0x5c,0xac,0x5f,0x1c,0xf8},22208,17635,62,9701,6805,0,21138,0},
+ {{0xe0,0xc0,0xc5,0x5c,0xa1,0x45,0xc2,0xe0,0xf1,0xa1,0xef,0xa7,0xa4,0xd5,0xf2,0xf5,0x9d,0x34,0xc9,0x13},18364,1404,72,9663,6805,0,20657,0},
+ {{0xe1,0x92,0x18,0xe6,0xcd,0xc4,0x8c,0xcc,0xb4,0xf6,0x0b,0xdc,0xdd,0x92,0x35,0x0e,0x7a,0xbd,0xb5,0x29},18340,1333,62,9652,6805,0,21138,0},
+ {{0xe2,0x8f,0xe7,0x8e,0x38,0x7b,0x4d,0x04,0xb0,0xd9,0xbf,0xff,0xc0,0xf7,0xa3,0x14,0x7a,0x67,0x67,0xcb},19480,5872,72,5914,6805,0,21138,0},
+ {{0xe2,0xeb,0x89,0x43,0x14,0xc1,0xf5,0x31,0x04,0x90,0xa7,0xc0,0x16,0xca,0x7e,0x65,0xd4,0xd0,0x57,0x35},18525,2422,72,9986,6805,0,21138,0},
+ {{0xe3,0x3c,0x00,0x0b,0x4a,0xef,0x2a,0x98,0x89,0xbb,0x6f,0xa2,0x4b,0xc7,0x62,0xc6,0xf5,0xc5,0xc5,0xc6},18543,2259,46,9986,6805,0,18459,0},
+ {{0xe3,0xaa,0x7b,0x19,0x50,0xf7,0x0c,0x70,0xb0,0x28,0x64,0xad,0x31,0xd7,0x8e,0x7c,0x3b,0x38,0x99,0x64},18382,1460,62,9156,6805,0,21138,0},
+ {{0xe4,0x16,0x70,0xfc,0x6c,0x48,0x12,0x86,0xd0,0x85,0x6a,0xbf,0x76,0xa3,0x2d,0x4a,0xca,0x65,0x4b,0x7d},18503,2188,51,5914,6805,0,18459,0},
+ {{0xe4,0x6d,0xee,0xce,0x4f,0xd5,0x03,0x24,0x46,0xcb,0x8d,0xb4,0xa2,0xae,0xd8,0xb7,0x9c,0x86,0xa7,0x18},18949,3917,62,15641,16652,0,18459,0},
+ {{0xe5,0x7c,0x40,0x58,0x7a,0x7e,0x5e,0x5f,0x53,0xc2,0x5b,0xfa,0x54,0x3c,0x0e,0xc2,0x99,0xfe,0x05,0xb3},19085,4638,72,9144,6805,0,21138,1},
+ {{0xe6,0x36,0xfd,0xf8,0x33,0x93,0xa3,0x1b,0x2c,0x3f,0x64,0x00,0xd5,0x59,0xf4,0xa7,0x67,0x1c,0x3e,0x97},18471,1977,62,9644,6805,0,21138,0},
+ {{0xe7,0x1f,0x52,0x74,0x09,0xa1,0x60,0x69,0x93,0xc0,0xde,0xcb,0xe3,0x1f,0x3e,0x34,0x05,0xc6,0x91,0xd3},20783,16276,62,6304,6805,0,21138,0},
+ {{0xe7,0x83,0x93,0x36,0xfa,0xde,0xb7,0xfd,0x6a,0x7e,0x93,0x48,0x60,0x8e,0xc4,0xd2,0xe7,0x93,0x1d,0xf1},21483,14260,72,2225,6805,0,21138,0},
+ {{0xe7,0x95,0xb4,0xb6,0xc1,0xcb,0x40,0xf7,0xa6,0x5b,0x6e,0xab,0xaf,0x70,0xb3,0x43,0x75,0x52,0x61,0x04},18519,9337,62,9986,6805,0,21138,2},
+ {{0xe9,0x07,0x0e,0xa3,0xfc,0xc0,0xf2,0xd9,0x57,0x4e,0x40,0x51,0xf6,0xce,0x6c,0x82,0xb1,0x46,0x34,0xc6},19976,7822,46,1393,6805,0,18459,0},
+ {{0xe9,0x07,0xf2,0xf6,0x37,0xee,0xd0,0xa1,0xf0,0xea,0x52,0x37,0x1f,0x51,0xf9,0xdc,0xb6,0x04,0x2a,0x6f},19092,4583,77,5957,6805,0,20657,0},
+ {{0xe9,0xc2,0xf7,0xf7,0x2e,0x13,0xc6,0xed,0xb2,0xc0,0x68,0xa6,0xe8,0xdf,0xe0,0xe8,0x40,0x6c,0xf4,0xaf},20864,11319,51,9652,6805,0,18459,0},
+ {{0xea,0xf2,0x5a,0xb9,0x0d,0x3a,0x28,0xd8,0xcc,0x74,0x2d,0xff,0x60,0x7c,0x1e,0x97,0x4c,0x07,0x9c,0x78},19767,6357,46,267,6805,0,21138,0},
+ {{0xeb,0x21,0xd2,0x2c,0xd7,0x06,0x13,0x7f,0x0f,0xbb,0xa6,0x8d,0x6b,0xdc,0x8e,0x36,0xc7,0xcb,0xa7,0xa7},19627,6225,107,9289,16652,0,21138,0},
+ {{0xeb,0x74,0xff,0xb4,0xbe,0xb5,0x92,0xd5,0xf6,0x43,0x55,0xe8,0x94,0x83,0x76,0xe8,0x5f,0x38,0x23,0xf3},21260,13183,62,17099,6805,21252,21138,0},
+ {{0xec,0x1c,0x0c,0x2f,0x73,0xec,0xff,0x18,0x66,0x61,0xea,0xd3,0x13,0x48,0xd2,0xf3,0xdf,0x7a,0x70,0xe9},22268,17911,67,5914,6805,0,21138,1},
+ {{0xed,0x89,0xec,0x85,0xee,0xf9,0x94,0x40,0x64,0xaa,0xe9,0x73,0x8a,0xad,0x51,0xb4,0xcc,0x6d,0x84,0xa6},19720,6900,67,9156,6805,0,21138,0},
+ {{0xee,0x6e,0xbb,0xb0,0xea,0x52,0x72,0x5b,0xcd,0xdf,0x97,0x24,0x4d,0x67,0x18,0xe5,0x67,0x48,0x9e,0x32},20748,10948,77,9663,6805,0,21138,0},
+ {{0xee,0xe1,0x8b,0x41,0x5d,0xd6,0xbf,0x4b,0x6c,0xbf,0x28,0x15,0xb6,0xc6,0x88,0xa3,0x82,0xb9,0x48,0x3a},19836,12006,41,9652,6805,0,18459,0},
+ {{0xee,0xe5,0x7a,0x8a,0xbe,0x44,0x39,0x3c,0xe8,0x5d,0x55,0x94,0xbc,0xb7,0x53,0xcc,0xcf,0x79,0x8b,0xfd},21587,15097,67,9701,6805,0,21138,0},
+ {{0xef,0x62,0xf7,0x9a,0x75,0xb8,0x31,0x37,0xf6,0x01,0x0f,0x2e,0xcc,0x29,0x28,0xa9,0x76,0xb8,0x5d,0x50},19791,12039,46,17120,6805,0,18459,0},
+ {{0xef,0x88,0x9e,0xdb,0xa3,0x01,0xb2,0x6f,0x7b,0x33,0x29,0x4b,0xe7,0x9f,0x63,0xb6,0x05,0x03,0xb9,0x78},20067,8115,67,5933,16652,0,21138,0},
+ {{0xf0,0xcd,0x99,0xe2,0x6f,0x88,0x13,0x58,0x9c,0xe0,0x9d,0xa7,0x4c,0x26,0xf4,0x90,0x0e,0x75,0x11,0x28},20438,8846,67,7471,6805,0,21138,0},
+ {{0xf1,0xa0,0x76,0x19,0xa4,0xc2,0x5e,0x26,0x50,0xf6,0xd2,0x84,0x1a,0x3d,0xf5,0xea,0x1a,0xa6,0x3d,0x38},19863,12262,46,9652,6805,0,18459,0},
+ {{0xf1,0xbd,0x5e,0xfb,0x7a,0x03,0x3e,0xa6,0x0d,0x69,0x52,0x03,0x8d,0xb8,0xcc,0x7d,0x49,0x88,0x93,0x8d},19550,10433,67,13847,6805,0,21138,0},
+ {{0xf1,0xc3,0x40,0x18,0x9f,0x56,0x01,0x83,0xc4,0x06,0xd2,0xbf,0x7a,0xc5,0x85,0xaf,0xa6,0x04,0xc5,0xe0},22272,17962,67,5914,6805,22268,21138,1},
+ {{0xf2,0x62,0x00,0x89,0x39,0xd5,0xc1,0xe1,0x76,0x1c,0xc8,0x28,0x56,0x22,0xeb,0xb0,0xad,0x85,0x6d,0x5d},19889,7207,72,9701,6805,0,21138,0},
+ {{0xf3,0x13,0x23,0xd3,0x04,0x74,0xba,0x04,0x6b,0xa9,0x94,0x4c,0x3a,0xc3,0xc1,0x47,0x0b,0xc0,0xc1,0x26},232,187,72,9663,6805,0,20657,0},
+ {{0xf3,0x55,0x99,0xf3,0xb4,0x0d,0xb2,0xf4,0xdf,0x9b,0xaf,0xbb,0xd5,0x97,0x70,0x0a,0x28,0xd8,0xfc,0x1e},19190,5048,62,5914,6805,0,21138,0},
+ {{0xf3,0xcb,0xad,0x96,0x21,0xbb,0x8f,0x6f,0xf7,0x53,0xa2,0xb3,0xfe,0x0b,0xb0,0x30,0x82,0x55,0x67,0x27},18825,3328,72,9144,6805,0,21138,0},
+ {{0xf4,0x20,0x63,0xd7,0xdc,0x0d,0xed,0x7b,0xf8,0xd2,0xb4,0x11,0x26,0x06,0x71,0x00,0x7a,0xae,0xdb,0xb0},21420,14042,62,7471,6805,21411,21138,0},
+ {{0xf4,0x9d,0x23,0x97,0x9b,0x1c,0x26,0x25,0xe1,0x8a,0xb3,0x1c,0x74,0x2f,0x87,0x3d,0x58,0xfe,0x0b,0xc7},18432,17175,46,10706,6811,0,18459,0},
+ {{0xf6,0xca,0x11,0x3b,0x18,0xbf,0x03,0x5d,0x24,0x38,0x85,0xd2,0x33,0x42,0xc8,0xb0,0x67,0x3d,0x11,0x8c},19454,13327,51,17099,6805,19430,18459,2},
+ {{0xf7,0x64,0x8c,0x49,0x4b,0x02,0x5a,0xf2,0x36,0x12,0xad,0xec,0x90,0xc1,0x47,0x8e,0xa7,0x3f,0x79,0xa7},21104,12513,51,9701,6805,0,18459,0},
+ {{0xf7,0x76,0xd7,0xb7,0xf8,0x02,0xd0,0xf3,0x14,0x1f,0x54,0x70,0x8d,0xe7,0x3d,0xc8,0x01,0x23,0x15,0x37},21218,12908,67,9947,6805,0,21138,0},
+ {{0xf7,0x7c,0x0c,0x27,0x5c,0xf6,0xf5,0x64,0x84,0xe9,0x7f,0x1b,0x33,0xf2,0x82,0x7f,0xed,0x88,0x80,0x44},18887,1996,72,5914,6805,18879,21138,0},
+ {{0xf7,0xe3,0x09,0xdd,0x40,0x48,0x6a,0xd2,0xd8,0xdb,0x6e,0x42,0xde,0xc0,0xe5,0x44,0x8e,0x9e,0x91,0xde},19693,6760,67,752,6805,0,21138,0},
+ {{0xf7,0xe7,0xe3,0x6f,0x21,0xa5,0x80,0xb9,0xcf,0xda,0xfd,0xba,0x72,0xcd,0xc8,0x02,0xc4,0xa1,0x9f,0x3f},19800,12127,46,17120,6805,0,18459,0},
+ {{0xf8,0x01,0x62,0x3e,0xd6,0xa6,0x39,0xe2,0xe3,0x1a,0x25,0x47,0x90,0x20,0x9f,0xa1,0xc8,0xdf,0xc7,0x4f},21095,1122,72,946,6805,0,21138,0},
+ {{0xf8,0x53,0x28,0x87,0x41,0xbe,0x1e,0x74,0x9b,0x19,0x89,0x78,0x61,0xb0,0xf5,0x58,0xa3,0x37,0xda,0xc9},18465,1952,72,9652,6805,0,21138,0},
+ {{0xf8,0x5b,0x3e,0xb1,0x49,0x00,0x56,0x16,0xd0,0x1f,0xd3,0xc7,0x27,0x4c,0xfa,0x7d,0x76,0xbe,0x95,0xdd},20900,11538,67,9701,6805,0,21138,0},
+ {{0xf8,0xc7,0x55,0x7f,0xc9,0x4e,0x6a,0xe0,0xb1,0x0a,0x1a,0x4a,0x61,0xa4,0x41,0xe6,0x29,0xf8,0x30,0x45},19653,6161,62,6157,6805,0,18459,0},
+ {{0xf9,0xfe,0xac,0xa7,0xfe,0x0e,0x2f,0x36,0x92,0x6b,0x5f,0x2e,0x28,0x8d,0x42,0x3f,0x63,0xbc,0x09,0xee},20430,9496,87,9701,6805,0,21138,0},
+ {{0xfa,0x01,0xd9,0xa0,0x34,0x16,0xd3,0x5a,0x31,0x37,0x40,0x72,0x8a,0x79,0x7f,0x87,0x92,0xdd,0xfd,0xa1},22101,17070,72,5957,6805,0,20657,0},
+ {{0xfa,0x4e,0xf8,0x34,0x17,0x82,0xc3,0x5f,0x52,0xfb,0xc0,0xe1,0xf7,0xaf,0x28,0xd5,0x81,0x62,0x9f,0x53},18551,2303,62,9986,16652,0,18459,0},
+ {{0xfa,0x5d,0x54,0x3b,0xb0,0x9c,0x6b,0xa8,0x5a,0xa7,0xe3,0x49,0x49,0x2c,0x65,0x99,0xe5,0x98,0x82,0xb5},18560,2327,51,9986,6805,18551,18459,0},
+ {{0xfa,0x9d,0x61,0x1e,0xdd,0x6d,0xb7,0xa4,0x5e,0x71,0xd0,0xd8,0x44,0x28,0xf9,0x0e,0xd5,0x54,0x0a,0x19},18652,3161,67,9701,6805,0,21138,2},
+ {{0xfc,0x40,0xac,0xf0,0x74,0x5a,0x62,0x7e,0x54,0xb8,0xa2,0x51,0x49,0x75,0xd7,0x24,0x59,0xb1,0xea,0x0b},18218,305,77,4897,6805,0,20670,2},
+ {{0xfc,0xe1,0xf8,0xfc,0x9f,0xd8,0x2e,0x7b,0x91,0x81,0x78,0x45,0x08,0x46,0xe1,0xfc,0x7e,0x6d,0x43,0x2e},20697,8347,72,9663,6805,0,20657,2},
+ {{0xfd,0x59,0xee,0xd6,0x9f,0x05,0x21,0x54,0x46,0x17,0xc3,0x6b,0x5f,0xee,0x1b,0x71,0x7a,0x06,0xe9,0xf4},19559,10467,72,13847,6805,0,21138,0},
+ {{0xfd,0x6a,0x1a,0xb3,0x70,0x73,0x86,0xd6,0x03,0xa4,0x6b,0x07,0x69,0xa8,0x2f,0xd7,0x74,0x0a,0xb3,0x93},22224,17703,67,9701,6805,0,21138,0},
+ {{0xfd,0x95,0xce,0x97,0xa9,0xfa,0x8b,0x24,0x9f,0xfb,0x41,0x91,0x10,0xa1,0xc1,0x81,0x71,0x77,0x2c,0x36},18358,1355,67,5933,16652,0,21138,0},
+ {{0xfd,0xd2,0xbc,0x51,0xe3,0x34,0x20,0x93,0xdd,0x39,0x5b,0xec,0xd9,0xa2,0x13,0x21,0xde,0xc8,0x89,0x4b},19644,6295,117,426,16652,0,21138,0},
+ {{0xfd,0xf1,0x4d,0xa4,0x1b,0xad,0x6c,0x4f,0xc4,0x29,0x4d,0x58,0xc3,0x24,0xab,0x96,0xc9,0x60,0x5e,0x3a},19923,7385,67,7457,6805,0,21138,0},
+ {{0xfe,0x37,0x3c,0xbd,0xca,0xb0,0xcd,0x8e,0x4f,0x63,0xb0,0x3c,0x6c,0x52,0xb6,0xd6,0x53,0xa5,0x8f,0x7a},22085,8565,51,9947,6805,0,18459,0},
+ {{0xfe,0x84,0xe8,0xc9,0x43,0x8f,0xaf,0xd6,0xa4,0x99,0xcb,0x10,0x7b,0xab,0x73,0xc5,0x71,0x4f,0x24,0xaa},22301,18013,67,946,6805,0,21138,0},
+ {{0xfe,0xcc,0x69,0xfc,0xae,0x81,0x09,0x2c,0x52,0x16,0x01,0x41,0x87,0xab,0x84,0xce,0xdd,0x36,0x59,0xfb},18510,2240,62,2225,6805,0,18459,0},
+ {{0xff,0x12,0xd9,0xf1,0xf4,0x62,0x63,0xdc,0xcd,0x49,0xdd,0x8a,0xdb,0x6a,0x55,0x55,0xba,0x7f,0x85,0x56},19959,7593,67,5957,6805,0,21138,0},
+ {{0xff,0x2c,0xf1,0x7d,0xc8,0x74,0x19,0xb0,0x51,0xa6,0xdb,0x09,0xa4,0xf5,0x92,0x00,0x7a,0x13,0xb5,0x8b},22042,9519,62,9986,6805,0,21138,0},
+};
+
+static const UINT32 pceCdGameCount = 504;
+static const char pceCdSoftwareListDescription[] = "NEC PC Engine / Turbografx-16 CD-ROMs";
+
+#endif
diff --git a/src/burner/qt/meson.build b/src/burner/qt/meson.build
index e9a5b51c4..078be6401 100644
--- a/src/burner/qt/meson.build
+++ b/src/burner/qt/meson.build
@@ -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',
diff --git a/src/burner/qt/neocdlist.cpp b/src/burner/qt/neocdlist.cpp
deleted file mode 100644
index bfa6457f6..000000000
--- a/src/burner/qt/neocdlist.cpp
+++ /dev/null
@@ -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;
- }
-}
diff --git a/src/burner/sdl/meson.build b/src/burner/sdl/meson.build
index 7b84059c2..1fcd3a4ed 100644
--- a/src/burner/sdl/meson.build
+++ b/src/burner/sdl/meson.build
@@ -8,7 +8,7 @@ frontend_sources = files(
'localise_gamelist.cpp',
'main.cpp',
'media.cpp',
- 'neocdlist.cpp',
+ '../cdlist.cpp',
'replay.cpp',
'romdata.cpp',
'run.cpp',
diff --git a/src/burner/sdl/neocdlist.cpp b/src/burner/sdl/neocdlist.cpp
deleted file mode 100644
index 7dffd5a94..000000000
--- a/src/burner/sdl/neocdlist.cpp
+++ /dev/null
@@ -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;
- }
-}
diff --git a/src/burner/win32/burner_win32.h b/src/burner/win32/burner_win32.h
index 60e17f6d7..0194280a9 100644
--- a/src/burner/win32/burner_win32.h
+++ b/src/burner/win32/burner_win32.h
@@ -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
diff --git a/src/burner/win32/meson.build b/src/burner/win32/meson.build
index 3b1f3366e..dcb5d65ea 100644
--- a/src/burner/win32/meson.build
+++ b/src/burner/win32/meson.build
@@ -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',
diff --git a/src/burner/win32/neocdlist.cpp b/src/burner/win32/neocdlist.cpp
deleted file mode 100644
index 28d3954e7..000000000
--- a/src/burner/win32/neocdlist.cpp
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/src/burner/win32/neocdsel.cpp b/src/burner/win32/neocdsel.cpp
index 727d62128..ad7e95bbe 100644
--- a/src/burner/win32/neocdsel.cpp
+++ b/src/burner/win32/neocdsel.cpp
@@ -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');
diff --git a/src/burner/win32/scrn.cpp b/src/burner/win32/scrn.cpp
index 99c2cbab3..05f4c5f76 100644
--- a/src/burner/win32/scrn.cpp
+++ b/src/burner/win32/scrn.cpp
@@ -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);
diff --git a/src/intf/cd/cd_chd.cpp b/src/intf/cd/cd_chd.cpp
index 13b9805e6..03002b13b 100644
--- a/src/intf/cd/cd_chd.cpp
+++ b/src/intf/cd/cd_chd.cpp
@@ -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);
}
diff --git a/src/intf/cd/cd_chd.h b/src/intf/cd/cd_chd.h
index 4c3ec113c..69adad4d3 100644
--- a/src/intf/cd/cd_chd.h
+++ b/src/intf/cd/cd_chd.h
@@ -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);
diff --git a/src/intf/cd/cd_img.cpp b/src/intf/cd/cd_img.cpp
index b09b5ad92..480b22021 100644
--- a/src/intf/cd/cd_img.cpp
+++ b/src/intf/cd/cd_img.cpp
@@ -31,41 +31,622 @@ const INT32 CD_TYPE_BINCUE = 1 << 1;
const INT32 CD_TYPE_CCD = 1 << 2;
const INT32 CD_TYPE_CHD = 1 << 3;
-static INT32 cd_pregap;
-static double cd_volume = 100.0;
+struct CDImageFile {
+ TCHAR szPath[MAX_PATH];
+ FILE* pFile;
+ INT64 nSectors;
+};
-struct MSF { UINT8 M; UINT8 S; UINT8 F; };
+struct CDImage {
+ TCHAR szPath[MAX_PATH];
+ INT32 nType;
+ INT32 nTrackCount;
+ INT32 nAudioTrackCount;
+ INT32 nSectorCount;
+ INT32 nFileCount;
+ CDImageFile Files[MAXIMUM_NUMBER_TRACKS];
+ CDImageTrack Tracks[MAXIMUM_NUMBER_TRACKS];
+ INT32 nFile[MAXIMUM_NUMBER_TRACKS];
+ INT32 nFileLBA[MAXIMUM_NUMBER_TRACKS];
+ INT32 nIndex0FileLBA[MAXIMUM_NUMBER_TRACKS];
+ INT32 nExplicitPregap[MAXIMUM_NUMBER_TRACKS];
+ INT32 nChdType[MAXIMUM_NUMBER_TRACKS];
+ ChdImage* pChd;
+};
-struct cdimgTRACK_DATA { UINT8 Control; UINT8 TrackNumber; UINT8 Address[4]; UINT8 EndAddress[4]; };
-struct cdimgCDROM_TOC { UINT8 FirstTrack; UINT8 LastTrack; UINT8 ImageType; TCHAR Image[MAX_PATH]; cdimgTRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS + 1]; };
+static INT32 cdimgCopyPath(TCHAR* dst, size_t count, const TCHAR* src);
+static INT32 cdimgReplaceExtension(TCHAR* path, size_t count, const TCHAR* extension);
+
+static INT32 CDImageParseMSF(const TCHAR* szText, INT32* pnLba)
+{
+ TCHAR* pEnd;
+ INT32 nMinute = _tcstol(szText, &pEnd, 10);
+ if (pEnd == szText || *pEnd++ != _T(':'))
+ return 1;
+
+ TCHAR* pSecond = pEnd;
+ INT32 nSecond = _tcstol(pSecond, &pEnd, 10);
+ if (pEnd == pSecond || *pEnd++ != _T(':'))
+ return 1;
+
+ TCHAR* pFrame = pEnd;
+ INT32 nFrame = _tcstol(pFrame, &pEnd, 10);
+ while (*pEnd == _T(' ') || *pEnd == _T('\t'))
+ pEnd++;
+
+ if (pEnd == pFrame || *pEnd || nMinute < 0 || nSecond < 0 || nSecond > 59 || nFrame < 0 || nFrame > 74)
+ return 1;
+
+ *pnLba = nMinute * CD_FRAMES_MINUTE + nSecond * CD_FRAMES_SECOND + nFrame;
+ return 0;
+}
+
+static INT32 CDImageResolvePath(TCHAR* szDest, const TCHAR* szImage, const TCHAR* szFile)
+{
+ if (!szDest || !szImage || !szFile)
+ return 1;
+
+ if (szFile[0] == _T('/') || szFile[0] == _T('\\') || (_tcslen(szFile) > 1 && szFile[1] == _T(':'))) {
+ return cdimgCopyPath(szDest, MAX_PATH, szFile);
+ }
+ const TCHAR* pSlash = _tcsrchr(szImage, _T('/'));
+ const TCHAR* pBackslash = _tcsrchr(szImage, _T('\\'));
+ if (!pSlash || (pBackslash && pBackslash > pSlash))
+ pSlash = pBackslash;
+
+ size_t nDirectory = pSlash ? (size_t)(pSlash - szImage + 1) : 0;
+ if (nDirectory + _tcslen(szFile) >= MAX_PATH)
+ return 1;
+
+ if (nDirectory)
+ memcpy(szDest, szImage, nDirectory * sizeof(TCHAR));
+
+ _tcscpy(szDest + nDirectory, szFile);
+ return 0;
+}
+
+static void CDImageCloseFiles(CDImage* pImage)
+{
+ if (!pImage)
+ return;
+
+ for (INT32 i = 0; i < pImage->nFileCount; i++) {
+ if (pImage->Files[i].pFile)
+ fclose(pImage->Files[i].pFile);
+ pImage->Files[i].pFile = NULL;
+ }
+}
+
+static INT32 CDImageOpenBinary(CDImageFile* pFile)
+{
+ pFile->pFile = _tfopen(pFile->szPath, _T("rb"));
+ if (!pFile->pFile)
+ return 1;
+
+ if (cdimgFseek(pFile->pFile, 0, SEEK_END)) {
+ fclose(pFile->pFile);
+ pFile->pFile = NULL;
+ return 1;
+ }
+ INT64 nSize = cdimgFtell(pFile->pFile);
+ if (nSize < 0 || cdimgFseek(pFile->pFile, 0, SEEK_SET)) {
+ fclose(pFile->pFile);
+ pFile->pFile = NULL;
+ return 1;
+ }
+ pFile->nSectors = nSize;
+ return 0;
+}
+
+static INT32 CDImageParseCue(CDImage* pImage)
+{
+ FILE* pCue = _tfopen(pImage->szPath, _T("rt"));
+ if (!pCue)
+ return 1;
+
+ TCHAR szLine[1024];
+ INT32 nFile = -1;
+ INT32 nTrack = -1;
+ INT32 nDiscBase = 0;
+ INT32 nCurrentFile = -1;
+ INT32 nFileBase = 0;
+ INT32 nVirtualGap = 0;
+ UINT8 Index1Seen[MAXIMUM_NUMBER_TRACKS] = { 0 };
+ while (_fgetts(szLine, ARRAY_SIZE(szLine), pCue)) {
+ INT32 nLength = (INT32)_tcslen(szLine);
+ while (nLength && (szLine[nLength - 1] == _T('\r') || szLine[nLength - 1] == _T('\n')))
+ szLine[--nLength] = 0;
+
+ TCHAR* p = szLine;
+ TCHAR* pLabel;
+ if ((pLabel = LabelCheck(p, _T("FILE"))) != NULL) {
+ TCHAR* pName = NULL;
+ TCHAR* pEnd = NULL;
+ if (pImage->nFileCount >= MAXIMUM_NUMBER_TRACKS || QuoteRead(&pName, &pEnd, pLabel) || !pName || !pEnd)
+ goto fail;
+
+ while (*pEnd == _T(' ') || *pEnd == _T('\t'))
+ pEnd++;
+ if (_tcsncmp(pEnd, _T("BINARY"), 6))
+ goto fail;
+
+ pEnd += 6;
+ while (*pEnd == _T(' ') || *pEnd == _T('\t'))
+ pEnd++;
+ if (*pEnd)
+ goto fail;
+
+ nFile = pImage->nFileCount++;
+ if (CDImageResolvePath(pImage->Files[nFile].szPath, pImage->szPath, pName) || CDImageOpenBinary(&pImage->Files[nFile]))
+ goto fail;
+
+ continue;
+ }
+ if ((pLabel = LabelCheck(p, _T("TRACK"))) != NULL) {
+ if (nFile < 0 || pImage->nTrackCount >= MAXIMUM_NUMBER_TRACKS)
+ goto fail;
+ TCHAR* pEnd;
+ INT32 nNumber = _tcstol(pLabel, &pEnd, 10);
+ if (nNumber != pImage->nTrackCount + 1)
+ goto fail;
+
+ while (*pEnd == _T(' ') || *pEnd == _T('\t')) pEnd++;
+ nTrack = pImage->nTrackCount++;
+ CDImageTrack* pTrack = &pImage->Tracks[nTrack];
+ pTrack->nNumber = nNumber;
+ pTrack->nIndex0LBA = -1;
+ pTrack->nControl = 0x41;
+ if (!_tcscmp(pEnd, _T("AUDIO"))) {
+ pTrack->nType = CDIMAGE_TRACK_AUDIO;
+ pTrack->nControl = 0x01;
+ pTrack->nSectorSize = pTrack->nUserSize = 2352;
+ pImage->nAudioTrackCount++;
+ } else if (!_tcscmp(pEnd, _T("MODE1/2048"))) {
+ pTrack->nType = CDIMAGE_TRACK_MODE1_2048;
+ pTrack->nSectorSize = pTrack->nUserSize = 2048;
+ pTrack->nUserOffset = 16;
+ } else if (!_tcscmp(pEnd, _T("MODE1/2352"))) {
+ pTrack->nType = CDIMAGE_TRACK_MODE1_2352;
+ pTrack->nSectorSize = 2352;
+ pTrack->nUserOffset = 16;
+ pTrack->nUserSize = 2048;
+ } else if (!_tcscmp(pEnd, _T("MODE2/2336"))) {
+ pTrack->nType = CDIMAGE_TRACK_MODE2_2336;
+ pTrack->nSectorSize = pTrack->nUserSize = 2336;
+ pTrack->nUserOffset = 16;
+ } else if (!_tcscmp(pEnd, _T("MODE2/2352")) || !_tcscmp(pEnd, _T("CDI/2352"))) {
+ pTrack->nType = CDIMAGE_TRACK_MODE2_2352;
+ pTrack->nSectorSize = 2352;
+ pTrack->nUserOffset = 16;
+ pTrack->nUserSize = 2336;
+ } else
+ goto fail;
+
+ pImage->nFile[nTrack] = nFile;
+ pTrack->szPath = pImage->Files[nFile].szPath;
+ continue;
+ }
+ if ((pLabel = LabelCheck(p, _T("INDEX 00"))) != NULL) {
+ if (nTrack < 0 || CDImageParseMSF(pLabel, &pImage->nIndex0FileLBA[nTrack]))
+ goto fail;
+
+ continue;
+ }
+ if ((pLabel = LabelCheck(p, _T("INDEX 01"))) != NULL) {
+ if (nTrack < 0 || Index1Seen[nTrack] || CDImageParseMSF(pLabel, &pImage->nFileLBA[nTrack]))
+ goto fail;
+
+ Index1Seen[nTrack] = 1;
+ continue;
+ }
+ if ((pLabel = LabelCheck(p, _T("PREGAP"))) != NULL) {
+ if (nTrack < 0 || CDImageParseMSF(pLabel, &pImage->nExplicitPregap[nTrack]))
+ goto fail;
+ }
+ }
+ fclose(pCue);
+ if (!pImage->nTrackCount)
+ return 1;
+
+ for (INT32 i = 0; i < pImage->nTrackCount; i++)
+ if (!Index1Seen[i])
+ return 1;
+
+ for (INT32 i = 0; i < pImage->nFileCount; i++) {
+ INT32 nSectorSize = 0;
+ for (INT32 j = 0; j < pImage->nTrackCount; j++) {
+ if (pImage->nFile[j] != i)
+ continue;
+ if (nSectorSize && nSectorSize != pImage->Tracks[j].nSectorSize)
+ return 1;
+ nSectorSize = pImage->Tracks[j].nSectorSize;
+ }
+
+ if (!nSectorSize || pImage->Files[i].nSectors % nSectorSize)
+ return 1;
+
+ pImage->Files[i].nSectors /= nSectorSize;
+ }
+ for (INT32 i = 0; i < pImage->nTrackCount; i++) {
+ if (pImage->nFile[i] != nCurrentFile) {
+ nCurrentFile = pImage->nFile[i];
+ nFileBase = nDiscBase;
+ nVirtualGap = 0;
+ }
+ nVirtualGap += pImage->nExplicitPregap[i];
+ CDImageTrack* pTrack = &pImage->Tracks[i];
+ pTrack->nIndex1LBA = nFileBase + pImage->nFileLBA[i] + nVirtualGap;
+ pTrack->nStartLBA = pTrack->nIndex1LBA;
+ if (pImage->nIndex0FileLBA[i] >= 0)
+ pTrack->nIndex0LBA = nFileBase + pImage->nIndex0FileLBA[i] + nVirtualGap;
+ else
+ pTrack->nIndex0LBA = pTrack->nIndex1LBA - pImage->nExplicitPregap[i];
+
+ pTrack->nPregap = pTrack->nIndex1LBA - pTrack->nIndex0LBA;
+ nDiscBase = nFileBase + (INT32)pImage->Files[nCurrentFile].nSectors + nVirtualGap;
+ }
+ pImage->nSectorCount = nDiscBase;
+ for (INT32 i = 0; i < pImage->nTrackCount; i++) {
+ INT32 nEnd = i + 1 < pImage->nTrackCount ? pImage->Tracks[i + 1].nIndex0LBA : pImage->nSectorCount;
+ pImage->Tracks[i].nSectors = nEnd - pImage->Tracks[i].nStartLBA;
+ }
+ return 0;
+
+fail:
+ fclose(pCue);
+ return 1;
+}
+
+static inline UINT8 CDImageBcd(UINT8 nValue)
+{
+ return ((nValue >> 4) * 10) + (nValue & 15);
+}
+
+static INT32 CDImageParseCcd(CDImage* pImage)
+{
+ TCHAR szSub[MAX_PATH];
+ if (cdimgCopyPath(szSub, MAX_PATH, pImage->szPath) || cdimgReplaceExtension(szSub, MAX_PATH, _T(".sub")))
+ return 1;
+ if (pImage->nFileCount >= 1 || cdimgCopyPath(pImage->Files[0].szPath, MAX_PATH, pImage->szPath) || cdimgReplaceExtension(pImage->Files[0].szPath, MAX_PATH, _T(".img")) || CDImageOpenBinary(&pImage->Files[0]))
+ return 1;
+
+ pImage->nFileCount = 1;
+ FILE* pSub = _tfopen(szSub, _T("rb"));
+ if (!pSub || cdimgFseek(pSub, 0, SEEK_END)) {
+ if (pSub)
+ fclose(pSub);
+
+ return 1;
+ }
+ INT64 nSize = cdimgFtell(pSub);
+ if (nSize < 96 || nSize % 96 || cdimgFseek(pSub, 0, SEEK_SET)) {
+ fclose(pSub);
+ return 1;
+ }
+ UINT8 Sub[96];
+ INT32 nLastTrack = 0;
+ INT32 nIndex1Base = -1;
+ while (fread(Sub, 1, sizeof(Sub), pSub) == sizeof(Sub)) {
+ UINT8* pQ = Sub + 12;
+ INT32 nAbsolute = CDImageBcd(pQ[7]) * CD_FRAMES_MINUTE + CDImageBcd(pQ[8]) * CD_FRAMES_SECOND + CDImageBcd(pQ[9]);
+ INT32 nTrack = CDImageBcd(pQ[1]);
+ INT32 nIndex = CDImageBcd(pQ[2]);
+ if (nIndex == 1 && nTrack == nLastTrack + 1 && nTrack <= MAXIMUM_NUMBER_TRACKS) {
+ CDImageTrack* pTrack = &pImage->Tracks[nLastTrack];
+ pTrack->nNumber = nTrack; pTrack->nControl = pQ[0]; pTrack->nType = (pQ[0] & 0x40) ? CDIMAGE_TRACK_MODE1_2352 : CDIMAGE_TRACK_AUDIO;
+ pTrack->nSectorSize = 2352; pTrack->nUserOffset = pTrack->nType == CDIMAGE_TRACK_AUDIO ? 0 : 16; pTrack->nUserSize = pTrack->nType == CDIMAGE_TRACK_AUDIO ? 2352 : 2048;
+ if (nIndex1Base < 0)
+ nIndex1Base = nAbsolute;
+ pTrack->nStartLBA = pTrack->nIndex1LBA = nAbsolute - nIndex1Base;
+ pTrack->nIndex0LBA = pTrack->nStartLBA; pTrack->szPath = pImage->Files[0].szPath; pImage->nFile[nLastTrack] = 0; pImage->nFileLBA[nLastTrack] = nAbsolute - nIndex1Base;
+ if (pTrack->nType == CDIMAGE_TRACK_AUDIO)
+ pImage->nAudioTrackCount++;
+
+ nLastTrack++;
+ }
+ }
+ fclose(pSub);
+ pImage->nTrackCount = nLastTrack;
+ pImage->Files[0].nSectors /= 2352;
+ pImage->nSectorCount = (INT32)pImage->Files[0].nSectors;
+ for (INT32 i = 0; i < nLastTrack; i++)
+ pImage->Tracks[i].nSectors = (i + 1 < nLastTrack ? pImage->Tracks[i + 1].nStartLBA : pImage->nSectorCount) - pImage->Tracks[i].nStartLBA;
+
+ return nLastTrack ? 0 : 1;
+}
+
+static INT32 CDImageParseRaw(CDImage* pImage)
+{
+ pImage->nFileCount = 1;
+ if (cdimgCopyPath(pImage->Files[0].szPath, MAX_PATH, pImage->szPath) || CDImageOpenBinary(&pImage->Files[0]) || pImage->Files[0].nSectors % 2352)
+ return 1;
+
+ pImage->Files[0].nSectors /= 2352;
+ pImage->nTrackCount = 1;
+ pImage->nSectorCount = (INT32)pImage->Files[0].nSectors;
+
+ CDImageTrack* pTrack = &pImage->Tracks[0];
+ pTrack->nNumber = 1;
+ pTrack->nType = CDIMAGE_TRACK_MODE1_2352;
+ pTrack->nControl = 0x41;
+ pTrack->nIndex0LBA = pTrack->nIndex1LBA = pTrack->nStartLBA = 0;
+ pTrack->nSectors = pImage->nSectorCount;
+ pTrack->nSectorSize = 2352;
+ pTrack->nUserOffset = 16;
+ pTrack->nUserSize = 2048;
+ pTrack->szPath = pImage->Files[0].szPath;
+ return 0;
+}
+
+static INT32 CDImageParseChd(CDImage* pImage)
+{
+ pImage->pChd = ChdOpenFile(pImage->szPath);
+ if (!pImage->pChd || (ChdGetContainerType(pImage->pChd) != CHD_CONTAINER_CD && ChdGetContainerType(pImage->pChd) != CHD_CONTAINER_GDROM))
+ return 1;
+
+ pImage->nTrackCount = ChdGetNumTracks(pImage->pChd);
+ pImage->nSectorCount = ChdGetTotalFrames(pImage->pChd);
+ if (pImage->nTrackCount < 1 || pImage->nTrackCount > MAXIMUM_NUMBER_TRACKS)
+ return 1;
+
+ for (INT32 i = 0; i < pImage->nTrackCount; i++) {
+ const ChdTrack* pChdTrack = ChdGetTrack(pImage->pChd, i);
+ CDImageTrack* pTrack = &pImage->Tracks[i];
+ pTrack->nNumber = i + 1; pTrack->nControl = pChdTrack->nControl; pTrack->nStartLBA = pTrack->nIndex1LBA = pChdTrack->nLogFrameOfs;
+ pTrack->nIndex0LBA = pTrack->nIndex1LBA - pChdTrack->nPregap; pTrack->nPregap = pChdTrack->nPregap; pTrack->nSectors = pChdTrack->nLogFrames;
+ pTrack->nSectorSize = pChdTrack->nDataSize; pTrack->szPath = pImage->szPath;
+
+ pImage->nChdType[i] = pChdTrack->nType;
+ if (pChdTrack->nType == CHD_TRACK_AUDIO) {
+ pTrack->nType = CDIMAGE_TRACK_AUDIO;
+ pTrack->nUserSize = 2352;
+ pImage->nAudioTrackCount++;
+ } else if (pChdTrack->nType == CHD_TRACK_MODE1) {
+ pTrack->nType = CDIMAGE_TRACK_MODE1_2048;
+ pTrack->nUserSize = 2048;
+ } else if (pChdTrack->nType == CHD_TRACK_MODE1_RAW) {
+ pTrack->nType = CDIMAGE_TRACK_MODE1_2352;
+ pTrack->nUserOffset = 16;
+ pTrack->nUserSize = 2048;
+ } else if (pChdTrack->nType == CHD_TRACK_MODE2) {
+ pTrack->nType = CDIMAGE_TRACK_MODE2_2336;
+ pTrack->nUserSize = 2336;
+ } else {
+ pTrack->nType = CDIMAGE_TRACK_MODE2_2352;
+ pTrack->nUserOffset = pChdTrack->nType == CHD_TRACK_MODE2_RAW ? 16 : 0;
+ pTrack->nUserSize = pChdTrack->nDataSize; }
+ }
+ for (INT32 i = 0; i < pImage->nTrackCount; i++) {
+ pImage->Tracks[i].nSectors = (i + 1 < pImage->nTrackCount ? pImage->Tracks[i + 1].nStartLBA : pImage->nSectorCount) - pImage->Tracks[i].nStartLBA;
+ }
+ return 0;
+}
+
+CDImage* CDImageOpen(const TCHAR* szPath)
+{
+ if (!szPath || !*szPath)
+ return NULL;
+
+ CDImage* pImage = (CDImage*)calloc(1, sizeof(CDImage));
+ if (!pImage || cdimgCopyPath(pImage->szPath, MAX_PATH, szPath)) {
+ free(pImage);
+ return NULL;
+ }
+
+ INT32 nError = 1;
+ if (IsFileExt(pImage->szPath, _T(".cue"))) {
+ pImage->nType = CD_TYPE_BINCUE;
+ nError = CDImageParseCue(pImage);
+ } else if (IsFileExt(pImage->szPath, _T(".ccd"))) {
+ pImage->nType = CD_TYPE_CCD;
+ nError = CDImageParseCcd(pImage);
+ } else if (IsFileExt(pImage->szPath, _T(".chd"))) {
+ pImage->nType = CD_TYPE_CHD;
+ nError = CDImageParseChd(pImage);
+ } else if (IsFileExt(pImage->szPath, _T(".bin")) || IsFileExt(pImage->szPath, _T(".img"))) {
+ pImage->nType = CD_TYPE_BINCUE;
+ nError = CDImageParseRaw(pImage);
+ }
+ if (nError) {
+ CDImageClose(pImage);
+ return NULL;
+ }
+ return pImage;
+}
+
+void CDImageClose(CDImage* pImage)
+{
+ if (!pImage)
+ return;
+
+ CDImageCloseFiles(pImage);
+ if (pImage->pChd)
+ ChdClose(pImage->pChd);
+
+ free(pImage);
+}
+
+INT32 CDImageGetTrackCount(const CDImage* pImage)
+{
+ return pImage ? pImage->nTrackCount : 0;
+}
+
+INT32 CDImageGetAudioTrackCount(const CDImage* pImage)
+{
+ return pImage ? pImage->nAudioTrackCount : 0;
+}
+
+INT32 CDImageGetSectorCount(const CDImage* pImage)
+{
+ return pImage ? pImage->nSectorCount : 0;
+}
+
+const TCHAR* CDImageGetPath(const CDImage* pImage)
+{
+ return pImage ? pImage->szPath : NULL;
+}
+
+const CDImageTrack* CDImageGetTrack(const CDImage* pImage, INT32 nTrack)
+{
+ return pImage && nTrack >= 0 && nTrack < pImage->nTrackCount ? &pImage->Tracks[nTrack] : NULL;
+}
+
+static INT32 CDImageFindTrack(const CDImage* pImage, INT32 nLba)
+{
+ if (!pImage || nLba < 0 || nLba >= pImage->nSectorCount)
+ return -1;
+
+ for (INT32 i = pImage->nTrackCount - 1; i >= 0; i--)
+ if (nLba >= pImage->Tracks[i].nIndex0LBA)
+ return i;
+
+ return -1;
+}
+
+INT32 CDImageReadRawSector(CDImage* pImage, INT32 nLba, UINT8* pDest)
+{
+ if (!pImage || !pDest)
+ return 1;
+
+ INT32 nTrack = CDImageFindTrack(pImage, nLba);
+ if (nTrack < 0)
+ return 1;
+
+ CDImageTrack* pTrack = &pImage->Tracks[nTrack];
+ if (pImage->pChd) {
+ INT32 nType = pImage->nChdType[nTrack];
+ if (nType == CHD_TRACK_AUDIO)
+ return ChdReadSector(pImage->pChd, nLba, CHD_TRACK_RAW_DONTCARE, pDest);
+ if (nType == CHD_TRACK_MODE1 || nType == CHD_TRACK_MODE1_RAW)
+ return ChdReadSector(pImage->pChd, nLba, CHD_TRACK_MODE1_RAW, pDest);
+ if (nType == CHD_TRACK_MODE2_RAW)
+ return ChdReadSector(pImage->pChd, nLba, CHD_TRACK_RAW_DONTCARE, pDest);
+
+ memset(pDest, 0, 2352);
+ INT32 nOffset = nType == CHD_TRACK_MODE2_FORM1 || nType == CHD_TRACK_MODE2_FORM2 ? 24 : 16;
+ return ChdReadSector(pImage->pChd, nLba, CHD_TRACK_RAW_DONTCARE, pDest + nOffset);
+ }
+ if (nLba < pTrack->nIndex1LBA && pImage->nExplicitPregap[nTrack]) {
+ memset(pDest, 0, 2352);
+ return 0;
+ }
+ INT32 nFileLba = pImage->nFileLBA[nTrack] + nLba - pTrack->nIndex1LBA;
+ if (nFileLba < 0)
+ return 1;
+
+ CDImageFile* pFile = &pImage->Files[pImage->nFile[nTrack]];
+ if (cdimgFseek(pFile->pFile, (INT64)nFileLba * pTrack->nSectorSize, SEEK_SET))
+ return 1;
+
+ if (pTrack->nSectorSize == 2352)
+ return fread(pDest, 1, 2352, pFile->pFile) == 2352 ? 0 : 1;
+
+ memset(pDest, 0, 2352);
+ return fread(pDest + 16, 1, pTrack->nSectorSize, pFile->pFile) == (size_t)pTrack->nSectorSize ? 0 : 1;
+}
+
+INT32 CDImageReadUserSector(CDImage* pImage, INT32 nLba, UINT8* pDest, INT32* pnSize)
+{
+ if (!pImage || !pDest)
+ return 1;
+
+ INT32 nTrack = CDImageFindTrack(pImage, nLba);
+ if (nTrack < 0)
+ return 1;
+
+ CDImageTrack* pTrack = &pImage->Tracks[nTrack];
+ if (pTrack->nType == CDIMAGE_TRACK_AUDIO)
+ return 1;
+
+ UINT8 Raw[2352];
+ if (pImage->pChd) {
+ INT32 nType = pImage->nChdType[nTrack];
+ if (pTrack->nUserSize == 2048 && (nType == CHD_TRACK_MODE1 || nType == CHD_TRACK_MODE1_RAW))
+ nType = CHD_TRACK_MODE1;
+ else if (pTrack->nUserSize == 2336)
+ nType = CHD_TRACK_MODE2;
+ else
+ nType = CHD_TRACK_RAW_DONTCARE;
+
+ if (ChdReadSector(pImage->pChd, nLba, nType, pDest))
+ return 1;
+ } else {
+ if (CDImageReadRawSector(pImage, nLba, Raw))
+ return 1;
+
+ memcpy(pDest, Raw + pTrack->nUserOffset, pTrack->nUserSize);
+ }
+ if (pnSize)
+ *pnSize = pTrack->nUserSize;
+
+ return 0;
+}
+
+INT32 CDImageGetChdSha1(const CDImage* pImage, UINT8* pSha1)
+{
+ return pImage && pImage->pChd ? ChdGetSha1(pImage->pChd, pSha1) : 1;
+}
+
+static CDImage* cdimgImage = NULL;
+static INT32 cd_pregap;
+static double cd_volume = 100.0;
+
+struct MSF {
+ UINT8 M;
+ UINT8 S;
+ UINT8 F;
+};
+
+struct cdimgTRACK_DATA {
+ UINT8 Control;
+ UINT8 TrackNumber;
+ UINT8 Address[4];
+ UINT8 EndAddress[4];
+};
+
+struct cdimgCDROM_TOC {
+ UINT8 FirstTrack;
+ UINT8 LastTrack;
+ UINT8 ImageType;
+ TCHAR Image[MAX_PATH];
+ cdimgTRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS + 1];
+};
static cdimgCDROM_TOC* cdimgTOC;
-static FILE* cdimgFile = NULL;
-static ChdImage* cdimgChd = NULL;
-static INT32 cdimgChdTrackLBA[MAXIMUM_NUMBER_TRACKS]; // logical LBA of each track start
-static INT32 cdimgTrack = 0;
-static INT32 cdimgLBA = 0;
+static FILE* cdimgFile = NULL;
+static ChdImage* cdimgChd = NULL;
+static INT32 cdimgChdTrackLBA[MAXIMUM_NUMBER_TRACKS]; // logical LBA of each track start
+static INT32 cdimgTrack = 0;
+static INT32 cdimgLBA = 0;
-static INT32 cdimgSamples = 0;
+static INT32 cdimgSamples = 0;
-static INT32 re_sync = 0;
+static INT32 re_sync = 0;
// identical to the format used in clonecd .sub files, can use memcpy
-struct QData { UINT8 Control; char track; char index; MSF MSFrel; char unused; MSF MSFabs; UINT16 CRC; };
+struct QData {
+ UINT8 Control;
+ char track;
+ char index;
+ MSF MSFrel;
+ char unused;
+ MSF MSFabs;
+ UINT16 CRC;
+};
-static QData* QChannel = NULL;
-static INT32 QChannelCount = 0;
+static QData* QChannel = NULL;
+static INT32 QChannelCount = 0;
// -----------------------------------------------------------------------------
-const INT32 cdimgOUT_SIZE = 2352;
+const INT32 cdimgOUT_SIZE = 2352;
static INT32 cdimgOutputbufferSize = 0;
-static INT16* cdimgOutputbuffer = NULL;
+static INT16* cdimgOutputbuffer = NULL;
static INT32 cdimgOutputPosition;
-static INT32 cdimgAudioFilePos; // Track audio read position within file (file sector index)
+static INT32 cdimgAudioFilePos; // Track audio read position within file (file sector index)
// -----------------------------------------------------------------------------
@@ -76,6 +657,9 @@ static INT32 cdimgAudioFilePos; // Track audio read position within file (file
#ifdef BUILD_NEOGEO
TCHAR* GetIsoPath()
{
+ if (cdimgImage) {
+ return (TCHAR*)CDImageGetPath(cdimgImage);
+ }
if (cdimgTOC) {
return cdimgTOC->Image;
}
@@ -165,9 +749,8 @@ static INT32 cdimgInitStream()
static INT32 cdimgCopyPath(TCHAR* dst, size_t count, const TCHAR* src)
{
- if (!dst || !src || count == 0 || _tcslen(src) >= count) {
+ if (!dst || !src || count == 0 || _tcslen(src) >= count)
return 1;
- }
_tcscpy(dst, src);
return 0;
@@ -177,14 +760,12 @@ static INT32 cdimgReplaceExtension(TCHAR* path, size_t count, const TCHAR* exten
{
size_t length;
- if (!path || !extension || count == 0) {
+ if (!path || !extension || count == 0)
return 1;
- }
length = _tcslen(path);
- if (length < 4 || _tcslen(extension) != 4) {
+ if (length < 4 || _tcslen(extension) != 4)
return 1;
- }
_tcscpy(path + length - 4, extension);
return 0;
@@ -211,7 +792,7 @@ static void cdimgPrintImageInfo()
const UINT8* addressUNBCD = dinkLBAToMSF(cdimgMSFToLBA(cdimgTOC->TrackData[trk].Address));
if (trk != cdimgTOC->LastTrack) {
- bprintf(0, _T("Track %02d: %02d:%02d:%02d\n"), trk + 1, addressUNBCD[1], addressUNBCD[2], addressUNBCD[3]);
+ bprintf(0, _T("Track %02d: %02d:%02d:%02d\n"), trk + 1, addressUNBCD[1], addressUNBCD[2], addressUNBCD[3]);
} else {
bprintf(0, _T(" total running time %02i:%02i:%02i\n"), addressUNBCD[1], addressUNBCD[2], addressUNBCD[3]);
}
@@ -247,10 +828,10 @@ static INT32 cdimgAddLastTrack()
// parse .sub file and build a TOC based in Q sub channel data
static INT32 cdimgParseSubFile()
{
- TCHAR filenameSub[MAX_PATH];
- FILE* h = NULL;
+ TCHAR filenameSub[MAX_PATH];
+ FILE* h = NULL;
UINT8* subData = NULL;
- INT32 track = 0;
+ INT32 track = 0;
if (cdimgCopyPath(filenameSub, MAX_PATH, CDEmuImage) ||
(!IsFileExt(filenameSub, _T(".ccd")) && !IsFileExt(filenameSub, _T(".img")) && !IsFileExt(filenameSub, _T(".sub"))) ||
@@ -268,7 +849,9 @@ static INT32 cdimgParseSubFile()
h = _tfopen(filenameSub, _T("rb"));
if (!h || cdimgFseek(h, 0, SEEK_END) != 0) {
- if (h) fclose(h);
+ if (h)
+ fclose(h);
+
return 1;
}
@@ -279,18 +862,19 @@ static INT32 cdimgParseSubFile()
}
QChannelCount = (INT32)(size64 / 96);
- subData = (UINT8*)malloc((size_t)size64);
+ subData = (UINT8*)malloc((size_t)size64);
QChannel = (QData*)calloc(QChannelCount, sizeof(QData));
if (!subData || !QChannel || fread(subData, 1, (size_t)size64, h) != (size_t)size64) {
fclose(h);
free_s((void**)&subData);
- free_s((void**)&QChannel);
+ free(QChannel);
+ QChannel = NULL;
QChannelCount = 0;
return 1;
}
fclose(h);
- cdimgTOC->ImageType = CD_TYPE_CCD;
+ cdimgTOC->ImageType = CD_TYPE_CCD;
cdimgTOC->FirstTrack = 1;
for (INT32 i = 0; i < QChannelCount; i++) {
memcpy(&QChannel[i], subData + i * 96 + 12, 12);
@@ -298,17 +882,18 @@ static INT32 cdimgParseSubFile()
if (QChannel[i].index && (QChannel[i].Control & 1) && current >= 1 && current <= MAXIMUM_NUMBER_TRACKS &&
current == track + 1 && cdimgTOC->TrackData[current - 1].TrackNumber == 0) {
track = current;
- cdimgTOC->TrackData[track - 1].Control = QChannel[i].Control;
+ cdimgTOC->TrackData[track - 1].Control = QChannel[i].Control;
cdimgTOC->TrackData[track - 1].TrackNumber = (UINT8)QChannel[i].track;
- cdimgTOC->TrackData[track - 1].Address[1] = QChannel[i].MSFabs.M;
- cdimgTOC->TrackData[track - 1].Address[2] = QChannel[i].MSFabs.S;
- cdimgTOC->TrackData[track - 1].Address[3] = QChannel[i].MSFabs.F;
+ cdimgTOC->TrackData[track - 1].Address[1] = QChannel[i].MSFabs.M;
+ cdimgTOC->TrackData[track - 1].Address[2] = QChannel[i].MSFabs.S;
+ cdimgTOC->TrackData[track - 1].Address[3] = QChannel[i].MSFabs.F;
}
}
free_s((void**)&subData);
if (track == 0) {
- free_s((void**)&QChannel);
+ free(QChannel);
+ QChannel = NULL;
QChannelCount = 0;
return 1;
}
@@ -320,15 +905,15 @@ static INT32 cdimgParseSubFile()
static INT32 cdimgParseCueFile()
{
- TCHAR szLine[1024];
- TCHAR szFile[MAX_PATH];
+ TCHAR szLine[1024];
+ TCHAR szFile[MAX_PATH];
TCHAR* s;
TCHAR* t;
- FILE* h;
- INT32 track = 0;
- INT32 length;
- INT32 fileCount = 0;
- UINT8 indexSeen[MAXIMUM_NUMBER_TRACKS] = { 0 };
+ FILE* h;
+ INT32 track = 0;
+ INT32 length;
+ INT32 fileCount = 0;
+ UINT8 indexSeen[MAXIMUM_NUMBER_TRACKS] = { 0 };
cdimgTOC->ImageType = CD_TYPE_BINCUE;
cdimgTOC->FirstTrack = 1;
@@ -338,7 +923,7 @@ static INT32 cdimgParseCueFile()
cdimgTOC->TrackData[0].Address[2] = 2;
cdimgTOC->TrackData[0].Address[3] = 0;
- cd_pregap = 150; // default for bin/cue?
+ cd_pregap = 150; // default for bin/cue?
if (cdimgCopyPath(cdimgTOC->Image, MAX_PATH, CDEmuImage) || cdimgReplaceExtension(cdimgTOC->Image, MAX_PATH, _T(".bin"))) {
return 1;
@@ -368,7 +953,7 @@ static INT32 cdimgParseCueFile()
s = t;
TCHAR* szQuote = NULL;
- TCHAR* szEnd = NULL;
+ TCHAR* szEnd = NULL;
const TCHAR* separator = _tcsrchr(CDEmuImage, _T('/'));
const TCHAR* backslash = _tcsrchr(CDEmuImage, _T('\\'));
if (!separator || (backslash && backslash > separator)) separator = backslash;
@@ -390,14 +975,16 @@ static INT32 cdimgParseCueFile()
return 1;
}
- bool absolute = szQuote[0] == _T('/') || szQuote[0] == _T('\\') ||
- (_tcslen(szQuote) > 1 && szQuote[1] == _T(':'));
- if (absolute) directoryLength = 0;
+ bool absolute = szQuote[0] == _T('/') || szQuote[0] == _T('\\') || (_tcslen(szQuote) > 1 && szQuote[1] == _T(':'));
+ if (absolute)
+ directoryLength = 0;
if (directoryLength + _tcslen(szQuote) >= MAX_PATH) {
fclose(h);
return 1;
}
- if (directoryLength) memcpy(szFile, CDEmuImage, directoryLength * sizeof(TCHAR));
+ if (directoryLength)
+ memcpy(szFile, CDEmuImage, directoryLength * sizeof(TCHAR));
+
_tcscpy(szFile + directoryLength, szQuote);
if (cdimgCopyPath(cdimgTOC->Image, MAX_PATH, szFile)) {
fclose(h);
@@ -417,12 +1004,11 @@ static INT32 cdimgParseCueFile()
fclose(h);
return 1;
}
-
if (track < cdimgTOC->FirstTrack) {
cdimgTOC->FirstTrack = track;
}
if (track > cdimgTOC->LastTrack) {
- cdimgTOC->LastTrack = track;
+ cdimgTOC->LastTrack = track;
}
cdimgTOC->TrackData[track - 1].TrackNumber = tobcd(track);
@@ -476,7 +1062,7 @@ static INT32 cdimgParseCueFile()
return 1;
}
- const UINT8 address[] = { 0, (UINT8)M, (UINT8)S, (UINT8)F };
+ const UINT8 address[] = { 0, (UINT8)M, (UINT8)S, (UINT8)F };
const UINT8* newaddress = cdimgLBAToMSF(dinkMSFToLBA(address) + cd_pregap);
//const UINT8* newaddressUNBCD = dinkLBAToMSF(dinkMSFToLBA(address) + cd_pregap);
//bprintf(0, _T("Track MSF: %02d:%02d:%02d "), newaddressUNBCD[1], newaddressUNBCD[2], newaddressUNBCD[3]);
@@ -510,19 +1096,23 @@ static INT32 cdimgExit()
if (cdimgFile)
fclose(cdimgFile);
- cdimgFile = NULL;
+ cdimgFile = NULL;
if (cdimgChd)
ChdClose(cdimgChd);
- cdimgChd = NULL;
+
+ cdimgChd = NULL;
+ CDImageClose(cdimgImage);
+ cdimgImage = NULL;
cdimgTrack = 0;
cdimgLBA = 0;
cd_volume = 100.0;
- free_s((void**)&cdimgTOC);
- free_s((void**)&QChannel);
- QChannel = NULL;
+ free(cdimgTOC);
+ cdimgTOC = NULL;
+ free(QChannel);
+ QChannel = NULL;
QChannelCount = 0;
return 0;
@@ -544,17 +1134,13 @@ static INT32 cdimgReadRawSector(INT32 lba, UINT8* dest, bool bAudio = false)
{
if (!cdimgTOC)
return 1;
-
- if (cdimgTOC->ImageType == CD_TYPE_CHD) {
- INT32 nType = bAudio ? CHD_TRACK_RAW_DONTCARE : CHD_TRACK_MODE1_RAW;
- return ChdReadSector(cdimgChd, lba, nType, dest);
- }
-
- // Fall-through: standard raw image (.bin/.cue, .ccd/.img).
+ if (cdimgImage)
+ return CDImageReadRawSector(cdimgImage, lba, dest);
if (!cdimgFile)
return 1;
if (cdimgFseek(cdimgFile, (INT64)lba * 2352, SEEK_SET) != 0)
return 1;
+
size_t n = fread(dest, 1, 2352, cdimgFile);
return (n == 2352) ? 0 : 1;
}
@@ -571,6 +1157,56 @@ INT32 cdimgCountChdAudioTracks(TCHAR* pszFile)
return ChdCountAudioTracks(pszPath);
}
+static INT32 cdimgParseImage()
+{
+ INT32 nType = IsFileExt(CDEmuImage, _T(".chd")) ? CD_TYPE_CHD : IsFileExt(CDEmuImage, _T(".ccd")) ? CD_TYPE_CCD : CD_TYPE_BINCUE;
+
+ cdimgImage = CDImageOpen(CDEmuImage);
+ if (!cdimgImage)
+ return 1;
+
+ INT32 nTracks = CDImageGetTrackCount(cdimgImage);
+ if (nTracks < 1 || nTracks > MAXIMUM_NUMBER_TRACKS)
+ return 1;
+
+ if (nType == CD_TYPE_CCD) {
+ INT32 nError = cdimgParseSubFile();
+ if (nError)
+ return nError;
+
+ for (INT32 i = 0; i < nTracks; i++) {
+ const CDImageTrack* pTrack = CDImageGetTrack(cdimgImage, i);
+ cdimgTOC->TrackData[i].EndAddress[0] = 0;
+ const UINT8* pAddress = cdimgLBAToMSF((i + 1 < nTracks ? CDImageGetTrack(cdimgImage, i + 1)->nIndex0LBA : CDImageGetSectorCount(cdimgImage)) + cd_pregap);
+ memcpy(cdimgTOC->TrackData[i].EndAddress, pAddress, 4);
+ }
+ return 0;
+ }
+
+ cdimgTOC->ImageType = nType;
+ cdimgTOC->FirstTrack = 1;
+ cdimgTOC->LastTrack = nTracks;
+
+ cd_pregap = 150;
+ for (INT32 i = 0; i < nTracks; i++) {
+ const CDImageTrack* pTrack = CDImageGetTrack(cdimgImage, i);
+ cdimgTOC->TrackData[i].Control = (UINT8)pTrack->nControl;
+ cdimgTOC->TrackData[i].TrackNumber = tobcd(i + 1);
+ const UINT8* pAddress = cdimgLBAToMSF(pTrack->nStartLBA + cd_pregap);
+ memcpy(cdimgTOC->TrackData[i].Address, pAddress, 4);
+ INT32 nEnd = i + 1 < nTracks ? CDImageGetTrack(cdimgImage, i + 1)->nIndex0LBA : CDImageGetSectorCount(cdimgImage);
+ pAddress = cdimgLBAToMSF(nEnd + cd_pregap);
+ memcpy(cdimgTOC->TrackData[i].EndAddress, pAddress, 4);
+ }
+
+ const UINT8* pLeadout = cdimgLBAToMSF(CDImageGetSectorCount(cdimgImage) + cd_pregap);
+ cdimgTOC->TrackData[nTracks].Control = 0x41;
+ cdimgTOC->TrackData[nTracks].TrackNumber = 0xaa;
+ memcpy(cdimgTOC->TrackData[nTracks].Address, pLeadout, 4);
+ const CDImageTrack* pFirst = CDImageGetTrack(cdimgImage, 0);
+ return cdimgCopyPath(cdimgTOC->Image, MAX_PATH, pFirst->szPath);
+}
+
static INT32 cdimgParseChdFile()
{
cdimgChd = ChdOpenFile(CDEmuImage);
@@ -636,7 +1272,7 @@ static INT32 cdimgParseChdFile()
// Lead-out entry, just past the last valid sector.
const UINT8* leadout = cdimgLBAToMSF(nTotal + cd_pregap);
cdimgTOC->TrackData[nTracks].Control = 0x41;
- cdimgTOC->TrackData[nTracks].TrackNumber = 0xAA;
+ cdimgTOC->TrackData[nTracks].TrackNumber = 0xaa;
cdimgTOC->TrackData[nTracks].Address[0] = 0;
cdimgTOC->TrackData[nTracks].Address[1] = leadout[1];
cdimgTOC->TrackData[nTracks].Address[2] = leadout[2];
@@ -672,32 +1308,12 @@ static INT32 cdimgInit()
return 1;
}
- if (IsFileExt(filename, _T(".cue"))) {
- if (cdimgParseCueFile()) {
- dprintf(_T("*** Couldn't parse .cue file\n"));
+ if (IsFileExt(filename, _T(".cue")) || IsFileExt(filename, _T(".ccd")) || IsFileExt(filename, _T(".chd"))) {
+ if (cdimgParseImage()) {
+ dprintf(_T("*** Couldn't parse CD image\n"));
cdimgExit();
-
return 1;
}
-
- } else
- if (IsFileExt(filename, _T(".ccd"))) {
- if (cdimgParseSubFile()) {
- dprintf(_T("*** Couldn't parse .sub file\n"));
- cdimgExit();
-
- return 1;
- }
-
- } else
- if (IsFileExt(filename, _T(".chd"))) {
- if (cdimgParseChdFile()) {
- dprintf(_T("*** Couldn't parse .chd file\n"));
- cdimgExit();
-
- return 1;
- }
-
} else {
dprintf(_T("*** Couldn't find .img / .bin file\n"));
cdimgExit();
@@ -726,7 +1342,7 @@ static INT32 cdimgInit()
// Validate the CD by scanning the ISO-9660 volume descriptor at sector 16.
// Both .bin and .chd images expose sector 16 as the first usable data sector.
- if (cdimgTOC->ImageType == CD_TYPE_CHD) {
+ if (cdimgImage != NULL) {
// Unified sector reader gives us a complete 2352-byte raw sector.
// CD001 identifier lives at byte 1 of the 2048-byte user data area,
// which is byte 17 (16 + 1) of the full 2352-byte sector.
@@ -738,7 +1354,6 @@ static INT32 cdimgInit()
}
} else {
FILE* h = _tfopen(cdimgTOC->Image, _T("rb"));
-
if (h) {
if (cdimgFseek(h, 16 * 2352 + 16, SEEK_SET) == 0) {
if (fread(buf, 1, 2048, h) == 2048) {
@@ -750,7 +1365,6 @@ static INT32 cdimgInit()
dprintf(_T("*** Bad CD!\n"));
}
}
-
fclose(h);
}
}
@@ -774,7 +1388,6 @@ static INT32 cdimgStop()
{
cdimgCloseFile();
CDEmuStatus = idle;
-
return 0;
}
@@ -784,22 +1397,23 @@ static INT32 cdimgFindTrack(INT32 LBA)
for (trk = cdimgTOC->FirstTrack - 1; trk < cdimgTOC->LastTrack; trk++)
if (LBA < cdimgMSFToLBA(cdimgTOC->TrackData[trk + 1].Address))
break;
+
return trk;
}
-static INT32 cdimgPlayLBA(INT32 LBA) // audio play start
+static INT32 cdimgPlayLBA(INT32 LBA) // audio play start
{
cdimgStop();
- if (QChannel != NULL) { // .CCD dump w/.SUB
+ if (QChannel != NULL) { // .CCD dump w/.SUB
if (LBA < 0 || LBA >= QChannelCount || (QChannel[LBA].Control & 0x40))
return 1;
- } else { // .BIN/.CUE dump or .CHD
+ } else { // .BIN/.CUE dump or .CHD
if (cdimgTOC->TrackData[cdimgFindTrack(LBA)].Control & 0x40)
return 1;
}
- cdimgLBA = LBA;
+ cdimgLBA = LBA;
cdimgTrack = cdimgFindTrack(cdimgLBA);
@@ -816,33 +1430,38 @@ static INT32 cdimgPlayLBA(INT32 LBA) // audio play start
INT32 sectors_to_read = (cdimgOUT_SIZE * 4) / 2352;
INT32 base;
INT32 trackEnd = cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack + 1].Address);
- if (sectors_to_read > trackEnd - cdimgLBA) sectors_to_read = trackEnd - cdimgLBA;
- if (sectors_to_read <= 0) return 1;
+ if (sectors_to_read > trackEnd - cdimgLBA)
+ sectors_to_read = trackEnd - cdimgLBA;
+ if (sectors_to_read <= 0)
+ return 1;
// Logical LBA space is shared by CHD and .bin/.cue: subtract the disc
// pregap. For CHD, cd_chd maps the logical LBA to its CHD frame per track.
base = cdimgLBA - cd_pregap;
- if (base < 0) base = 0;
+ if (base < 0)
+ base = 0;
cdimgAudioFilePos = base;
- if (cdimgTOC->ImageType == CD_TYPE_CHD) {
-
+ if (cdimgImage != NULL) {
UINT8 sector_buf[2352];
INT32 read_count = 0;
for (INT32 i = 0; i < sectors_to_read; i++) {
if (cdimgReadRawSector(base + i, sector_buf, true) != 0)
break;
- // Convert big-endian CD-DA data to native byte order
- for (INT32 j = 0; j < 2352; j += 4) {
- INT32 dst_idx = (i * 2352 + j) / 2;
- cdimgOutputbuffer[dst_idx] = (sector_buf[j] << 8) | sector_buf[j + 1];
- cdimgOutputbuffer[dst_idx + 1] = (sector_buf[j + 2] << 8) | sector_buf[j + 3];
+ if (cdimgTOC->ImageType == CD_TYPE_CHD) {
+ for (INT32 j = 0; j < 2352; j += 4) {
+ INT32 dst_idx = (i * 2352 + j) / 2;
+ cdimgOutputbuffer[dst_idx + 0] = (sector_buf[j + 0] << 8) | sector_buf[j + 1];
+ cdimgOutputbuffer[dst_idx + 1] = (sector_buf[j + 2] << 8) | sector_buf[j + 3];
+ }
+ } else {
+ memcpy((UINT8*)cdimgOutputbuffer + i * 2352, sector_buf, 2352);
}
read_count++;
}
- cdimgAudioFilePos = base + read_count;
+ cdimgAudioFilePos = base + read_count;
cdimgOutputbufferSize = read_count * (2352 / 4);
if (read_count == 0) {
cdimgStop();
@@ -850,7 +1469,6 @@ static INT32 cdimgPlayLBA(INT32 LBA) // audio play start
}
} else {
-
cdimgFile = _tfopen(cdimgTOC->Image, _T("rb"));
if (cdimgFile == NULL)
return 1;
@@ -863,17 +1481,17 @@ static INT32 cdimgPlayLBA(INT32 LBA) // audio play start
// fill the input buffer (size returned as count of 4-byte sample units)
cdimgOutputbufferSize = (INT32)fread(cdimgOutputbuffer, 4, sectors_to_read * (2352 / 4), cdimgFile);
- cdimgAudioFilePos = (INT32)(cdimgFtell(cdimgFile) / 2352);
+ cdimgAudioFilePos = (INT32)(cdimgFtell(cdimgFile) / 2352);
if (cdimgOutputbufferSize <= 0) {
cdimgStop();
return 1;
}
}
cdimgOutputPosition = 0;
- cdimgSamples = 0;
+ cdimgSamples = 0;
// this breaks states, commenting for now just in-case. -dink
//cdimgLBA = cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack].Address); // start at the beginning of track
- CDEmuStatus = playing;
+ CDEmuStatus = playing;
return 0;
}
@@ -890,7 +1508,8 @@ static INT32 cdimgPlay(UINT8 M, UINT8 S, UINT8 F)
static INT32 cdimgLoadSector(INT32 LBA, char* pBuffer)
{
- if (CDEmuStatus == playing) return 0; // data loading
+ if (CDEmuStatus == playing)
+ return 0; // data loading
INT32 originalLBA = LBA;
if (CDEmuStatus == seeking) {
@@ -901,7 +1520,7 @@ static INT32 cdimgLoadSector(INT32 LBA, char* pBuffer)
// Unified sector reader: cdimgReadRawSector handles both .bin and .chd
// transparently. For .bin files we still prefer the sequential-access
// optimization below (avoids redundant fseek calls).
- if (cdimgTOC && cdimgTOC->ImageType == CD_TYPE_CHD) {
+ if (cdimgTOC && cdimgImage != NULL) {
if (cdimgReadRawSector(LBA, (UINT8*)pBuffer) != 0) {
dprintf(_T("*** couldn't read sector (LBA %08u)\n"), originalLBA);
return 0;
@@ -911,7 +1530,7 @@ static INT32 cdimgLoadSector(INT32 LBA, char* pBuffer)
// index of the next sector. cdimgTrack is kept in sync using a
// full-disc LBA (with pregap) so cdimgFindTrack returns the correct
// track index for the BIOS standby-screen Q-channel query.
- cdimgLBA = LBA + 1;
+ cdimgLBA = LBA + 1;
cdimgTrack = cdimgFindTrack(LBA + cd_pregap);
return cdimgLBA;
}
@@ -967,7 +1586,6 @@ static INT32 cdimgLoadSector(INT32 LBA, char* pBuffer)
static UINT8* cdimgReadTOC(INT32 track)
{
static UINT8 TOCEntry[4];
-
memset(&TOCEntry, 0, sizeof(TOCEntry));
if (track == CDEmuTOC_FIRSTLAST) {
@@ -982,7 +1600,6 @@ static UINT8* cdimgReadTOC(INT32 track)
TOCEntry[0] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[1];
TOCEntry[1] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[2];
TOCEntry[2] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[3];
-
TOCEntry[3] = 0;
return TOCEntry;
@@ -1032,7 +1649,7 @@ static UINT8* cdimgReadQChannel()
switch (CDEmuStatus) {
case reading:
case playing: {
- if (QChannel != NULL && cdimgLBA >= 0 && cdimgLBA < QChannelCount) { // .CCD/.SUB
+ if (QChannel != NULL && cdimgLBA >= 0 && cdimgLBA < QChannelCount) { // .CCD/.SUB
QChannelData[0] = QChannel[cdimgLBA].track;
QChannelData[1] = QChannel[cdimgLBA].MSFabs.M;
@@ -1044,7 +1661,7 @@ static UINT8* cdimgReadQChannel()
QChannelData[6] = QChannel[cdimgLBA].MSFrel.F;
QChannelData[7] = QChannel[cdimgLBA].Control;
- } else { // .BIN/.ISO / .CHD
+ } else { // .BIN/.ISO / .CHD
// cdimgLBA is the file-relative sector index for .cue
// (data-track origin). For .chd we additionally keep
// cdimgTrack set by cdimgFindTrack to identify which contains
@@ -1084,7 +1701,6 @@ static UINT8* cdimgReadQChannel()
static int cdimgSetVolume(double dVolume)
{
cd_volume = dVolume;
-
return 0;
}
@@ -1112,22 +1728,27 @@ static INT32 cdimgGetSoundBuffer(INT16* buffer, INT32 samples)
if (cdimgOutputPosition >= cdimgOutputbufferSize) {
cdimgOutputPosition = 0;
INT32 remainingSectors = trackEnd - (cdimgAudioFilePos + cd_pregap);
- INT32 sectorsToRead = (cdimgOUT_SIZE * 4) / 2352;
+ INT32 sectorsToRead = (cdimgOUT_SIZE * 4) / 2352;
if (sectorsToRead > remainingSectors) sectorsToRead = remainingSectors;
if (sectorsToRead <= 0) {
cdimgStop();
break;
}
- if (cdimgTOC->ImageType == CD_TYPE_CHD) {
+ if (cdimgImage != NULL) {
UINT8 sectorBuffer[2352];
INT32 readCount = 0;
for (INT32 i = 0; i < sectorsToRead; i++) {
- if (cdimgReadRawSector(cdimgAudioFilePos + i, sectorBuffer, true) != 0) break;
- for (INT32 j = 0; j < 2352; j += 4) {
- INT32 offset = (i * 2352 + j) / 2;
- cdimgOutputbuffer[offset] = (sectorBuffer[j] << 8) | sectorBuffer[j + 1];
- cdimgOutputbuffer[offset + 1] = (sectorBuffer[j + 2] << 8) | sectorBuffer[j + 3];
+ if (cdimgReadRawSector(cdimgAudioFilePos + i, sectorBuffer, true) != 0)
+ break;
+ if (cdimgTOC->ImageType == CD_TYPE_CHD) {
+ for (INT32 j = 0; j < 2352; j += 4) {
+ INT32 offset = (i * 2352 + j) / 2;
+ cdimgOutputbuffer[offset + 0] = (sectorBuffer[j + 0] << 8) | sectorBuffer[j + 1];
+ cdimgOutputbuffer[offset + 1] = (sectorBuffer[j + 2] << 8) | sectorBuffer[j + 3];
+ }
+ } else {
+ memcpy((UINT8*)cdimgOutputbuffer + i * 2352, sectorBuffer, 2352);
}
readCount++;
}
@@ -1151,17 +1772,19 @@ static INT32 cdimgGetSoundBuffer(INT16* buffer, INT32 samples)
}
INT32 count = cdimgOutputbufferSize - cdimgOutputPosition;
- if (count > samples) count = samples;
- if (count > remainingSamples) count = remainingSamples;
+ if (count > samples)
+ count = samples;
+ if (count > remainingSamples)
+ count = remainingSamples;
INT16* src = cdimgOutputbuffer + cdimgOutputPosition * 2;
for (INT32 i = count * 2 - 1; i >= 0; i--) {
buffer[i] = CLIP((src[i] * (cd_volume / 100.0)) + buffer[i]);
}
- buffer += count * 2;
+ buffer += count * 2;
cdimgOutputPosition += count;
- samples -= count;
- cdimgSamples += count;
+ samples -= count;
+ cdimgSamples += count;
while (cdimgSamples >= (44100 / CD_FRAMES_SECOND)) {
cdimgSamples -= 44100 / CD_FRAMES_SECOND;
cdimgLBA++;
diff --git a/src/intf/cd/cd_img.h b/src/intf/cd/cd_img.h
index 072bed8ee..b1065be7d 100644
--- a/src/intf/cd/cd_img.h
+++ b/src/intf/cd/cd_img.h
@@ -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;