rom.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. import sqlite3
  2. import os
  3. import re
  4. import string
  5. import stat
  6. import popen2
  7. import glob
  8. import sys
  9. import pprint
  10. # Detect Mirrord Roms
  11. # Rom Type Mapping
  12. #
  13. # 0 ROM only
  14. # 1 ROM and RAM
  15. # 2 ROM and Save RAM
  16. # 3 ROM and DSP1 chip
  17. # 4 ROM, RAM and DSP1 chip
  18. # 5 ROM, Save RAM and DSP1 chip
  19. # 19 ROM and Super FX chip
  20. # 227 ROM, RAM and GameBoy data
  21. # 246 ROM and DSP2 chip
  22. # Process /Users/david/Devel/arch/snes/roms/Teenage Mutant Ninja Turtles IV - Turtles in Time (U) [!].smc
  23. # 0 uCON64 2.0.0 Apple (PPC) 1999-2005
  24. # 1 Uses code from various people. See 'developers.html' for more!
  25. # 2 This may be freely redistributed under the terms of the GNU Public License
  26. # 4 /Users/david/Devel/arch/snes/roms/Teenage Mutant Ninja Turtles IV - Turtles in Time (U) [!].smc
  27. # 6 Multi Game Doctor (2)/Multi Game Hunter/MGH
  28. # 8 00007fb0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ........
  29. # 9 00007fc0 54 2e 4d 2e 4e 2e 54 2e 20 34 20 20 20 20 20 20 T.M.N.T. 4
  30. # 10 00007fd0 20 20 20 20 20 20 00 0a 00 01 a4 00 7c e9 83 16 ......|...
  31. # 12 Super Nintendo Entertainment System/SNES/Super Famicom
  32. # 13 T.M.N.T. 4
  33. # 14 Konami
  34. # 15 U.S.A.
  35. # 16 1048576 Bytes (8.0000 Mb)
  36. # 18 Padded: Maybe, 105 Bytes (0.0008 Mb)
  37. # 19 Interleaved/Swapped: No
  38. # 20 Backup unit/emulator header: No
  39. # 21 HiROM: No
  40. # 22 Internal size: 8 Mb
  41. # 23 ROM type: (0) ROM
  42. # 24 ROM speed: 200 ns (SlowROM)
  43. # 25 SRAM: No
  44. # 26 Version: 1.0
  45. # 27 Checksum: Ok, 0x1683 (calculated) == 0x1683 (internal)
  46. # 28 Inverse checksum: Ok, 0xe97c (calculated) == 0xe97c (internal)
  47. # 29 Checksum (CRC32): 0x5940bd99
  48. # 31 This ROM has no backup unit header
  49. swc_header_tpl = '''
  50. Backup unit header info (SWC)
  51. 00000000 20 00 0c 00 00 00 00 00 aa bb 04 00 00 00 00 00 ...............
  52. 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
  53. 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
  54. [0-1] File size: 262144 Bytes (2.0000 Mb) => Matches
  55. [2:7] Run program in mode: 3
  56. [2:6] Split: No => Matches
  57. [2:5] SRAM mapping mode: LoROM => Matches
  58. [2:4] DRAM mapping mode: LoROM => Matches
  59. [2:3-2] SRAM size: 0 kB => Matches
  60. [2:1] Run program in mode: 3
  61. [2:0] External cartridge memory: Disabled
  62. '''
  63. def createdb():
  64. try:
  65. os.unlink("roms.sqlite3")
  66. except:
  67. pass
  68. conn = sqlite3.connect('roms.sqlite3')
  69. c = conn.cursor()
  70. c.execute('''create table roms
  71. (
  72. file_name text,
  73. file_ext text,
  74. file_size integer,
  75. rom_size integer,
  76. rom_mb real,
  77. rom_padded integer,
  78. rom_trainer integer,
  79. rom_backup integer,
  80. rom_name text,
  81. rom_vendor text,
  82. rom_region text,
  83. rom_hirom integer,
  84. rom_internalsize integer,
  85. rom_type integer,
  86. rom_speed integer,
  87. rom_sram integer,
  88. rom_version real,
  89. rom_chk integer,
  90. swc_size integer,
  91. swc_mode integer,
  92. swc_split text,
  93. swc_sram_mode text,
  94. swc_dram_mode text,
  95. swc_sram_size text
  96. )''')
  97. return conn, c
  98. def process(conn, c, file_name, out):
  99. file_ext = os.path.splitext(file_name)[1].replace(".", '')
  100. file_size = os.stat(file_name)[stat.ST_SIZE]
  101. rom_size = 0
  102. rom_mb = 0
  103. rom_padded = 0
  104. rom_trainer = 0
  105. rom_backup = 0
  106. rom_name = ''
  107. rom_vendor = ''
  108. rom_region = ''
  109. rom_hirom = 0
  110. rom_internalsize = 0
  111. rom_type = 0
  112. rom_speed = 0
  113. rom_sram = 0
  114. rom_version = 0
  115. rom_chk = 0
  116. swc_size = 0
  117. swc_mode = 0
  118. swc_split = ''
  119. swc_sram_mode = ''
  120. swc_dram_mode = ''
  121. swc_sram_size = ''
  122. print "-" * 60
  123. print "Process %s" % file_name
  124. try:
  125. rom_name = out[13]
  126. rom_vendor = out[14]
  127. rom_region = out[15]
  128. try:
  129. rom_size = int(out[16].split(" ")[0])
  130. rom_mb = float(
  131. re.compile("([\d.]+) Mb").search(out[16]).groups()[0])
  132. except:
  133. print "Broken..."
  134. return
  135. if not "No" in out[18]:
  136. rom_padded = int(
  137. re.compile("([\d.]+) Bytes").search(out[18]).groups()[0])
  138. for idx, line in enumerate(out):
  139. if line is None:
  140. continue
  141. if "Backup unit/emulator header: Yes" in line:
  142. rom_backup = int(
  143. re.compile("([\d.]+) Bytes").search(line).groups()[0])
  144. if "Intro/Trainer:" in line:
  145. rom_trainer = int(
  146. re.compile("([\d.]+) Bytes").search(line).groups()[0])
  147. if "HiROM: Yes" in line:
  148. rom_hirom = 1
  149. if "Internal size:" in line:
  150. rom_internalsize = int(
  151. re.compile("([\d.]+) Mb").search(line).groups()[0])
  152. if "ROM type:" in line:
  153. try:
  154. rom_type = int(
  155. re.compile("([\d]+)").search(line).groups()[0])
  156. except:
  157. pass
  158. if "ROM speed:" in line:
  159. rom_speed = int(
  160. re.compile("([\d]+) ns").search(line).groups()[0])
  161. if "SRAM: Yes" in line:
  162. rom_sram = int(
  163. re.compile("([\d]+) kBytes").search(line).groups()[0])
  164. if "Version:" in line:
  165. rom_version = float(
  166. re.compile("([\d.]+)").search(line).groups()[0])
  167. if "Checksum: Ok" in line:
  168. rom_chk = 1
  169. except:
  170. for idx, line in enumerate(out):
  171. if line is None:
  172. continue
  173. print idx, line
  174. sys.exit()
  175. query = """INSERT INTO roms
  176. VALUES
  177. (
  178. ?,?,?,?,?,
  179. ?,?,?,?,?,
  180. ?,?,?,?,?,
  181. ?,?,?,?,?,
  182. ?,?,?,?) """
  183. data = (file_name,
  184. file_ext,
  185. file_size,
  186. rom_size,
  187. rom_mb,
  188. rom_padded,
  189. rom_trainer,
  190. rom_backup,
  191. rom_name,
  192. rom_vendor,
  193. rom_region,
  194. rom_hirom,
  195. rom_internalsize,
  196. rom_type,
  197. rom_speed,
  198. rom_sram,
  199. rom_version,
  200. rom_chk,
  201. swc_size,
  202. swc_mode,
  203. swc_split,
  204. swc_sram_mode,
  205. swc_dram_mode,
  206. swc_sram_size)
  207. c.execute(query, data)
  208. conn.commit()
  209. def ucon64_info(filename):
  210. cmd = "ucon64 --dbuh -snes \"%s\"" % filename
  211. r, w, e = popen2.popen3(cmd)
  212. err = e.readlines()
  213. out = r.readlines()
  214. r.close()
  215. e.close()
  216. w.close()
  217. if len(err):
  218. return False, err
  219. return out, err
  220. def clean(s):
  221. s = s.replace("\n", "")
  222. if not len(s):
  223. return None
  224. return s
  225. def main():
  226. conn, c = createdb()
  227. path = sys.argv[1]
  228. files = glob.glob(path + "/*")
  229. for filename in files:
  230. try:
  231. r, err = ucon64_info(filename)
  232. if not r:
  233. print err
  234. continue
  235. r = map(clean, r)
  236. process(conn, c, filename, r)
  237. except (KeyboardInterrupt, SystemExit):
  238. print "Saving DB..."
  239. c.close()
  240. conn.commit()
  241. conn.close()
  242. sys.exit(-1)
  243. c.close()
  244. conn.commit()
  245. conn.close()
  246. if __name__ == "__main__":
  247. main()