Advertisement
sebbu

tmx converter

Feb 22nd, 2013
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.64 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3.  
  4. import sys #stdout, stderr, argc, argc
  5. import os #listdir
  6. import posixpath #join, splitext
  7. import xml.parsers.expat #EXPAT
  8. import base64
  9. import zlib
  10. import gzip
  11. import struct #unpack, pack
  12. import StringIO #StringIO
  13.  
  14. HANDLER_NAMES = [
  15.     'StartElementHandler', 'EndElementHandler',
  16.     'CharacterDataHandler', 'ProcessingInstructionHandler',
  17.     'UnparsedEntityDeclHandler', 'NotationDeclHandler',
  18.     'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler',
  19.     'CommentHandler', 'StartCdataSectionHandler',
  20.     'EndCdataSectionHandler',
  21.     'DefaultHandler', 'DefaultHandlerExpand',
  22.     #'NotStandaloneHandler',
  23.     'ExternalEntityRefHandler'
  24.     ]
  25.  
  26. dump_all = False # wall of text
  27.  
  28. class State(object):
  29.     pass
  30. State.INITIAL = State()
  31. State.LAYER = State()
  32. State.DATA = State()
  33. State.FINAL = State()
  34.  
  35. class ContentHandler:
  36.  
  37.     __slots__ = (
  38.         'p', # Expat object
  39.         'state', # state of collision info
  40.         'encoding', # encoding of layer data
  41.         'compression', # compression of layer data
  42.         'mtime', # date of gzip content
  43.         'width', # width of the map
  44.         'height', # height of the map
  45.         'buffer', # characters within a section
  46.         'gids', # list of the tiles of the layer
  47.     )
  48.  
  49.     def __init__(self):
  50.         self.state = State.INITIAL
  51.         self.p = xml.parsers.expat.ParserCreate()
  52.         self.p.ordered_attributes = 1
  53.         self.p.StartElementHandler = self.start_element
  54.         self.p.EndElementHandler = self.end_element
  55.         self.p.CharacterDataHandler = self.char_data
  56.         self.width = 0
  57.         self.height = 0
  58.         self.encoding = ''
  59.         self.compression = ''
  60.         self.buffer = bytearray()
  61.         pass
  62.  
  63.     # 3 handler functions
  64.     def start_element(self, name, attrs):
  65.         if dump_all:
  66.             sys.stdout.write('<%s' % name)
  67.             if len(attrs)>0:
  68.                 #sys.stdout.write(' %s' % ' '.join('%s="%s"' % (k,v) for k,v in attr.items()))
  69.                 sys.stdout.write(' %s' % ' '.join('%s="%s"' % (attrs[2*i], attrs[2*i+1]) for i in range(len(attrs)/2)))
  70.             sys.stdout.write('>')
  71.         if self.state is State.INITIAL:
  72.             if name == u'map':
  73.                 for i in range(len(attrs)/2):
  74.                     if attrs[2*i] == u'width':
  75.                         self.width = int(attrs[2*i+1])
  76.                     elif attrs[2*i] == u'height':
  77.                         self.height = int(attrs[2*i+1])
  78.             self.state = State.LAYER
  79.         elif self.state is State.LAYER:
  80.             if name == u'layer':
  81.                 for i in range(len(attrs)/2):
  82.                     if attrs[2*i] == u'width':
  83.                         if self.width <> int(attrs[2*i+1]):
  84.                             sys.stderr.write('partial layer not supported yet.\n')
  85.                             return
  86.                     elif attrs[2*i] == u'height':
  87.                         if self.height <> int(attrs[2*i+1]):
  88.                             sys.stderr.write('partial layer not supported yet.\n')
  89.                             return
  90.                 self.state = State.DATA
  91.                 self.gids = []
  92.         elif self.state is State.DATA:
  93.             if name == u'data':
  94.                 self.encoding = ''
  95.                 self.compression = ''
  96.                 for i in range(len(attrs)/2):
  97.                     if attrs[2*i] == u'encoding':
  98.                         self.encoding = attrs[2*i+1]
  99.                     elif attrs[2*i] == u'compression':
  100.                         self.compression = attrs[2*i+1]
  101.             elif name == u'tile':
  102.                 for i in range(len(attrs)/2):
  103.                     if attrs[2*i] == u'encoding':
  104.                         self.gids.append(int(attrs[2*i+1]))
  105.  
  106.     def end_element(self, name):
  107.         if dump_all:
  108.             sys.stdout.write('<%s>' % name)
  109.         if self.state is State.DATA:
  110.             if name == u'data':
  111.                 if self.encoding not in (u'', u'csv', u'base64', u'xml'):
  112.                     print('Bad encoding:', self.encoding)
  113.                 if self.compression not in (u'', u'none', u'zlib', u'gzip'):
  114.                     print('Bad compression:', self.compression)
  115.                 #decoding start
  116.                 if self.encoding == u'base64':
  117.                     data2 = base64.b64decode(str(self.buffer))
  118.                     #print(data2)
  119.                     #print(' '.join( '%d' % ord(data2[i]) for i in range(10)))
  120.                     if self.compression == u'zlib':
  121.                         data = zlib.decompress(data2)
  122.                     elif self.compression == u'gzip':
  123.                         #data = zlib.decompressobj().decompress('x\x9c' + data2[10:-8])
  124.                         out = StringIO.StringIO()
  125.                         out.write(data2)
  126.                         out.seek(0) #needed
  127.                         f = gzip.GzipFile(fileobj=out, mode='rb')
  128.                         #f._init_read()
  129.                         #f._read_gzip_header()
  130.                         data = f.read()
  131.                         self.mtime = f.mtime
  132.                         #print('mtime = %d' % self.mtime)
  133.                         f.close()
  134.                         out.close()
  135.                     for i in range(self.width*self.height):
  136.                         gid = int(struct.unpack('<I',data[i*4:i*4+4])[0])
  137.                         #print('%s' % data[i*4:i*4+4])
  138.                         #print('%d' % gid)
  139.                         self.gids.append(gid)
  140.                 #decoding end
  141.                 if len(self.gids) != self.width*self.height:
  142.                     sys.stderr.write('ERROR : incorrect gid count.\n')
  143.                     return
  144.                 #print('"%s" "%s"' % (self.encoding, self.compression))
  145.                 #coding start
  146.                 data = ''
  147.                 for i in range(len(self.gids)):
  148.                     data += struct.pack('<I', self.gids[i])
  149.                 if len(data) <> self.width*self.height*4:
  150.                     sys.stderr.write('ERROR : incorrect data packing.\n')
  151.                     return
  152.                 if self.encoding == u'base64':
  153.                     if self.compression == u'zlib':
  154.                         data = zlib.compress(data)
  155.                     elif self.compression == u'gzip':
  156.                         out = StringIO.StringIO()
  157.                         f = gzip.GzipFile(fileobj=out, mode='w', compresslevel=6, mtime=self.mtime)
  158.                         f.write(data)
  159.                         f.close()
  160.                         data = out.getvalue()
  161.                         #print(' '.join( '%d' % ord(data2[i]) for i in range(10)))
  162.                         #print(' '.join( '%d' % ord(data[i]) for i in range(10)))
  163.                         data=data[:8]+chr(0)+chr(3)+data[10:]
  164.                     data = base64.b64encode(data)
  165.                     if data <> self.buffer:
  166.                         print('%d %d' % (len(data), len(self.buffer)))
  167.                         print('%s' % data)
  168.                         print('%s' % self.buffer)
  169.                         sys.stderr.write('ERROR : decompress + compress returned different data.\n')
  170.                         #return
  171.                 #coding end
  172.                 self.buffer = bytearray()
  173.                 print('layer parsed.')
  174.                 self.state = State.LAYER
  175.  
  176.     def char_data(self, data):
  177.         if dump_all:
  178.             sys.stdout.write('%s' % data)
  179.         if self.state is State.DATA:
  180.             if len(data.strip()) > 0:
  181.                 self.buffer += data.strip().encode('ascii')
  182.  
  183.     def Parse(self, data, isfinal=1):
  184.         self.p.Parse(data, isfinal)
  185.  
  186.     def ParseFile(self, file):
  187.         self.p.ParseFile(file)
  188.  
  189. CLIENT_MAPS = 'maps'
  190. SERVER_WLK = 'data'
  191. SERVER_NPCS = 'npc'
  192.  
  193. def main(argv):
  194.     if len(argv) != 3:
  195.         #sys.stderr.write('ERROR: incorrect number of arguments\n')
  196.         sys.stderr.write('USAGE: sax.py CLIENT_DIR SERVER_DIR\n')
  197.         return
  198.     _, client_data, server_data = argv
  199.     tmx_dir = posixpath.join(client_data, CLIENT_MAPS)
  200.     wlk_dir = posixpath.join(server_data, SERVER_WLK)
  201.     npc_dir = posixpath.join(server_data, SERVER_NPCS)
  202.     for arg in os.listdir(tmx_dir):
  203.         base, ext = posixpath.splitext(arg)
  204.         if ext == '.tmx':
  205.             tmx = posixpath.join(tmx_dir, arg)
  206.             print('Parsing %s' % tmx)
  207.             with open(tmx, 'r') as input:
  208.                 p = ContentHandler()
  209.                 p.ParseFile(input)
  210.                 del p
  211.                 #return
  212.  
  213. if __name__ == '__main__':
  214.     main(sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement