src/tools/py2sis/ensymble/decodemif.py
changeset 0 ca70ae20a155
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/py2sis/ensymble/decodemif.py	Tue Feb 16 10:07:05 2010 +0530
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##############################################################################
+# decodemif.py - Decodes a Symbian OS v9.x multi-image file (MIF)
+# Copyright 2006, 2007 Jussi Ylänen
+#
+# This program is part of Ensymble developer utilities for Symbian OS(TM).
+#
+# Ensymble is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Ensymble is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ensymble; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+# Version history
+# ---------------
+#
+# v0.03 2006-09-22
+# Replaced every possible range(...) with xrange(...) for efficiency
+#
+# v0.02 2006-08-22
+# Added file type recognition (SVG, binary SVG or other)
+#
+# v0.01 2006-08-14
+# Added support for strange index entries (length 0)
+#
+# v0.00 2006-08-13
+# Work started
+##############################################################################
+
+VERSION = "v0.02 2006-09-22"
+
+import sys
+import os
+import struct
+import getopt
+import random
+import tempfile
+
+# Parameters
+MAXMIFFILESIZE      = 1024 * 1024       # Arbitrary maximum size of MIF file
+
+tempdir = None
+dumpcounter = 0
+
+def mkdtemp(template):
+    '''
+    Create a unique temporary directory.
+
+    tempfile.mkdtemp() was introduced in Python v2.3. This is for
+    backward compatibility.
+    '''
+
+    # Cross-platform way to determine a suitable location for temporary files.
+    systemp = tempfile.gettempdir()
+
+    if not template.endswith("XXXXXX"):
+        raise ValueError("invalid template for mkdtemp(): %s" % template)
+
+    for n in xrange(10000):
+        randchars = []
+        for m in xrange(6):
+            randchars.append(random.choice("abcdefghijklmnopqrstuvwxyz"))
+
+        tempdir = os.path.join(systemp, template[: -6]) + "".join(randchars)
+
+        try:
+            os.mkdir(tempdir, 0700)
+            return tempdir
+        except OSError:
+            pass
+
+def dumpdata(data):
+    '''Dumps data to a file in a temporary directory.'''
+
+    global tempdir, dumpcounter
+
+    if tempdir == None:
+        # Create temporary directory for dumped files.
+        tempdir = mkdtemp("decodemif-XXXXXX")
+        dumpcounter = 0
+
+    # Determine file type.
+    if data[0:5] == "<?xml":
+        ext = "svg"
+    elif data[0:4] == '\xcc\x56\xfa\x03':
+        ext = "svgb"
+    else:
+        ext = "dat"
+
+    filename = os.path.join(tempdir, "dump%04d.%s" % (dumpcounter, ext))
+    dumpcounter += 1
+    f = file(filename, "wb")
+    f.write(data)
+    f.close()
+    print "%s written" % filename
+
+def main():
+    global tempdir, dumpcounter
+
+    pgmname     = os.path.basename(sys.argv[0])
+    pgmversion  = VERSION
+
+    try:
+        try:
+            gopt = getopt.gnu_getopt
+        except:
+            # Python <v2.3, GNU-style parameter ordering not supported.
+            gopt = getopt.getopt
+
+        # Parse command line using getopt.
+        short_opts = "t:h"
+        long_opts = [
+            "dumpdir", "help"
+        ]
+        args = gopt(sys.argv[1:], short_opts, long_opts)
+
+        opts = dict(args[0])
+        pargs = args[1]
+
+        if "--help" in opts.keys() or "-h" in opts.keys():
+            # Help requested.
+            print (
+'''
+DecodeMIF - Symbian OS v9.x MIF file decoder %(pgmversion)s
+
+usage: %(pgmname)s [--dumpdir=DIR] [miffiles...]
+
+        -t, --dumpdir       - Directory to use for dumped files (or automatic)
+        miffiles            - MIF files to decode (stdin if not given or -)
+
+''' % locals())
+            return 0
+
+        # A temporary directory is generated by default.
+        tempdir = opts.get("--dumpdir", opts.get("-t", None))
+
+        if len(pargs) == 0:
+            miffilenames = ["-"]
+        else:
+            miffilenames = pargs
+
+        for miffilename in miffilenames:
+            if miffilename == '-':
+                miffile = sys.stdin
+            else:
+                miffile = file(miffilename, "rb")
+
+            try:
+                # Load the whole MIF file as a string.
+                mifdata = miffile.read(MAXMIFFILESIZE)
+                if len(mifdata) == MAXMIFFILESIZE:
+                    raise IOError("%s: file too large" % miffilename)
+            finally:
+                if miffile != sys.stdin:
+                    miffile.close()
+
+            # Verify MIF signature.
+            if mifdata[:4] != "B##4":
+                raise ValueError("%s: not a MIF file" % miffilename)
+
+            if len(mifdata) < 16:
+                raise ValueError("%s: file too short" % miffilename)
+
+            entries = struct.unpack("<L", mifdata[12:16])[0] / 2
+
+            # Verify header length:
+            # 16-byte header, 16 bytes per index entry
+            if len(mifdata) < (16 + 16 * entries):
+                raise ValueError("%s: file too short" % miffilename)
+
+            # Read index.
+            index = []
+            for n in xrange(entries):
+                hdroff = 16 + n * 16
+                a = struct.unpack("<L", mifdata[hdroff +  0:hdroff + 4])[0]
+                b = struct.unpack("<L", mifdata[hdroff +  4:hdroff + 8])[0]
+                c = struct.unpack("<L", mifdata[hdroff +  8:hdroff + 12])[0]
+                d = struct.unpack("<L", mifdata[hdroff + 12:hdroff + 16])[0]
+
+                if b == 0 and d == 0:
+                    # Unknown index entry type, skip it.
+                    continue
+
+                if a != c or b != d:
+                    raise ValueError("%s: invalid index entry %d" %
+                                     (miffilename, n))
+
+                # Check total length of file.
+                if a + b > len(mifdata):
+                    raise ValueError("%s: index %d out of range" %
+                                     (miffilename, n))
+
+                index.append((a, b))
+
+            n = len(index)
+            print "%s: %s %s inside" % (miffilename, n or "no",
+                                        ((n == 1) and "file") or "files")
+
+            # Extract contents.
+            for i in index:
+                offset = i[0]
+                length = i[1]
+                if mifdata[offset:offset + 4] != "C##4":
+                    raise ValueError("%s: invalid file header %d" %
+                                     (miffilename, n))
+
+                print "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" % (
+                    tuple(struct.unpack("<LLLLLLL", mifdata[(offset + 4):
+                                                            (offset + 32)])))
+                dumpdata(mifdata[offset + 32:offset + length + 32])
+    except (TypeError, ValueError, IOError, OSError), e:
+        return "%s: %s" % (pgmname, str(e))
+    except KeyboardInterrupt:
+        return ""
+
+# Call main if run as stand-alone executable.
+if __name__ == '__main__':
+    sys.exit(main())