예제 #1
0
 def save(self, writer=None):
     if writer is None:
         writer = BinaryIO()
     start = writer.tell()
     writer.write(self.magic)
     sizeofs = writer.tell()
     writer.writeUInt32(0)
     writer.writeUInt16(self.num)
     writer.writeUInt16(0)
     for entry in self.entries:
         writer.writeUInt32(entry.start)
         writer.writeUInt32(entry.stop)
     size = writer.tell() - start
     with writer.seek(sizeofs):
         writer.writeUInt32(size)
     return writer
예제 #2
0
 def save(self, writer=None):
     if writer is None:
         writer = BinaryIO()
     start = writer.tell()
     writer.write(self.magic)
     writer.writeUInt16(self.endian)
     writer.writeUInt16(self.version)
     sizeofs = writer.tell()
     writer.writeUInt32(0)
     headersizeofs = writer.tell()
     writer.writeUInt16(0)
     writer.writeUInt16(self.numblocks)
     size = writer.tell() - start
     with writer.seek(headersizeofs):
         writer.writeUInt16(size)
     writer.writeUInt32(writer.tell() + 4 - start)  # block[0] ofs
     writer = self.tex.save(writer)
     size = writer.tell() - start
     with writer.seek(sizeofs):
         writer.writeUInt32(size)
     return writer
예제 #3
0
 def save(self, writer=None):
     writer = BinaryIO()  # FIXME
     blocks = {}
     num = 0
     for name in self.files:
         match = re.match(
             '^(?P<block>[0-9]+c?)_'
             '(?P<idx>[0-9]{1,5})'
             '(?P<flags>[A-O]*c)?'
             '(?:\\[(?P<key>[0-9A-F]{1,4})\\])?$', name)
         if not match:
             raise ValueError(
                 '{0} is not a valid identifier+options'.format(name))
         block_name = match.group('block')
         if block_name not in blocks:
             blocks[block_name] = {}
         idx = int(match.group('idx'))
         num = max(idx, num)
         flags = match.group('flags')
         try:
             key = int(match.group('key'), 16)
         except:
             key = 0
         blocks[block_name][idx] = (flags, key, self.files[name])
     if self.version in game.GEN_IV:
         if set(blocks.keys()) | {'0c', '0'} != {'0c', '0'}:
             raise ValueError('Gen IV cannot have any blocks other than'
                              ' 0 (and 0c). Got: {0}'.format(blocks.keys()))
         blocks.pop('0c', None)  # TODO: handle comment blocks
         self.numblocks = 1
     else:
         self.numblocks = len(blocks)
     # base_offset = self.size()
     # if self.version > game.GEN_IV:
     #    base_offset += 4*self.numblocks
     # base_offset += TableEntry.instance(self.version).size()*self.numblocks
     self.num = num + 1
     start = writer.tell()
     writer = AtomicStruct.save(self, writer)
     text_writer = BinaryIO()
     text_offs = writer.tell() + 8 * self.num
     prev_text_pos = 0
     if self.version in game.GEN_IV:
         for i, block_name in enumerate(blocks):
             # if self.version > game.GEN_IV:
             #     text_offs += 4*self.numblocks+text_writer.tell()-prev_text_pos
             #     prev_text_pos = text_writer.tell()
             for j in xrange(self.num):
                 try:
                     flags, key, text = blocks[block_name][j]
                 except KeyError:
                     flags = key = None
                     text = ''
                 string = []
                 cidx = 0
                 while cidx < len(text):
                     char = text[cidx]
                     cidx += 1
                     if char == '\\':
                         char = text[cidx]
                         cidx += 1
                         if char == 'x':
                             # n = int(text[cidx:cidx+2], 16)
                             n = rtable['\\x' + text[cidx:cidx + 2]]
                             cidx += 2
                         elif char == 'n':
                             n = 0xE000
                         elif char == 'r':
                             n = 0x25BC
                         elif char == 'f':
                             n = 0x25BD
                         elif char == 'u':
                             n = rtable['\\u' + text[cidx:cidx + 4]]
                             cidx += 4
                         elif char == '?':
                             n = int(text[cidx:cidx + 4], 16)
                             cidx += 4
                         else:
                             n = 1
                         string.append(n)
                     elif char == '\n':
                         string.append(0xE000)
                     elif char == '\r':
                         string.append(0x25BC)
                     elif char == '\f':
                         string.append(0x25BD)
                     elif char == 'V' and text[cidx:cidx + 3] == 'AR(':
                         eov = text.find(')', cidx + 3)
                         if eov == -1:
                             raise RuntimeError(
                                 'Could not find end of VAR()')
                         args = []
                         for arg in text[cidx + 3:eov].split(','):
                             args.append(int(arg.strip(), 0))
                         cidx = eov + 1
                         string.append(0xFFFE)
                         string.append(args.pop(0))
                         string.append(len(args))
                         string.extend(args)
                     else:
                         string.append(rtable[char])
                 if flags and 'c' in flags:
                     string = compress(string, 15)
                 string.append(0xFFFF)
                 size = len(string)
                 text_writer.writeAlign(4)
                 state = (((self.seed * 0x2FD) & 0xFFFF) * (j + 1)) & 0xFFFF
                 key = state | state << 16
                 writer.writeUInt32(key ^ (text_offs + text_writer.tell()))
                 writer.writeUInt32(key ^ size)
                 key = (TEXT_KEY4_INIT * (j + 1)) & 0xFFFF
                 for char in string:
                     text_writer.writeUInt16(char ^ key)
                     key = (key + TEXT_KEY4_STEP) & 0xFFFF
             # TODO: comments
             writer.write(text_writer.getvalue())
     else:
         block = Editable()
         block.uint32('size')
         block.array('entries',
                     TableEntry(self.version).base_struct,
                     length=self.num)
         block.freeze()
         block_offset_pos = writer.tell()
         for i in xrange(self.numblocks):
             writer.writeUInt32(0)
         for i, block_name in enumerate(blocks):
             text_writer = BinaryIO()
             block.save(text_writer)
             for j, entry in enumerate(block.entries):
                 entry.offset = text_writer.tell()
                 try:
                     flags, key, text = blocks[block_name][j]
                 except KeyError:
                     flags = key = None
                     text = ''
                 string = []
                 cidx = 0
                 while cidx < len(text):
                     char = text[cidx]
                     cidx += 1
                     if char == '\\':
                         char = text[cidx]
                         cidx += 1
                         if char == 'x':
                             n = int(text[cidx:cidx + 2], 16)
                             cidx += 2
                         elif char == 'u' or char == '?':
                             n = int(text[cidx:cidx + 4], 16)
                             cidx += 4
                         elif char == 'n':
                             n = 0xFFFE
                         elif char == 'r':
                             string.append(0xF000)
                             string.append(0xBE01)
                             string.append(0)
                             continue
                         elif char == 'f':
                             string.append(0xF000)
                             string.append(0xBE00)
                             string.append(0)
                             continue
                         else:
                             n = 1
                         string.append(n)
                     elif char == '\n':
                         string.append(0xFFFE)
                     elif char == '\r':
                         string.append(0xF000)
                         string.append(0xBE01)
                         string.append(0)
                     elif char == '\f':
                         string.append(0xF000)
                         string.append(0xBE00)
                         string.append(0)
                     elif char == 'V' and text[cidx:cidx + 3] == 'AR(':
                         eov = text.find(')', cidx + 3)
                         if eov == -1:
                             raise RuntimeError(
                                 'Could not find end of VAR()')
                         args = []
                         for arg in text[cidx + 3:eov].split(','):
                             args.append(int(arg.strip(), 0))
                         cidx = eov + 1
                         string.append(0xF000)
                         string.append(args.pop(0))
                         string.append(len(args))
                         string.extend(args)
                     else:
                         string.append(ord(char))
                 flag = 0
                 if flags:
                     for shift in range(16):
                         if chr(65 + shift) in flags:
                             flag |= 1 << shift
                     if 'c' in flags:
                         string = compress(string, 16)
                 if not key:
                     key = 0
                 string.append(0xFFFF)
                 encchars = []
                 while string:
                     char = string.pop() ^ key
                     key = ((key >> 3) | (key << 13)) & 0xFFFF
                     encchars.insert(0, char)
                 entry.charcount = len(encchars)
                 entry.flags = flag
                 for char in encchars:
                     text_writer.writeUInt16(char)
             text_writer.writeAlign(4)
             block.size = text_writer.tell()
             with text_writer.seek(0):
                 block.save(text_writer)
             block_offset = writer.tell() - start
             with writer.seek(block_offset_pos + 4 * i):
                 writer.writeUInt32(block_offset)
             writer.write(text_writer.getvalue())
         self.filesize = writer.tell() - start
         with writer.seek(start):
             AtomicStruct.save(self, writer)
     return writer