2013-10-17 14:05:27 +00:00
|
|
|
#!/usr/bin/env python
|
2009-11-04 09:48:26 +00:00
|
|
|
|
|
|
|
""" Adobe character mapping (CMap) support.
|
|
|
|
|
|
|
|
CMaps provide the mapping between character codes and Unicode
|
|
|
|
code-points to character ids (CIDs).
|
|
|
|
|
|
|
|
More information is available on the Adobe website:
|
|
|
|
|
|
|
|
http://opensource.adobe.com/wiki/display/cmap/CMap+Resources
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
2009-11-03 01:27:30 +00:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import os.path
|
2010-06-13 13:50:24 +00:00
|
|
|
import gzip
|
|
|
|
import cPickle as pickle
|
2011-03-02 14:43:03 +00:00
|
|
|
import struct
|
2009-11-03 13:39:34 +00:00
|
|
|
from psparser import PSStackParser
|
2013-11-07 07:09:44 +00:00
|
|
|
from psparser import PSSyntaxError, PSEOF
|
|
|
|
from psparser import PSLiteral
|
|
|
|
from psparser import literal_name
|
2009-12-19 14:17:00 +00:00
|
|
|
from encodingdb import name2unicode
|
2009-11-15 02:42:05 +00:00
|
|
|
from utils import choplist, nunpack
|
2007-12-31 03:41:45 +00:00
|
|
|
|
|
|
|
|
2013-11-07 08:35:04 +00:00
|
|
|
class CMapError(Exception):
|
|
|
|
pass
|
2008-04-27 11:47:38 +00:00
|
|
|
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
## CMap
|
2009-05-17 06:20:22 +00:00
|
|
|
##
|
2009-12-19 14:17:00 +00:00
|
|
|
class CMap(object):
|
|
|
|
|
|
|
|
debug = 0
|
|
|
|
|
|
|
|
def __init__(self, code2cid=None):
|
|
|
|
self.code2cid = code2cid or {}
|
|
|
|
return
|
|
|
|
|
|
|
|
def is_vertical(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def use_cmap(self, cmap):
|
|
|
|
assert isinstance(cmap, CMap)
|
2013-11-07 08:35:04 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def copy(dst, src):
|
2013-11-07 08:35:04 +00:00
|
|
|
for (k, v) in src.iteritems():
|
2009-12-19 14:17:00 +00:00
|
|
|
if isinstance(v, dict):
|
|
|
|
d = {}
|
|
|
|
dst[k] = d
|
|
|
|
copy(d, v)
|
|
|
|
else:
|
|
|
|
dst[k] = v
|
|
|
|
copy(self.code2cid, cmap.code2cid)
|
|
|
|
return
|
|
|
|
|
|
|
|
def decode(self, code):
|
|
|
|
if self.debug:
|
|
|
|
print >>sys.stderr, 'decode: %r, %r' % (self, code)
|
|
|
|
d = self.code2cid
|
|
|
|
for c in code:
|
|
|
|
c = ord(c)
|
|
|
|
if c in d:
|
|
|
|
d = d[c]
|
|
|
|
if isinstance(d, int):
|
|
|
|
yield d
|
|
|
|
d = self.code2cid
|
|
|
|
else:
|
|
|
|
d = self.code2cid
|
|
|
|
return
|
2009-05-17 06:20:22 +00:00
|
|
|
|
2010-11-14 10:07:34 +00:00
|
|
|
def dump(self, out=sys.stdout, code2cid=None, code=None):
|
|
|
|
if code2cid is None:
|
|
|
|
code2cid = self.code2cid
|
|
|
|
code = ()
|
2013-11-07 08:35:04 +00:00
|
|
|
for (k, v) in sorted(code2cid.iteritems()):
|
2010-11-14 10:07:34 +00:00
|
|
|
c = code+(k,)
|
|
|
|
if isinstance(v, int):
|
2013-11-07 08:35:04 +00:00
|
|
|
out.write('code %r = cid %d\n' % (c, v))
|
2010-11-14 10:07:34 +00:00
|
|
|
else:
|
|
|
|
self.dump(out=out, code2cid=v, code=c)
|
|
|
|
return
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2009-05-17 06:20:22 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
## IdentityCMap
|
2009-11-15 02:42:05 +00:00
|
|
|
##
|
2009-12-19 14:17:00 +00:00
|
|
|
class IdentityCMap(object):
|
2009-03-24 16:26:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def __init__(self, vertical):
|
|
|
|
self.vertical = vertical
|
|
|
|
return
|
2009-03-24 16:26:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def is_vertical(self):
|
|
|
|
return self.vertical
|
|
|
|
|
|
|
|
def decode(self, code):
|
2010-02-07 03:14:00 +00:00
|
|
|
n = len(code)/2
|
|
|
|
if n:
|
2011-03-02 14:43:03 +00:00
|
|
|
return struct.unpack('>%dH' % n, code)
|
2010-02-07 03:14:00 +00:00
|
|
|
else:
|
|
|
|
return ()
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
|
|
|
|
## UnicodeMap
|
2007-12-31 03:41:45 +00:00
|
|
|
##
|
2009-12-19 14:17:00 +00:00
|
|
|
class UnicodeMap(object):
|
2009-01-05 04:40:50 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
debug = 0
|
|
|
|
|
2010-01-01 03:09:26 +00:00
|
|
|
def __init__(self, cid2unichr=None):
|
|
|
|
self.cid2unichr = cid2unichr or {}
|
2009-12-19 14:17:00 +00:00
|
|
|
return
|
|
|
|
|
2010-01-01 03:09:26 +00:00
|
|
|
def get_unichr(self, cid):
|
2009-12-19 14:17:00 +00:00
|
|
|
if self.debug:
|
2010-01-01 03:09:26 +00:00
|
|
|
print >>sys.stderr, 'get_unichr: %r, %r' % (self, cid)
|
|
|
|
return self.cid2unichr[cid]
|
2009-12-19 14:17:00 +00:00
|
|
|
|
2010-11-14 10:07:34 +00:00
|
|
|
def dump(self, out=sys.stdout):
|
2013-11-07 08:35:04 +00:00
|
|
|
for (k, v) in sorted(self.cid2unichr.iteritems()):
|
|
|
|
out.write('cid %d = unicode %r\n' % (k, v))
|
2010-11-14 10:07:34 +00:00
|
|
|
return
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
|
|
|
|
## FileCMap
|
|
|
|
##
|
|
|
|
class FileCMap(CMap):
|
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def __init__(self):
|
2009-12-19 14:17:00 +00:00
|
|
|
CMap.__init__(self)
|
2009-10-24 04:41:59 +00:00
|
|
|
self.attrs = {}
|
|
|
|
return
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<CMap: %s>' % self.attrs.get('CMapName')
|
|
|
|
|
|
|
|
def is_vertical(self):
|
2010-10-17 05:13:39 +00:00
|
|
|
return self.attrs.get('WMode', 0) != 0
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def set_attr(self, k, v):
|
|
|
|
self.attrs[k] = v
|
|
|
|
return
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def add_code2cid(self, code, cid):
|
|
|
|
assert isinstance(code, str) and isinstance(cid, int)
|
|
|
|
d = self.code2cid
|
|
|
|
for c in code[:-1]:
|
|
|
|
c = ord(c)
|
|
|
|
if c in d:
|
|
|
|
d = d[c]
|
|
|
|
else:
|
|
|
|
t = {}
|
|
|
|
d[c] = t
|
2013-11-07 08:35:04 +00:00
|
|
|
d = t
|
2009-12-19 14:17:00 +00:00
|
|
|
c = ord(code[-1])
|
|
|
|
d[c] = cid
|
|
|
|
return
|
2009-10-24 04:41:59 +00:00
|
|
|
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
## FileUnicodeMap
|
2007-12-31 03:41:45 +00:00
|
|
|
##
|
2009-12-19 14:17:00 +00:00
|
|
|
class FileUnicodeMap(UnicodeMap):
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def __init__(self):
|
|
|
|
UnicodeMap.__init__(self)
|
|
|
|
self.attrs = {}
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def __repr__(self):
|
2009-12-19 14:17:00 +00:00
|
|
|
return '<UnicodeMap: %s>' % self.attrs.get('CMapName')
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def set_attr(self, k, v):
|
|
|
|
self.attrs[k] = v
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
2010-01-01 03:09:26 +00:00
|
|
|
def add_cid2unichr(self, cid, code):
|
2009-12-19 14:17:00 +00:00
|
|
|
assert isinstance(cid, int)
|
|
|
|
if isinstance(code, PSLiteral):
|
|
|
|
# Interpret as an Adobe glyph name.
|
2010-08-26 15:02:46 +00:00
|
|
|
self.cid2unichr[cid] = name2unicode(code.name)
|
2009-12-19 14:17:00 +00:00
|
|
|
elif isinstance(code, str):
|
|
|
|
# Interpret as UTF-16BE.
|
2010-01-01 03:09:26 +00:00
|
|
|
self.cid2unichr[cid] = unicode(code, 'UTF-16BE', 'ignore')
|
2009-12-19 14:17:00 +00:00
|
|
|
elif isinstance(code, int):
|
2010-01-01 03:09:26 +00:00
|
|
|
self.cid2unichr[cid] = unichr(code)
|
2009-12-19 14:17:00 +00:00
|
|
|
else:
|
|
|
|
raise TypeError(code)
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
## PyCMap
|
|
|
|
##
|
|
|
|
class PyCMap(CMap):
|
|
|
|
|
|
|
|
def __init__(self, name, module):
|
|
|
|
CMap.__init__(self, module.CODE2CID)
|
|
|
|
self.name = name
|
|
|
|
self._is_vertical = module.IS_VERTICAL
|
|
|
|
return
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<PyCMap: %s>' % (self.name)
|
|
|
|
|
|
|
|
def is_vertical(self):
|
|
|
|
return self._is_vertical
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
|
|
|
|
## PyUnicodeMap
|
|
|
|
##
|
|
|
|
class PyUnicodeMap(UnicodeMap):
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def __init__(self, name, module, vertical):
|
|
|
|
if vertical:
|
2010-01-01 03:09:26 +00:00
|
|
|
cid2unichr = module.CID2UNICHR_V
|
2009-12-19 14:17:00 +00:00
|
|
|
else:
|
2010-01-01 03:09:26 +00:00
|
|
|
cid2unichr = module.CID2UNICHR_H
|
|
|
|
UnicodeMap.__init__(self, cid2unichr)
|
2009-12-19 14:17:00 +00:00
|
|
|
self.name = name
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
2007-12-31 03:41:45 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '<PyUnicodeMap: %s>' % (self.name)
|
|
|
|
|
2007-12-31 03:41:45 +00:00
|
|
|
|
|
|
|
## CMapDB
|
|
|
|
##
|
2008-07-09 15:15:32 +00:00
|
|
|
class CMapDB(object):
|
2007-12-31 03:41:45 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
debug = 0
|
2010-06-13 13:50:24 +00:00
|
|
|
_cmap_cache = {}
|
|
|
|
_umap_cache = {}
|
2013-11-07 07:14:53 +00:00
|
|
|
|
2013-11-07 08:35:04 +00:00
|
|
|
class CMapNotFound(CMapError):
|
|
|
|
pass
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2010-06-13 13:50:24 +00:00
|
|
|
@classmethod
|
|
|
|
def _load_data(klass, name):
|
|
|
|
filename = '%s.pickle.gz' % name
|
|
|
|
if klass.debug:
|
|
|
|
print >>sys.stderr, 'loading:', name
|
2013-11-07 08:35:04 +00:00
|
|
|
cmap_paths = (os.environ.get('CMAP_PATH', '/usr/share/pdfminer/'),
|
|
|
|
os.path.join(os.path.dirname(__file__), 'cmap'),)
|
2011-07-31 08:05:07 +00:00
|
|
|
for directory in cmap_paths:
|
2010-06-13 13:50:24 +00:00
|
|
|
path = os.path.join(directory, filename)
|
|
|
|
if os.path.exists(path):
|
|
|
|
gzfile = gzip.open(path)
|
|
|
|
try:
|
|
|
|
return type(name, (), pickle.loads(gzfile.read()))
|
|
|
|
finally:
|
|
|
|
gzfile.close()
|
|
|
|
else:
|
|
|
|
raise CMapDB.CMapNotFound(name)
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
@classmethod
|
|
|
|
def get_cmap(klass, name):
|
|
|
|
if name == 'Identity-H':
|
|
|
|
return IdentityCMap(False)
|
|
|
|
elif name == 'Identity-V':
|
|
|
|
return IdentityCMap(True)
|
|
|
|
try:
|
2010-06-13 13:50:24 +00:00
|
|
|
return klass._cmap_cache[name]
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
data = klass._load_data(name)
|
|
|
|
klass._cmap_cache[name] = cmap = PyCMap(name, data)
|
|
|
|
return cmap
|
2009-10-24 04:41:59 +00:00
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
@classmethod
|
|
|
|
def get_unicode_map(klass, name, vertical=False):
|
|
|
|
try:
|
2010-06-13 13:50:24 +00:00
|
|
|
return klass._umap_cache[name][vertical]
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
data = klass._load_data('to-unicode-%s' % name)
|
|
|
|
klass._umap_cache[name] = umaps = [PyUnicodeMap(name, data, v) for v in (False, True)]
|
|
|
|
return umaps[vertical]
|
2007-12-31 03:41:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
## CMapParser
|
|
|
|
##
|
|
|
|
class CMapParser(PSStackParser):
|
|
|
|
|
2009-12-19 14:17:00 +00:00
|
|
|
def __init__(self, cmap, fp):
|
2009-10-24 04:41:59 +00:00
|
|
|
PSStackParser.__init__(self, fp)
|
|
|
|
self.cmap = cmap
|
2013-10-17 12:40:43 +00:00
|
|
|
# some ToUnicode maps don't have "begincmap" keyword.
|
|
|
|
self._in_cmap = True
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
2008-02-03 09:36:34 +00:00
|
|
|
|
2009-10-24 04:41:59 +00:00
|
|
|
def run(self):
|
|
|
|
try:
|
|
|
|
self.nextobject()
|
|
|
|
except PSEOF:
|
|
|
|
pass
|
|
|
|
return
|
|
|
|
|
|
|
|
def do_keyword(self, pos, token):
|
|
|
|
name = token.name
|
|
|
|
if name == 'begincmap':
|
2009-12-19 14:17:00 +00:00
|
|
|
self._in_cmap = True
|
2009-10-24 04:41:59 +00:00
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
elif name == 'endcmap':
|
2009-12-19 14:17:00 +00:00
|
|
|
self._in_cmap = False
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
2013-11-07 08:35:04 +00:00
|
|
|
if not self._in_cmap:
|
|
|
|
return
|
2009-10-24 04:41:59 +00:00
|
|
|
#
|
|
|
|
if name == 'def':
|
|
|
|
try:
|
2013-11-07 08:35:04 +00:00
|
|
|
((_, k), (_, v)) = self.pop(2)
|
2009-12-19 14:17:00 +00:00
|
|
|
self.cmap.set_attr(literal_name(k), v)
|
2009-10-24 04:41:59 +00:00
|
|
|
except PSSyntaxError:
|
|
|
|
pass
|
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'usecmap':
|
2009-12-19 14:17:00 +00:00
|
|
|
try:
|
2013-11-07 08:35:04 +00:00
|
|
|
((_, cmapname),) = self.pop(1)
|
2009-12-19 14:17:00 +00:00
|
|
|
self.cmap.use_cmap(CMapDB.get_cmap(literal_name(cmapname)))
|
|
|
|
except PSSyntaxError:
|
|
|
|
pass
|
|
|
|
except CMapDB.CMapNotFound:
|
|
|
|
pass
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'begincodespacerange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endcodespacerange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'begincidrange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endcidrange':
|
2013-11-07 08:35:04 +00:00
|
|
|
objs = [obj for (__, obj) in self.popall()]
|
|
|
|
for (s, e, cid) in choplist(3, objs):
|
2009-10-24 04:41:59 +00:00
|
|
|
if (not isinstance(s, str) or not isinstance(e, str) or
|
2013-11-07 08:35:04 +00:00
|
|
|
not isinstance(cid, int) or len(s) != len(e)):
|
|
|
|
continue
|
2009-10-24 04:41:59 +00:00
|
|
|
sprefix = s[:-4]
|
|
|
|
eprefix = e[:-4]
|
2013-11-07 08:35:04 +00:00
|
|
|
if sprefix != eprefix:
|
|
|
|
continue
|
2009-10-24 04:41:59 +00:00
|
|
|
svar = s[-4:]
|
|
|
|
evar = e[-4:]
|
|
|
|
s1 = nunpack(svar)
|
|
|
|
e1 = nunpack(evar)
|
|
|
|
vlen = len(svar)
|
|
|
|
#assert s1 <= e1
|
|
|
|
for i in xrange(e1-s1+1):
|
2013-11-07 08:35:04 +00:00
|
|
|
x = sprefix+struct.pack('>L', s1+i)[-vlen:]
|
2009-12-19 14:17:00 +00:00
|
|
|
self.cmap.add_code2cid(x, cid+i)
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'begincidchar':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endcidchar':
|
2013-11-07 08:35:04 +00:00
|
|
|
objs = [obj for (__, obj) in self.popall()]
|
|
|
|
for (cid, code) in choplist(2, objs):
|
2009-10-24 04:41:59 +00:00
|
|
|
if isinstance(code, str) and isinstance(cid, str):
|
2009-12-19 14:17:00 +00:00
|
|
|
self.cmap.add_code2cid(code, nunpack(cid))
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'beginbfrange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endbfrange':
|
2013-11-07 08:35:04 +00:00
|
|
|
objs = [obj for (__, obj) in self.popall()]
|
|
|
|
for (s, e, code) in choplist(3, objs):
|
2009-10-24 04:41:59 +00:00
|
|
|
if (not isinstance(s, str) or not isinstance(e, str) or
|
2013-11-07 08:35:04 +00:00
|
|
|
len(s) != len(e)):
|
|
|
|
continue
|
2009-10-24 04:41:59 +00:00
|
|
|
s1 = nunpack(s)
|
|
|
|
e1 = nunpack(e)
|
|
|
|
#assert s1 <= e1
|
|
|
|
if isinstance(code, list):
|
|
|
|
for i in xrange(e1-s1+1):
|
2010-01-01 03:09:26 +00:00
|
|
|
self.cmap.add_cid2unichr(s1+i, code[i])
|
2009-10-24 04:41:59 +00:00
|
|
|
else:
|
|
|
|
var = code[-4:]
|
|
|
|
base = nunpack(var)
|
|
|
|
prefix = code[:-4]
|
|
|
|
vlen = len(var)
|
|
|
|
for i in xrange(e1-s1+1):
|
2013-11-07 08:35:04 +00:00
|
|
|
x = prefix+struct.pack('>L', base+i)[-vlen:]
|
2010-01-01 03:09:26 +00:00
|
|
|
self.cmap.add_cid2unichr(s1+i, x)
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'beginbfchar':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endbfchar':
|
2013-11-07 08:35:04 +00:00
|
|
|
objs = [obj for (__, obj) in self.popall()]
|
|
|
|
for (cid, code) in choplist(2, objs):
|
2009-10-24 04:41:59 +00:00
|
|
|
if isinstance(cid, str) and isinstance(code, str):
|
2010-01-01 03:09:26 +00:00
|
|
|
self.cmap.add_cid2unichr(nunpack(cid), code)
|
2009-10-24 04:41:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if name == 'beginnotdefrange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
if name == 'endnotdefrange':
|
|
|
|
self.popall()
|
|
|
|
return
|
|
|
|
|
|
|
|
self.push((pos, token))
|
|
|
|
return
|
2010-02-07 03:14:00 +00:00
|
|
|
|
2013-11-07 08:35:04 +00:00
|
|
|
|
2010-02-07 03:14:00 +00:00
|
|
|
# test
|
|
|
|
def main(argv):
|
|
|
|
args = argv[1:]
|
|
|
|
for fname in args:
|
|
|
|
fp = file(fname, 'rb')
|
|
|
|
cmap = FileUnicodeMap()
|
2010-11-14 10:07:34 +00:00
|
|
|
#cmap = FileCMap()
|
2010-02-07 03:14:00 +00:00
|
|
|
CMapParser(cmap, fp).run()
|
|
|
|
fp.close()
|
2010-11-14 10:07:34 +00:00
|
|
|
cmap.dump()
|
2010-02-07 03:14:00 +00:00
|
|
|
return
|
|
|
|
|
2013-11-07 08:35:04 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main(sys.argv))
|