diff -r 9435b9008a58 -r 934f9131337b releasing/blocks/framework/src/SymbianUtils/Evalid.py --- /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"#(\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("" + 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