Автор Тема: Консольная утилита для определения маппера у Fami/NES rom'ов для linux/macos  (Прочитано 851 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн ndivision

  • Пользователь
  • Сообщений: 154
  • Пол: Мужской
    • Просмотр профиля
Привет всем!
Сходу сам не нашел, но наверняка кто то уже писал.
Ищу консольную утилитку, для linux/unix/macos для определения какой mapper в rom'е (для Fami/NES).
Для старых rom'ов понятно - уже все занесено в базу, а весь новодел - там его нету.

Можно на C, можно на python, вообще язык не важен.

Если кто то подскажет - буду благодарен!
Заранее спасибо за ответы!

Оффлайн supremacy

  • Пользователь
  • Сообщений: 2276
  • Пол: Мужской
    • Просмотр профиля
Можешь сам написать. Кластер делал библиотечку для разбора заголовка. https://github.com/ClusterM/nes-containers
Масяня вроде писал утилитку которая ромы сортирует по папкам в зависимости от маппера.
https://ramfactory.com/devices/INVITENES/Software/ROMSSorter.exe

Можно ещё отсюда парсинг взять
https://github.com/Kitrinx/NES_Header_Repair
« Последнее редактирование: 30 Январь 2022, 20:09:41 от supremacy »

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5107
    • Просмотр профиля
https://github.com/Kitrinx/NES_Header_Repair
Я брал когда-то, там iNES 1.0 и NES 2.0. Вот готовый, нужно передать .nes в 1-м аргументе: https://gist.github.com/infval/24a7b56f661666453344b4c650e5ddd5. Можно убрать строчку input("Press any key..."), чтобы не ждать ввода. Проверок нет. UNIF тоже нужен? UPD: Может вам нужен не просто номер маппер из заголовка, а что-то ещё? Не очень понял.

Оффлайн ndivision

  • Пользователь
  • Сообщений: 154
  • Пол: Мужской
    • Просмотр профиля
Да вот в том то и дело, что мог бы и сам и на C.
Но так как наверняка уже 100500 раз до меня это кто то писал - по этому и спросил - может уже что то готовое есть.

Sharpnull - на данном этапе устроил бы просто номер маппера. Если полный разбор заголовка будет - то вообще шикарно.
Как уже написал выше желательно на C.

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5107
    • Просмотр профиля
Как уже написал выше желательно на C.
По той же ссылке добавил "get_mapper.c". Если iNES 1.0 - выводит "Mapper: 4", если NES 2.0, то будет выведен также подмаппер "Mapper: 452\nSubmapper: 13". Компилировал под виндой "gcc -O3 -Wall -Wextra -static -static-libgcc get_mapper.c -o 1.exe".
UPD
Если полный разбор заголовка будет - то вообще шикарно.
Вообще, лучше взять у NintendulatorNRS (https://unlicensed.games/libg/static.php?page=NintendulatorNRS), он же отвечает за NES 2.0, в исходном коде есть подмапперы, которые он даже не описал на wiki.nesdev.org. А я это так, балуюсь :)
UPD2: Добавил пропущенный fclose(). Не знаю насколько это важно, если программа сразу закрывается, должно и так высвободиться.
« Последнее редактирование: 30 Январь 2022, 23:03:29 от Sharpnull »

Оффлайн ndivision

  • Пользователь
  • Сообщений: 154
  • Пол: Мужской
    • Просмотр профиля
Sharpnull
Шикарненько! Фактически то что нужно было. Собрал на linux/arm без проблем, затестил - в первом приближении работает отлично!
А сложно будет прикрутить что бы md5 указанного файла выводил?
В linux/unix отдельная команда конечно есть, но тут раз уж взялись утилитку отдельную и годную сделать - было бы круто реализовать в рамках нее.

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5107
    • Просмотр профиля
А сложно будет прикрутить что бы md5 указанного файла выводил?
Не сложно, но я для хешей NES ромов использую скрипт на Python, там вообще легко и на всех *nix системах Python 3 должен быть, не понимаю почему его не использовать.
Вот архив с кодом, мне лень делать на Github, может позже. В нём:
* .c/.h/Makefile - программа на C с добавлением MD5, реализацию MD5 взял простую, не разбирался. Компилировал в MinGW.
* nes_hash.py - вывод CRC32/MD5/SHA-1/SHA-256 хешей для PRG + CHR и всего файла (на Windows можно просто перетащить ром на скрипт).
* get_mapper.py - старый файл, просто.
UPD: Добавил проверку на размер файла меньше 17 байт. Всё равно никто не скачал.
UPD2: Кстати, код MD5 не будет работать правильно на Big-Endian системе, я догадываюсь как исправить, но для проверки похоже нужно эмулировать систему с Big-Endian.
UPD3: Добавил вывод CRC32 хеша на C, там очень маленькая функция. В версии v4.
« Последнее редактирование: 31 Январь 2022, 19:18:59 от Sharpnull »

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5107
    • Просмотр профиля
Оказалось, что ucon64 отображает информацию о маппере, но только для iNES.

Я улучшил свою программу и сделал Web версию с помощью Emscripten, в которой можно перетащить .nes файл или через Open ROM.
Исходный код и сборка Win x64: https://github.com/infval/nes-header-info
Скомпилированная Web версия: https://infval.github.io/nes-header-info-web/
Баги всегда есть, а названия компаний и описание можно улучшить, лучше пишите в ЛС об этом.

Особенности
* Вывод всех данных для заголовков: iNES (официальный), NES 2.0, Nintendo Header.
* Для первых 256 мапперов выводится описание (например, Nintendo NROM), для подозрительных мапперов присутствует "!" (это внутренние, бесполезные или дублирующие). Информация взята из кода NintendulatorNRS, wiki.nesdev, FCEUX.
* Для Nintendo Header выводится информация о "создателе" на основе Maker's Code. Информация собрана из некоторых ромов, кода ucon64, ещё из сети.
* Контрольные суммы CRC32, MD5, SHA-1 для: File - весь файл, ROM - весь файл без заголовка и Trainer, PRG ROM, CHR ROM, Misc - отдельные части, если они присутствуют, но если указаны, а размер файла меньше, то будет N/A. Misc выводится всегда, если файл больше суммы остальных частей. Рядом с CRC32 размер части в байтах.
* Поиск совпадения хешей в nes20db.xml (NES 2.0 XML Database) из текущей папки консоли и вывод названия .nes файла. Нет в Web (Emscripten) версии.

Изменения с прошлой версии
* Быстрый CRC32 код использующий вычисляемую таблицу, с моей доработкой для поддержки любого порядка байтов (Endian-independent).
* Другой MD5 код, прошлая реализация MD5 была плохой: использовалась дополнительная RAM равная данным, макс. размер файла 512МБ, только для Little-Endian (моё исправление было не полным).

Замечания
* Ограничение на размер файла: минимальный - 16 байт (только заголовок), максимальный - 2ГБ (ограничение ftell() для некоторых платформ и этого достаточно). Файл полностью копируется в RAM, поэтому нужно иметь свободное место, но чаще всего файлы небольшие.
* Контрольные суммы MD5 и SHA-1 на глаз вычисляются медленнее, чем в Python. На файле 128МБ у меня заметная задержка вычисления MD5 и SHA-1 в консоли и долгое вычисление в Web версии.
* Для Windows в консольной версии добавил специальный код для чтения пути до файла как Unicode, потому что в стандартный "int main(int argc, char* argv[])" используется какая-то текущая кодировка. Это нужно например для имён файлов от NewRisingSun (NES 2.0 XML Database), где используются нестандартное двоеточие и иероглифы. У меня в Windows 10 из шрифтов консоли правильно отображаются иероглифы в MS Gothic, NSimSun, SimSun-ExtB (больше символов), но с другими даже без правильного отображения можно выбрать файл через Tab или вставку из буфера обмена. Специальный код для Windows также используется для вывода совпадений из nes20db.xml, потому что нельзя просто вывести Unicode в консоль, шрифт также требуется для правильного отображения.
В Linux в аргументах может передаваться UTF-8, тогда не будет никаких проблем, иначе переименовывайте файл или используйте Web версию. Отображение из nes20db.xml либо будет правильное, либо неверные символы за пределами ACSII/ANSI.
* Nintendo Header иногда указывается разработчиком и содержится в конце PRG ROM. Данные не точные и может быть ложное срабатывание, когда заголовка нет, или наоборот - не показан, когда он есть, но составлен неверно. Размер PRG/CHR со значение 0, может означать 8 KiB или 64 KiB, поэтому дописываю "(or 64 KiB)" или "(or  8 KiB)", основной размер пытаюсь определить по указанному мапперу и наличию CHR RAM.
* Maker's Code в Nintendo Header содержится в 1 байте и его нужно читать как HEX число, позже Nintendo в других консолях стала использовать 2 байта в ASCII и были добавлены буквы до Z, т. е. число 0xA4 (Konami) стало строкой "A4" и стали доступны значения как "AZ". Названия компаний могут быть написаны по-разному или у одного "создателя" быть больше одной компании, потому что я не знаю официальной доступной базы "создателей".
* "TV system" (NTSC или PAL) и "PRG RAM Size" (значение * 8 KiB, но для 0 равно 0 или 8 KiB) указаны в последней спецификации iNES, но активно не используются, они перекрывают байты NES 2.0, поэтому для NES 2.0 указано N/A. Для определения поддерживаемых регионов/систем в NES 2.0 есть "CPU/PPU timing mode" (я назвал "Frame Timing"): NTSC, PAL, Dendy, Multiple-region (Both, Dual, "NTSC & PAL"). В разделе NES 2.0 свой "PRG RAM Size" вычисляемый по-другому.
* Mirroring имеет верное значения только для мапперов, где нельзя переключать Mirroring, иначе должно быть 0 (Horizontal). При этом эмуляторы могут брать во внимание Mirroring как значение по умолчанию, из-за чего может испортится прокрутка фона у ошибочно указанного маппера или предположения о значении по умолчанию в коде игры, тогда требуется установка правильного маппера или исправления кода.
* 4-screen VRAM - применим только для некоторых мапперов, подробнее в описании NES 2.0.
* Некоторые термины по-разному называются в эмуляторах и спецификациях, приведу соответствие моего выбора с другими.
Название     : wiki.nesdev                 | NintendulatorNRS          | Mesen (0.9.9)  | FCEUX
-------------*-----------------------------*---------------------------*----------------*---------------------
4-screen VRAM: Hard-wired four-screen mode | 4-screen VRAM             | Four Screens   | Four-screen
Battery      : "Battery" and other         | Battery                   | Battery        | Battery-backed NVRAM
                non-volatile memory
Console Type : Console Type                | Console Type              | System         | System
TV system    : TV system                   | ---                       | Frame Timing   | Region
PRG RAM      : PRG-RAM                     | PRG RAM                   | Work RAM       | PRG RAM
CHR RAM      : CHR-RAM                     | CHR RAM                   | CHR RAM        | CHR RAM
PRG Save     : PRG-NVRAM/EEPROM            | PRG RAM (battery)         | Save RAM       | PRG NVRAM
CHR Save     : CHR-NVRAM                   | CHR RAM (battery)         | CHR Save RAM   | CHR NVRAM
Frame Timing : CPU/PPU timing mode         | TV system [исходный код]  | Frame Timing   | Region
Console Ext. : Extended Console Type       | Console Type              | System         | Extend System
VS PPU       : Vs. PPU Type                | VS PPU                    | VS PPU Type    | VS. System PPU
VS Type      : Vs. Hardware Type           | VS Type                   | VS System Type | VS. System Hardware
Misc ROMs    : Miscellaneous ROMs          | Misc ROMs                 | ---            | Misc. ROM(s)
Expansion    : Default Expansion Device    | Input or Expansion Device | Input Type     | Input device
* Максимально выводимый размер PRG ROM и CHR ROM для NES 2.0 - 16140901064495857664 байт (14 EiB эксабайт/эксбибайт), но формат поддерживает до 56 EiB, что не влезает в 64-битное число, для >14 EiB будет выведено 0 байт.

Компиляция в Windows для консоли через MinGW и make
* Установить MSYS2 по инструкции (https://www.msys2.org/), там будет mingw-w64-x86_64-toolchain для компиляции под x64, а если нужно под x86, то ещё mingw-w64-i686-toolchain. Про MSYS2 для x86 не знаю.
* Запустить MSYS2 MinGW x64/x86. Перейти в папку с Makefile (например, cd /c/Project) и выполнить make.
Компиляция в Windows для Web (Emscripten)
* Установить Emscripten по инструкции (https://emscripten.org/docs/getting_started/downloads.html) в консоли запущенной от администратора (!). Также MSYS2 выше для Makefile.
* Запустить emcmdprompt.bat. Т. к. я использую Makefile, добавить путь до make.exe в переменные среды или в консоли каждый раз (например, set PATH=%PATH%;C:\msys\usr\bin). Перейти в папку с Makefile для Emscripten (например, cd C:\Project\emscripten). Выполнить emmake make для отладочной версии или emmake make release для оптимизированной.
* Для проверки нужно запустить локальный сервер, т. к. Python придётся установить всё равно, то в консоли в папке с emscripten\index.html выполнить python -m http.server и зайти в браузере на 127.0.0.1:8000.

Использовано
https://wiki.nesdev.org
https://unlicensed.games/libg/static.php?page=NintendulatorNRS
https://github.com/TASEmulators/fceux
https://ucon64.sourceforge.io/
https://create.stephan-brumme.com/crc32/
https://github.com/Zunawe/md5-c
https://github.com/clibs/sha1

Пример вывода в консоли с nes20db.xml и Nintendo Header
nes20db.xml is found
-------------*-----------------------------------------
              NES 2.0
 4E 45 53 1A 08 00 21 08 20 00 00 07 00 00 00 01
-------------*-----------------------------------------
Mapper Number: 2 = Nintendo UxROM
PRG ROM  Size:   128 KiB =   131072 B
CHR ROM  Size:     0 KiB =        0 B
Mirroring    : Vertical
4-screen VRAM: No
Battery      : No
Trainer      : No
Console Type : NES/Famicom/Dendy (#0)
TV system    : N/A
PRG RAM  Size: N/A
-------------*-----------------------------------------
Submapper    : 2
PRG RAM  Size:     0 KiB =        0 B
CHR RAM  Size:     8 KiB =     8192 B
PRG Save Size:     0 KiB =        0 B
CHR Save Size:     0 KiB =        0 B
Frame Timing : NTSC (#0)
Console Ext. : N/A
VS PPU       : N/A
VS Type      : N/A
Misc ROMs    : 0
Expansion    : Standard Controllers (#1)
-------------*-----------------------------------------
File    CRC32: C31BCF11 | Size: 131088
        MD5  : 0187914A1E3121BCCABE9783A3A776DA
        SHA-1: C7F744BE2E59B9238E6B61FE3F8110B1D96AA77E
-------------*-----------------------------------------
ROM     CRC32: 67D5C3F9 | Size: 131072
        MD5  : 783924A53E172029792CEAEABEF6093A
        SHA-1: 42E0AFDD1E603C4F301AEB030B799F69EEBE2E15
Licensed Japan\Hello Kitty World.nes
-------------*-----------------------------------------
PRG ROM CRC32: 67D5C3F9 | Size: 131072
        MD5  : 783924A53E172029792CEAEABEF6093A
        SHA-1: 42E0AFDD1E603C4F301AEB030B799F69EEBE2E15
Licensed Japan\Hello Kitty World.nes
-------------*-----------------------------------------
              Nintendo Header
 48 45 4C 4C 4F 4B 49 54 54 59 20 57 4F 52 4C 44
 1F 70 00 00 38 02 01 0F 8E 28
-------------*-----------------------------------------
Title        : {HELLOKITTY WORLD}
Mapper       : UNROM (#2)
PRG ROM  Size: 128 KiB = 131072 B
CHR      Size:   8 KiB =   8192 B (or 64 KiB)
CHR RAM      : Yes
Mirroring    : Vertical
Maker's Code : 0x8E = Character Soft
Checksum     : PRG = 1F70, CHR = 0000, Validation = 28
« Последнее редактирование: 24 Февраль 2022, 12:16:25 от Sharpnull »