--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/blocks/framework/src/SymbianUtils/Evalid.py Thu Sep 02 15:02:14 2010 +0800
@@ -0,0 +1,293 @@
+#
+# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Generate checksums for different types of files
+#
+
+import sys
+import os
+import re
+import struct
+import subprocess
+import platform
+try:
+ from hashlib import md5
+except ImportError:
+ import md5
+
+import SymbianUtils
+
+class Evalid(object):
+ '''
+ Provide some of the functionality found in epoc32/tools/EvalidCompare.pm
+
+ generateSignature() - use appropriate method to calculate checksum for a file
+ getUid() - extract Uid from file
+ '''
+
+ class ExternalError(SymbianUtils.SymbianUtilsError):
+ """ An external utility exited with an error """
+
+ ext = ".exe" if platform.system() == "Windows" else ""
+ binPath = os.path.normpath(os.path.join(os.path.dirname(__file__), "bin"))
+ NM = os.path.join(binPath, "nm" + ext)
+ ELFDUMP = os.path.join(binPath, "elfdump" + ext)
+ ELF2E32 = os.path.join(binPath, "elf2e32" + ext)
+ PE_DUMP = os.path.join(binPath, "pe_dump" + ext)
+
+ ELF_DLL_NAME = re.compile(r"#<DLL>(\S+\.\S+)#<\\DLL>")
+ ELF_DEBUG = re.compile(r"^\.(rel\.)?debug_")
+ ELF_P_HEAD = re.compile(r"^\tProgram header offset.*$")
+ ELF_S_HEAD = re.compile(r"^\tSection header offset.*$")
+ PRECOMP_IGNORE = re.compile(r'^# \d+ ".*"( \d)?$')
+ E32_EMPTY = re.compile("Time Stamp:|E32ImageFile|Header CRC:")
+ E32_LOWER = re.compile("imports from")
+ INTEL_OBJECTPATH_WIN = re.compile(r"\.\.\\[^(]*\\")
+ INTEL_OBJECTPATH_NIX = re.compile("\.\.\/[^(]*\/")
+ INTEL_DLLTOOL = re.compile("^(.+ (_head|_))\w+_(EPOC32_\w+(_LIB|_iname))$", re.I)
+
+ @classmethod
+ def typeLookup(cls, type):
+ '''
+ Return the internally used identifier string for the type
+ @todo: Warning
+ @param type: The type
+ @type type: String
+ @return: Internally used type identifier
+ @rtype: String
+ '''
+ if type in ("e32", "default", "elf", "preprocessed_text", "intel", "intel_pe"):
+ return type
+ elif type in ("file", "symbol"):
+ return "default"
+ elif type in ("staticlib", "dso"):
+ return "elf"
+ elif type in ("exe", "plugin", "dll"):
+ return "e32"
+ else:
+ #sys.stderr.write("warning - unknown hashtype %s.\n"%type)
+ return "default"
+
+ @classmethod
+ def generateSignature(cls, path, fileType):
+ '''
+ Generic dispatcher method for file types. Use the appropriate method for
+ I{type} to generate the signature for file at I{path}.
+
+ @param path: The path where the file is located
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ if not isinstance(path, basestring):
+ raise TypeError, "path must be a string"
+ if not path:
+ raise ValueError, "path must not be zero length"
+ path = os.path.normpath(path)
+ fileType = cls.typeLookup(fileType)
+ methodName = "sig_" + fileType
+ if hasattr(cls, methodName):
+ method = getattr(cls, methodName)
+ return method(path)
+ else:
+ raise NotImplementedError("No signature generator for type %s" % fileType)
+
+ @staticmethod
+ def getUid(index, file):
+ '''Get UID of file
+
+ @param index: Which UID
+ @param file: Absolute path
+ @return: UID
+ @rtype: String
+ '''
+ if index not in (1, 2, 3):
+ raise ValueError("Index can only be one of 1, 2 or 3")
+ if os.path.getsize(file) < 12:
+ return None
+ start = (index-1) * 4
+ finish = start + 4
+ f = open(file, "rb")
+ head = f.read(12)
+ f.close()
+ return struct.unpack("<l", head[start:finish])[0]
+
+ @staticmethod
+ def getMd5():
+ '''A convenicence method to use appropriate library regardless of Python
+ version. Maintain compatibility while using hashlib whenever possible.
+
+ @return: md5 object
+ @rtype: md5
+ '''
+ if hasattr(md5, "new"):
+ return md5.new()
+ else:
+ return md5()
+
+ # Signatures for various formats
+
+ @classmethod
+ def sig_e32(cls, path):
+ '''
+ Return the checksum of significant parts using elf2e32
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ bin = cls.ELF2E32 + " --dump --e32input="
+ m = cls.getMd5()
+ fo = os.popen(bin+path, "r", -1)
+ for line in fo:
+ if cls.E32_EMPTY.search(line):
+ line = ""
+ if cls.E32_LOWER.search(line):
+ line = line.lower()
+ m.update(line)
+ if fo.close():
+ raise cls.ExternalError("elf2e32 failed at %s" % path)
+ return m.hexdigest()
+
+ @classmethod
+ def sig_default(cls, path):
+ '''
+ Calculate the checksum of the file without filtering.
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ m = cls.getMd5()
+ f = open(path, "rb")
+ while True:
+ buf = f.read(32*1024)
+ if not buf:
+ break
+ m.update(buf)
+ f.close()
+ return m.hexdigest()
+
+ @classmethod
+ def sig_elf(cls, path):
+ '''
+ Return the checksum of significant parts using elfdump
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ bin = cls.ELFDUMP + " -i "
+ def firstGroupToLc(match):
+ return ("#<DLL>" + match.group(1).lower() + "#<\\DLL>")
+ m = cls.getMd5()
+ fo = os.popen(bin+path, "r", -1)
+ for line in fo:
+ if cls.ELF_P_HEAD.match(line):
+ line = "Program header offset\n"
+ if cls.ELF_S_HEAD.match(line):
+ line = "Section header offset\n"
+ line = cls.ELF_DLL_NAME.sub(firstGroupToLc, line)
+ if cls.ELF_DEBUG.match(line):
+ line = ""
+ #sys.stderr.write(line)
+ m.update(line)
+ if fo.close():
+ raise cls.ExternalError("elfdump failed at %s" % path)
+ return m.hexdigest()
+
+ @classmethod
+ def sig_preprocessed_text(cls, path):
+ '''
+ Return the checksum of significant parts of preprocessed text
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ m = cls.getMd5()
+ f = open(path, "rb")
+ for line in f:
+ line = line.replace("\r\n", "\n")
+ if cls.PRECOMP_IGNORE.search(line):
+ line = "\n"
+ m.update(line)
+ f.close()
+ return m.hexdigest()
+
+ @classmethod
+ def sig_intel_pe(cls, path):
+ '''
+ Return the checksum of significant parts of pe_dump output
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ m = cls.getMd5()
+ fo = os.popen("%s %s" % (cls.PE_DUMP, path), "r", -1)
+ for line in fo:
+ m.update(line)
+ if fo.close():
+ raise cls.ExternalError("pe_dump failed at %s" % path)
+ return m.hexdigest()
+
+
+ @classmethod
+ def sig_intel(cls, path):
+ '''
+ Return the checksum of significant parts using nm
+
+ @param path: The absolute path
+ @type path: String
+ @return: checksum
+ @rtype: String
+ '''
+ m = cls.getMd5()
+ try:
+ s = subprocess.Popen([cls.NM, "--no-sort", path], env=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = s.communicate()
+ except OSError, e:
+ raise cls.ExternalError, "nm failed at %s: %s" % (path, str(e))
+ if s.returncode != 0:
+ raise cls.ExternalError, "nm failed at %s: %s" % (path, err)
+ for line in out.splitlines():
+ # no need for regexps here
+ if line.endswith(":\n") \
+ or line.startswith("BFD: ") \
+ or cls.INTEL_OBJECTPATH_WIN.search(line) \
+ or cls.INTEL_OBJECTPATH_NIX.search(line):
+ line = "\n"
+ match = cls.INTEL_DLLTOOL.search(line)
+ if match:
+ line = "%s_..._%s" % (match.groups()[0], match.groups()[2])
+ line = line.upper()
+ m.update(line)
+
+ if s.returncode != 0:
+ raise cls.ExternalError("nm failed at %s" % path)
+ return m.hexdigest()
+
+def main():
+ path = sys.argv[1]
+ ftype = sys.argv[2]
+ print Evalid.generateSignature(path, ftype)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file