烧录卡的rom裁减

Sun 28 December 2014 | tags:

从GBA时代就知道,从卡带dump下来的rom并不是器实际容量,而是闪存芯片的容量。例如rom的实际用了20M,但生产卡带也需要使用32MB的闪存芯片,这样就有12MB是没用的填充空白数据。那时候烧录卡内置的容量也就128MB,256MB,当然寸M必争了。

到NDS的时候基本上rom都会有几MB到几十MB的盈余,那个时候烧录卡所用的micro sd卡普遍容量还是比较吃紧的,把这个空白部分去掉能省出多装几个rom的容量。

到3DS的rom,更夸张了,大多能有几百MB到上G的空白数据,所以就算现在的micro sd容量很富裕了,但是裁减一下还是能省出很大一块空间。

GBA的时代,有的烧录卡的烧录工具自带这个功能。

NDS的时候,好不容易找到了Linux下的裁减工具,既不好用也不支持批量处理。

3DS的时候,那时它还没破解所以耍了一段时间卖了。最近买了个二手3DS,配上gateway烧录卡,又把rom裁减这回事想起来了,不过跟小时候的区别是,现在直接自己写一个就好了。时间真是快啊……

从前向后扫:

#!/usr/bin/env python2.7

import sys, os

chunksize = 1024 * 200

def trunc_tail(infile):
    with open(infile, 'r') as fh:
        currentByte = fh.read(chunksize)
        position = fh.tell()
        while True:
            nextbyte = fh.read(chunksize)
            if nextbyte == "":
                break
            elif currentByte != nextbyte:
                if len(currentByte) != len(nextbyte):
                    if currentByte[-len(nextbyte):] == nextbyte:
                        continue
                position = fh.tell()
                currentByte = nextbyte
                sys.stdout.write('\r{0}'.format(position))
                sys.stdout.flush()
        sys.stdout.write('\n')

    if os.stat(infile).st_size != position:
        with open(infile, 'ab') as wh:
            wh.truncate(position)


if __name__ == '__main__':
    for f in sys.argv[1:]:
        trunc_tail(f)

从后向前扫:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/bin/env python2.7

import sys, os

chunksize = 1024

def trunk_tail(infile):
    filesize = os.stat(infile).st_size
    blank = ' ' * (len(str(filesize)) + 1)
    sys.stdout.write('{0}'.format(filesize))
    sys.stdout.flush()

    with open(infile, 'rb') as fh:
        finalpos = filesize
        for cks in (chunksize*500, chunksize*50, chunksize, chunksize/50, 10):
            if finalpos < cks*2:
                continue
            fh.seek(finalpos-cks)
            preblock = fh.read(cks)
            for pos in xrange(finalpos-cks*2, -1, -cks):
                fh.seek(pos)
                currblock = fh.read(cks)
                if preblock != currblock:
                    if pos != finalpos - cks * 2:
                        finalpos = pos + cks
                    break
                sys.stdout.write('\r{0}\r{1}'.format(blank,pos))
                sys.stdout.flush()
    sys.stdout.write('\r{0}\r{1}'.format(blank,finalpos))
    sys.stdout.write('\n')

    if finalpos < filesize:
        with open(infile, 'ab') as wh:
            wh.truncate(finalpos)

if __name__ == '__main__':
    for f in sys.argv[1:]:
        trunk_tail(f)

一般来说从后向前速度应该会更快。