src/tools/py2sis/ensymble/rscfile.py
changeset 0 ca70ae20a155
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tools/py2sis/ensymble/rscfile.py	Tue Feb 16 10:07:05 2010 +0530
@@ -0,0 +1,202 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##############################################################################
+# rscfile.py - Symbian OS compiled resource file (RSC) utilities
+# Copyright 2006, 2007 Jussi Ylänen
+#
+# This file 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
+##############################################################################
+
+import struct
+
+import symbianutil
+
+
+##############################################################################
+# Module-level functions which are normally only used by this module
+##############################################################################
+
+def makeuidfromoffset(offset):
+    '''Convert a Symbian OS resource file offset to a UID.
+
+    ---- From rcomp v7.01 source ----
+    space: 0, A: 1, B: 2, ..., Z: 26
+
+    ABCD corresponds to the number 4321 which becomes
+    ((4*27 + 3) * 27 + 2) * 27 + 1.
+    ----                         ----
+
+    The description above contains an error. The actual situation
+    is reversed: ABCD corresponds to the number 1234 which results in
+    ((1*27 + 2) * 27 + 3) * 27 + 4.
+    '''
+
+    if len(offset) not in range(1, 5):
+        raise ValueError("offset must be four characters or less")
+    uid = 0L
+    offset = offset.upper()
+    for c in offset:
+        try:
+            ordc = " ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(c)
+        except ValueError:
+            raise ValueError("invalid character '%s' in offset" % c)
+        uid *= 27
+        uid += ordc
+    return uid
+
+
+##############################################################################
+# Resource class for containing binary fields
+##############################################################################
+
+class Resource(object):
+    '''A Symbian OS resource type
+
+    Limitations:
+
+    - Write only
+    - Available types are limited to BYTE, WORD, LONG, LLINK and LTEXT.
+    - Unicode compression is not supported.'''
+
+    def __init__(self, fieldtypes, *args):
+        self.fieldtypes = fieldtypes
+        self.fieldvalues = []
+
+        if len(self.fieldtypes) != len(args):
+            raise ValueError("invalid number of field values")
+
+        offset = 0
+        for n in xrange(len(args)):
+            ftype = self.fieldtypes[n]
+            fval = args[n]
+            if ftype == "BYTE":
+                if fval < 0:
+                    fval += 0x100
+                if fval < 0 or fval > 255:
+                    raise ValueError("byte integer too large")
+                self.fieldvalues.append(struct.pack("<B", fval))
+                offset += 1
+            elif ftype == "WORD":
+                if fval < 0:
+                    fval += 0x10000
+                if fval < 0 or fval > 65535:
+                    raise ValueError("word integer too large")
+                self.fieldvalues.append(struct.pack("<H", fval))
+                offset += 2
+            elif ftype == "LONG" or ftype == "LLINK":
+                if fval < 0:
+                    fval += 0x100000000L
+                if fval < 0 or fval > 4294967295:
+                    raise ValueError("long integer too large")
+                self.fieldvalues.append(struct.pack("<L", fval))
+                offset += 4
+            elif ftype == "LTEXT":
+                if len(fval) > 255:
+                    raise ValueError("Unicode string too long")
+                self.fieldvalues.append(struct.pack("<B", len(fval)))
+                offset += 1
+                if len(fval) > 0:
+                    if (offset & 1) != 0:
+                        # Odd offset. Add padding byte (only if length > 0).
+                        self.fieldvalues.append(struct.pack("B", 0xab))
+                        offset += 1
+                    fval_enc = fval.encode("UTF-16LE")
+                    self.fieldvalues.append(fval_enc)
+                    offset += len(fval_enc)
+
+            # TODO: Arrays, recursive structs
+            # TODO: TEXT, DOUBLE, BUF, BUF8, BUF<n>, LINK, SRLINK
+
+    def tostring(self):
+        return "".join(self.fieldvalues)
+
+    # TODO: fromstring()
+
+
+##############################################################################
+# RSCWriter class for creating Symbian OS compiled resource files (RSC)
+##############################################################################
+
+class RSCWriter(object):
+    '''A Symbian OS compiled resource file (RSC) file generator
+
+    Limitations:
+
+    - Output format is always "Compressed Unicode resource format".
+    - Despite the format name, nothing is compressed.'''
+
+    def __init__(self, uid2, uid3 = None, offset = None):
+        self.resources = []
+
+        if ((uid3 == None and offset == None) or
+            (uid3 != None and offset != None)):
+            raise AttributeError("one of uid3 or offset required, not both")
+
+        self.flags = 0x00
+        if offset != None:
+            try:
+                uid3 = makeuidfromoffset(offset)
+            except:
+                raise ValueError("invalid offset '%s'" % offset)
+            self.flags = 0x01
+
+        self.uid2 = uid2
+        self.uid3 = uid3
+
+    def addresource(self, resource):
+        self.addrawresource(resource.tostring())
+
+    def addrawresource(self, string):
+        self.resources.append(string)
+
+    def tostring(self):
+        # UIDs (UID1 always 0x101f4a6b)
+        fields = [symbianutil.uidstostring(0x101f4a6bL, self.uid2, self.uid3)]
+
+        # Flags
+        fields.append(struct.pack("<B", self.flags))
+
+        # Longest resource (to be updated)
+        fields.append("\0\0")
+
+        # Unicode compression bitmap (no compression)
+        fields.append("\0" * ((len(self.resources) + 7) / 8))
+
+        # Resource contents
+        offsets = []
+        foffset = len("".join(fields))
+        maxrlen = 0
+        for res in self.resources:
+            # Find longest resource.
+            rlen = len(res)
+            if rlen > maxrlen:
+                maxrlen = rlen
+            offsets.append(foffset)
+            fields.append(res)
+            foffset += rlen
+        offsets.append(foffset)
+
+        # Update longest resource.
+        fields[2] = struct.pack("<H", maxrlen)
+
+        # Resource index
+        for off in offsets:
+            fields.append(struct.pack("<H", off))
+
+        # TODO: Ineffiecient. Improve.
+        return "".join(fields)