configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcrml_parser.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcrml_parser.py	Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,389 @@
+#
+# Copyright (c) 2009 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: 
+#
+
+
+
+
+import re
+import os
+import sys
+import logging
+import xml.parsers.expat
+import codecs
+from hcrplugin.hcr_exceptions import *
+from hcrplugin.hcrrepository import HcrRecord, HcrRepository
+from hcrplugin.hcr_writer import HcrWriter
+from hcrplugin.header_writer import *
+try:
+    from cElementTree import ElementTree
+except ImportError:
+    try:    
+        from elementtree import ElementTree
+    except ImportError:
+        try:
+            from xml.etree import cElementTree as ElementTree
+        except ImportError:
+            from xml.etree import ElementTree
+
+import __init__
+
+from cone.public import exceptions,plugin,utils,api
+
+class HcrmlImpl(plugin.ImplBase):
+    """
+    <class description>
+    """
+    
+    IMPL_TYPE_ID = "hcrml"
+
+    def __init__(self, resource_ref, configuration):
+        plugin.ImplBase.__init__(self, resource_ref, configuration)
+        self.logger = logging.getLogger('cone.hcrml(%s)' % resource_ref)
+        self.configuration = configuration
+        self.hcrml_file = resource_ref
+
+
+    def generate(self, context=None):
+        """
+        Generate the given implementation. 
+        @return: 
+        """
+        outputfile = self.__get_output_filename()
+        if outputfile != None:
+            # Create the path to the output file
+            output_path = os.path.dirname(outputfile)
+            if output_path != '' and not os.path.exists(output_path):
+                os.makedirs(output_path)
+        
+        # For output type 'hcr', write the binary repository file
+        if self.output_obj.type == 'hcr':
+            self.logger.info("Generating binary repository to '%s'" % outputfile)
+            writer = HcrWriter()
+            repo = self.output_obj.get_hcr_repository()
+            data = writer.get_repository_bindata(repo)
+            f = open(outputfile,'wb')
+            try:        f.write(data)
+            finally:    f.close()
+        elif self.output_obj.type == 'header':
+            self.logger.info("Generating header file to '%s'" % outputfile)
+            writer = HeaderWriter(outputfile, self.output_obj)
+            writer.write()
+        elif self.output_obj.type == None:
+            # The HCRML file contains no <output> element, so no output should
+            # be generated
+            pass
+
+    def get_refs(self):
+        return self.refs
+    
+    def list_output_files(self):
+        """
+        Return a list of output files as an array. 
+        """
+        fname = self.__get_output_filename()
+        return [fname] if fname else []
+    
+    def __get_output_filename(self):
+        if self.output_obj.file != None:
+            return os.path.normpath(os.path.join(self.output, self.output_obj.file))
+        else:
+            return None
+
+
+class HcrmlReader(plugin.ReaderBase):
+    NAMESPACE = 'http://www.symbianfoundation.org/xml/hcrml/1'
+    FILE_EXTENSIONS = ['hcrml']
+    
+    def __init__(self, resource_ref, configuration):
+        self.configuration = configuration
+        self.hcrml_file = resource_ref
+        self.refs = []
+        self.namespaces = [self.NAMESPACE]
+        self.doc = None
+    
+    @classmethod
+    def read_impl(cls, resource_ref, configuration, etree):
+        reader = HcrmlReader(resource_ref, configuration)
+        reader.doc = etree
+        
+        impl = HcrmlImpl(resource_ref, configuration)
+        impl.output_obj = reader.read_hcrml_output()
+        impl.refs = reader.refs
+        return impl
+
+    def read_hcrml_output(self, ignore_includes=False):
+        output = Output()
+        
+        # There should only be one <output> element, so use find()
+        out_elem = self.doc.find("{%s}output" % self.namespaces[0])
+        if out_elem != None:
+            version = out_elem.get('version')
+            read_only = out_elem.get('readOnly')
+            file = out_elem.get('file')
+            type = out_elem.get('type')
+            
+            if type == None or type == '':
+                raise NoTypeDefinedInOutPutTagError("Type attribute missing in hcrml file")
+            
+            if type not in ('hcr', 'header'): 
+               raise InvalidTypeDefinedInOutPutTagError("Type attribute invalid in hcrml file: %s" % type)
+           
+            output.version = version
+            output.read_only = read_only
+            output.file = file
+            output.type = type
+         
+            # An <output> element may contain <include> elements for including other
+            # HCRML files, so read and include categories from those
+            if not ignore_includes:
+                included_files = self.read_hcrml_includes(out_elem)
+                read_categories = self.read_categories_from_hcrml_files(included_files)
+                output.categories.extend(read_categories)
+            
+         
+        """ output tag is not mandatory, but there should be some categories included """
+        for cat_elem in self.doc.getiterator("{%s}category" % self.namespaces[0]):
+            category = self.read_hrcml_category(cat_elem)
+            output.categories.append(category)
+        return output 
+    
+    def read_hcrml_includes(self, output_elem):
+        """
+        Read all <include> elements under an <output> element.
+        @return: List of other HCRML files to include.
+        """
+        result = []
+        
+        include_refs = []
+        for include_elem in output_elem.findall("{%s}include" % self.namespaces[0]):
+            ref = include_elem.get('ref')
+            if ref != None: include_refs.append(ref)
+        
+        if include_refs:
+            # There are include refs, construct the list of files that should
+            # be included
+            all_files = self.configuration.list_resources()
+            included_files = []
+            for ref in include_refs:
+                files_by_ref = self.filter_file_list_by_include_ref(all_files, ref)
+                result.extend(files_by_ref)
+        
+        # Make sure that no file is in the list more than once
+        result = list(set(result))
+        return result
+        
+    def read_categories_from_hcrml_files(self, files):
+        """
+        Read all categories from the list of the given HCRML files.
+        """
+        categories = []
+        
+        for file in files:
+            # Skip the current file
+            if os.path.normpath(file) == os.path.normpath(self.hcrml_file):
+                continue
+            
+            # Read the <output> element and append its categories to the result list
+            reader = HcrmlReader(file, self.configuration)
+            reader.doc = self._read_xml_doc_from_resource(file, self.configuration)
+            # Read the output element, but ignore includes, since we are
+            # currently reading from inside an include
+            output_obj = reader.read_hcrml_output(ignore_includes=True)
+            categories.extend(output_obj.categories)
+            
+        return categories
+            
+    def read_hrcml_category(self,cat_elem):
+        category_uid = cat_elem.get('uid')
+        if category_uid == None or category_uid == '':
+           raise NoCategoryUIDInHcrmlFileError("No category uid attribute implemented in hcrml file!")
+        name = cat_elem.get('name')
+        if name == None or name == '':
+           raise NoCategoryNameInHcrmlFileError("No category name attribute implemented in hcrml file!")
+        category = Category()
+        category.name = name
+        try:
+            category.category_uid = long(category_uid)
+        except ValueError:
+            category.category_uid = long(category_uid, 16)
+        category.xml_elem = cat_elem  
+        for setting_elem in cat_elem.getiterator("{%s}setting" % self.namespaces[0]):
+             setting = self.read_hcrml_setting(setting_elem)
+             category.settings.append(setting)
+        return category
+            
+
+    def read_hcrml_setting(self,setting_elem):
+        
+        ref = setting_elem.get('ref')
+        if ref == None or ref == '':
+            raise NoRefInHcrmlFileError("No ref in setting tag attribute implemented in hcrml file!")
+        else:
+            self.refs.append(ref)
+        type = setting_elem.get('type')
+        if type == None or type == '':
+            raise NoTypeAttributeInSettingHcrmlFileError("No type in setting tag attribute implemented in hcrml file ref: %s" % ref )
+        name = setting_elem.get('name')
+        if name == None or name == '':
+            raise NoNameAttributeInSettingHcrmlFileError("No type in setting tag attribute implemented in hcrml file ref: %s" % ref )
+        id = setting_elem.get('id')
+        if id == None or id == '':
+            raise NoIdAttributeInSettingHcrmlFileError("No id in setting tag attribute implemented in hcrml file ref: %s" % ref )
+
+        comment = setting_elem.get('comment')
+        if comment == None:
+            comment = ''
+            
+        
+        setting = Setting(self.configuration)
+        setting.comment = comment
+        setting.name = name
+        setting.ref = ref
+        try:
+            setting.id = long(id)
+        except ValueError:
+            setting.id = long(id, 16)
+        setting.type = type
+        setting.xml_elem = setting_elem
+        for flag_elem in setting_elem.getiterator("{%s}flags" % self.namespaces[0]):
+             flag = self.read_hrcml_flags(setting_elem)
+             setting.flag = flag
+        return setting
+
+    def read_hrcml_flags(self,flag_elem):
+         Uninitialised = flag_elem.get('Uninitialised') 
+         Modifiable = flag_elem.get('Modifiable')
+         Persistent = flag_elem.get('Persistent')
+         flag = Flag()
+         flag.Uninitialised = Uninitialised
+         flag.Modifiable = Modifiable
+         flag.Persistent = Persistent
+         return flag
+     
+    def filter_file_list_by_include_ref(self, files, ref):
+        pattern = ref + '$'
+        pattern = pattern.replace('.', r'\.')
+        pattern = pattern.replace('*', '.*')
+        pattern = '(^|.*/)' + pattern
+        result = []
+        for file in files:
+            if re.match(pattern, file.replace('\\', '/')) != None:
+                result.append(file)
+        return result
+
+
+class Flag(object):
+    def __init__(self):
+        self.Uninitialised = 0
+        self.Modifiable    = 0
+        self.Persistent    = 0
+
+class Setting(object):
+    def __init__(self,configuration):
+        self.name   = None
+        self.ref    = None
+        self.type   = None
+        self.id = None
+        self.flag = None
+        self.comment = ''
+        self.configuration = configuration
+        
+    @property
+    def value(self):
+        dview = self.configuration.get_default_view()
+        feature = dview.get_feature(self.ref)
+        value = feature.get_value()
+        
+        if self.type in (HcrRecord.VALTYPE_ARRAY_INT32, HcrRecord.VALTYPE_ARRAY_UINT32):
+            # Convert string values to numbers
+            value = map(lambda x: self.__str_to_long(x), value)
+        elif self.type == HcrRecord.VALTYPE_BIN_DATA and feature.get_type() == 'string':
+            value = self.__hex_to_bindata(value)
+        return value
+    
+    def __str_to_long(self, str_value):
+        try:
+            return long(str_value)
+        except ValueError:
+            return long(str_value, 16)
+    
+    def __hex_to_bindata(self, hexdata):
+        orig_hexdata = hexdata
+        hexdata = hexdata.replace(' ', '').replace('\r', '').replace('\n', '').replace('\t', '')
+        if len(hexdata) % 2 != 0:
+            raise ValueError("Failed to convert %r into binary data: String length %d (whitespace stripped) is not divisible by 2", orig_hexdata, len(hexdata))
+        for c in hexdata:
+            if c not in "0123456789abcdefABCDEF":
+                raise ValueError("Failed to convert %r into binary data: Not a valid hex string", hexdata)
+        
+        temp = []
+        for i in xrange(len(hexdata) / 2):
+            start = i * 2
+            end   = start + 2 
+            temp.append(chr(int(hexdata[start:end], 16)))
+        return ''.join(temp)
+
+class Category(object):
+    def __init__(self):
+        self.name   = None
+        self.category_uid    = None
+        self.settings = []
+    
+    def get_hcr_records(self):
+        """
+        Return a list of HcrRecord objects created based on this category's settings.
+        """
+        result = []
+        for setting in self.settings:
+            record = HcrRecord(setting.type, setting.value, self.category_uid, setting.id)
+            flag = setting.flag
+            if flag:
+                record.flags = 0
+                if flag.Uninitialised == '1':   record.flags |= HcrRecord.FLAG_UNINITIALIZED
+                if flag.Modifiable == '1':      record.flags |= HcrRecord.FLAG_MODIFIABLE
+                if flag.Persistent == '1':      record.flags |= HcrRecord.FLAG_PERSISTENT
+            result.append(record)
+        return result 
+        
+
+class Output(object):
+    def __init__(self):
+        self.file = None
+        self.type = None
+        self.version = None
+        self.read_only = None
+        self.categories = []
+    
+    def get_hcr_records(self):
+        """
+        Return a list of HcrRecord objects created based on this output object's categories.
+        """
+        result = []
+        for category in self.categories:
+            result.extend(category.get_hcr_records())
+        return result
+    
+    def get_hcr_repository(self):
+        """
+        Return a HcrRepository object created based on this output.
+        
+        The type of this Output object should be 'hcr', otherwise and an exception is raised.
+        """
+        if self.type != 'hcr':
+            raise RuntimeError("get_hcr_repository() called on an Output object with type '%s' (should be 'hcr')" % self.type)
+        
+        return HcrRepository(self.get_hcr_records())
+        
\ No newline at end of file