configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcrml_parser.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 
       
    18 
       
    19 
       
    20 import re
       
    21 import os
       
    22 import sys
       
    23 import logging
       
    24 import xml.parsers.expat
       
    25 import codecs
       
    26 from hcrplugin.hcr_exceptions import *
       
    27 from hcrplugin.hcrrepository import HcrRecord, HcrRepository
       
    28 from hcrplugin.hcr_writer import HcrWriter
       
    29 from hcrplugin.header_writer import *
       
    30 try:
       
    31     from cElementTree import ElementTree
       
    32 except ImportError:
       
    33     try:    
       
    34         from elementtree import ElementTree
       
    35     except ImportError:
       
    36         try:
       
    37             from xml.etree import cElementTree as ElementTree
       
    38         except ImportError:
       
    39             from xml.etree import ElementTree
       
    40 
       
    41 import __init__
       
    42 
       
    43 from cone.public import exceptions,plugin,utils,api
       
    44 
       
    45 class HcrmlImpl(plugin.ImplBase):
       
    46     """
       
    47     <class description>
       
    48     """
       
    49     
       
    50     IMPL_TYPE_ID = "hcrml"
       
    51 
       
    52     def __init__(self, resource_ref, configuration):
       
    53         plugin.ImplBase.__init__(self, resource_ref, configuration)
       
    54         self.logger = logging.getLogger('cone.hcrml(%s)' % resource_ref)
       
    55         self.configuration = configuration
       
    56         self.hcrml_file = resource_ref
       
    57 
       
    58 
       
    59     def generate(self, context=None):
       
    60         """
       
    61         Generate the given implementation. 
       
    62         @return: 
       
    63         """
       
    64         outputfile = self.__get_output_filename()
       
    65         if outputfile != None:
       
    66             # Create the path to the output file
       
    67             output_path = os.path.dirname(outputfile)
       
    68             if output_path != '' and not os.path.exists(output_path):
       
    69                 os.makedirs(output_path)
       
    70         
       
    71         # For output type 'hcr', write the binary repository file
       
    72         if self.output_obj.type == 'hcr':
       
    73             self.logger.info("Generating binary repository to '%s'" % outputfile)
       
    74             writer = HcrWriter()
       
    75             repo = self.output_obj.get_hcr_repository()
       
    76             data = writer.get_repository_bindata(repo)
       
    77             f = open(outputfile,'wb')
       
    78             try:        f.write(data)
       
    79             finally:    f.close()
       
    80         elif self.output_obj.type == 'header':
       
    81             self.logger.info("Generating header file to '%s'" % outputfile)
       
    82             writer = HeaderWriter(outputfile, self.output_obj)
       
    83             writer.write()
       
    84         elif self.output_obj.type == None:
       
    85             # The HCRML file contains no <output> element, so no output should
       
    86             # be generated
       
    87             pass
       
    88 
       
    89     def get_refs(self):
       
    90         return self.refs
       
    91     
       
    92     def list_output_files(self):
       
    93         """
       
    94         Return a list of output files as an array. 
       
    95         """
       
    96         fname = self.__get_output_filename()
       
    97         return [fname] if fname else []
       
    98     
       
    99     def __get_output_filename(self):
       
   100         if self.output_obj.file != None:
       
   101             return os.path.normpath(os.path.join(self.output, self.output_obj.file))
       
   102         else:
       
   103             return None
       
   104 
       
   105 
       
   106 class HcrmlReader(plugin.ReaderBase):
       
   107     NAMESPACE = 'http://www.symbianfoundation.org/xml/hcrml/1'
       
   108     FILE_EXTENSIONS = ['hcrml']
       
   109     
       
   110     def __init__(self, resource_ref, configuration):
       
   111         self.configuration = configuration
       
   112         self.hcrml_file = resource_ref
       
   113         self.refs = []
       
   114         self.namespaces = [self.NAMESPACE]
       
   115         self.doc = None
       
   116     
       
   117     @classmethod
       
   118     def read_impl(cls, resource_ref, configuration, etree):
       
   119         reader = HcrmlReader(resource_ref, configuration)
       
   120         reader.doc = etree
       
   121         
       
   122         impl = HcrmlImpl(resource_ref, configuration)
       
   123         impl.output_obj = reader.read_hcrml_output()
       
   124         impl.refs = reader.refs
       
   125         return impl
       
   126 
       
   127     def read_hcrml_output(self, ignore_includes=False):
       
   128         output = Output()
       
   129         
       
   130         # There should only be one <output> element, so use find()
       
   131         out_elem = self.doc.find("{%s}output" % self.namespaces[0])
       
   132         if out_elem != None:
       
   133             version = out_elem.get('version')
       
   134             read_only = out_elem.get('readOnly')
       
   135             file = out_elem.get('file')
       
   136             type = out_elem.get('type')
       
   137             
       
   138             if type == None or type == '':
       
   139                 raise NoTypeDefinedInOutPutTagError("Type attribute missing in hcrml file")
       
   140             
       
   141             if type not in ('hcr', 'header'): 
       
   142                raise InvalidTypeDefinedInOutPutTagError("Type attribute invalid in hcrml file: %s" % type)
       
   143            
       
   144             output.version = version
       
   145             output.read_only = read_only
       
   146             output.file = file
       
   147             output.type = type
       
   148          
       
   149             # An <output> element may contain <include> elements for including other
       
   150             # HCRML files, so read and include categories from those
       
   151             if not ignore_includes:
       
   152                 included_files = self.read_hcrml_includes(out_elem)
       
   153                 read_categories = self.read_categories_from_hcrml_files(included_files)
       
   154                 output.categories.extend(read_categories)
       
   155             
       
   156          
       
   157         """ output tag is not mandatory, but there should be some categories included """
       
   158         for cat_elem in self.doc.getiterator("{%s}category" % self.namespaces[0]):
       
   159             category = self.read_hrcml_category(cat_elem)
       
   160             output.categories.append(category)
       
   161         return output 
       
   162     
       
   163     def read_hcrml_includes(self, output_elem):
       
   164         """
       
   165         Read all <include> elements under an <output> element.
       
   166         @return: List of other HCRML files to include.
       
   167         """
       
   168         result = []
       
   169         
       
   170         include_refs = []
       
   171         for include_elem in output_elem.findall("{%s}include" % self.namespaces[0]):
       
   172             ref = include_elem.get('ref')
       
   173             if ref != None: include_refs.append(ref)
       
   174         
       
   175         if include_refs:
       
   176             # There are include refs, construct the list of files that should
       
   177             # be included
       
   178             all_files = self.configuration.list_resources()
       
   179             included_files = []
       
   180             for ref in include_refs:
       
   181                 files_by_ref = self.filter_file_list_by_include_ref(all_files, ref)
       
   182                 result.extend(files_by_ref)
       
   183         
       
   184         # Make sure that no file is in the list more than once
       
   185         result = list(set(result))
       
   186         return result
       
   187         
       
   188     def read_categories_from_hcrml_files(self, files):
       
   189         """
       
   190         Read all categories from the list of the given HCRML files.
       
   191         """
       
   192         categories = []
       
   193         
       
   194         for file in files:
       
   195             # Skip the current file
       
   196             if os.path.normpath(file) == os.path.normpath(self.hcrml_file):
       
   197                 continue
       
   198             
       
   199             # Read the <output> element and append its categories to the result list
       
   200             reader = HcrmlReader(file, self.configuration)
       
   201             reader.doc = self._read_xml_doc_from_resource(file, self.configuration)
       
   202             # Read the output element, but ignore includes, since we are
       
   203             # currently reading from inside an include
       
   204             output_obj = reader.read_hcrml_output(ignore_includes=True)
       
   205             categories.extend(output_obj.categories)
       
   206             
       
   207         return categories
       
   208             
       
   209     def read_hrcml_category(self,cat_elem):
       
   210         category_uid = cat_elem.get('uid')
       
   211         if category_uid == None or category_uid == '':
       
   212            raise NoCategoryUIDInHcrmlFileError("No category uid attribute implemented in hcrml file!")
       
   213         name = cat_elem.get('name')
       
   214         if name == None or name == '':
       
   215            raise NoCategoryNameInHcrmlFileError("No category name attribute implemented in hcrml file!")
       
   216         category = Category()
       
   217         category.name = name
       
   218         try:
       
   219             category.category_uid = long(category_uid)
       
   220         except ValueError:
       
   221             category.category_uid = long(category_uid, 16)
       
   222         category.xml_elem = cat_elem  
       
   223         for setting_elem in cat_elem.getiterator("{%s}setting" % self.namespaces[0]):
       
   224              setting = self.read_hcrml_setting(setting_elem)
       
   225              category.settings.append(setting)
       
   226         return category
       
   227             
       
   228 
       
   229     def read_hcrml_setting(self,setting_elem):
       
   230         
       
   231         ref = setting_elem.get('ref')
       
   232         if ref == None or ref == '':
       
   233             raise NoRefInHcrmlFileError("No ref in setting tag attribute implemented in hcrml file!")
       
   234         else:
       
   235             self.refs.append(ref)
       
   236         type = setting_elem.get('type')
       
   237         if type == None or type == '':
       
   238             raise NoTypeAttributeInSettingHcrmlFileError("No type in setting tag attribute implemented in hcrml file ref: %s" % ref )
       
   239         name = setting_elem.get('name')
       
   240         if name == None or name == '':
       
   241             raise NoNameAttributeInSettingHcrmlFileError("No type in setting tag attribute implemented in hcrml file ref: %s" % ref )
       
   242         id = setting_elem.get('id')
       
   243         if id == None or id == '':
       
   244             raise NoIdAttributeInSettingHcrmlFileError("No id in setting tag attribute implemented in hcrml file ref: %s" % ref )
       
   245 
       
   246         comment = setting_elem.get('comment')
       
   247         if comment == None:
       
   248             comment = ''
       
   249             
       
   250         
       
   251         setting = Setting(self.configuration)
       
   252         setting.comment = comment
       
   253         setting.name = name
       
   254         setting.ref = ref
       
   255         try:
       
   256             setting.id = long(id)
       
   257         except ValueError:
       
   258             setting.id = long(id, 16)
       
   259         setting.type = type
       
   260         setting.xml_elem = setting_elem
       
   261         for flag_elem in setting_elem.getiterator("{%s}flags" % self.namespaces[0]):
       
   262              flag = self.read_hrcml_flags(setting_elem)
       
   263              setting.flag = flag
       
   264         return setting
       
   265 
       
   266     def read_hrcml_flags(self,flag_elem):
       
   267          Uninitialised = flag_elem.get('Uninitialised') 
       
   268          Modifiable = flag_elem.get('Modifiable')
       
   269          Persistent = flag_elem.get('Persistent')
       
   270          flag = Flag()
       
   271          flag.Uninitialised = Uninitialised
       
   272          flag.Modifiable = Modifiable
       
   273          flag.Persistent = Persistent
       
   274          return flag
       
   275      
       
   276     def filter_file_list_by_include_ref(self, files, ref):
       
   277         pattern = ref + '$'
       
   278         pattern = pattern.replace('.', r'\.')
       
   279         pattern = pattern.replace('*', '.*')
       
   280         pattern = '(^|.*/)' + pattern
       
   281         result = []
       
   282         for file in files:
       
   283             if re.match(pattern, file.replace('\\', '/')) != None:
       
   284                 result.append(file)
       
   285         return result
       
   286 
       
   287 
       
   288 class Flag(object):
       
   289     def __init__(self):
       
   290         self.Uninitialised = 0
       
   291         self.Modifiable    = 0
       
   292         self.Persistent    = 0
       
   293 
       
   294 class Setting(object):
       
   295     def __init__(self,configuration):
       
   296         self.name   = None
       
   297         self.ref    = None
       
   298         self.type   = None
       
   299         self.id = None
       
   300         self.flag = None
       
   301         self.comment = ''
       
   302         self.configuration = configuration
       
   303         
       
   304     @property
       
   305     def value(self):
       
   306         dview = self.configuration.get_default_view()
       
   307         feature = dview.get_feature(self.ref)
       
   308         value = feature.get_value()
       
   309         
       
   310         if self.type in (HcrRecord.VALTYPE_ARRAY_INT32, HcrRecord.VALTYPE_ARRAY_UINT32):
       
   311             # Convert string values to numbers
       
   312             value = map(lambda x: self.__str_to_long(x), value)
       
   313         elif self.type == HcrRecord.VALTYPE_BIN_DATA and feature.get_type() == 'string':
       
   314             value = self.__hex_to_bindata(value)
       
   315         return value
       
   316     
       
   317     def __str_to_long(self, str_value):
       
   318         try:
       
   319             return long(str_value)
       
   320         except ValueError:
       
   321             return long(str_value, 16)
       
   322     
       
   323     def __hex_to_bindata(self, hexdata):
       
   324         orig_hexdata = hexdata
       
   325         hexdata = hexdata.replace(' ', '').replace('\r', '').replace('\n', '').replace('\t', '')
       
   326         if len(hexdata) % 2 != 0:
       
   327             raise ValueError("Failed to convert %r into binary data: String length %d (whitespace stripped) is not divisible by 2", orig_hexdata, len(hexdata))
       
   328         for c in hexdata:
       
   329             if c not in "0123456789abcdefABCDEF":
       
   330                 raise ValueError("Failed to convert %r into binary data: Not a valid hex string", hexdata)
       
   331         
       
   332         temp = []
       
   333         for i in xrange(len(hexdata) / 2):
       
   334             start = i * 2
       
   335             end   = start + 2 
       
   336             temp.append(chr(int(hexdata[start:end], 16)))
       
   337         return ''.join(temp)
       
   338 
       
   339 class Category(object):
       
   340     def __init__(self):
       
   341         self.name   = None
       
   342         self.category_uid    = None
       
   343         self.settings = []
       
   344     
       
   345     def get_hcr_records(self):
       
   346         """
       
   347         Return a list of HcrRecord objects created based on this category's settings.
       
   348         """
       
   349         result = []
       
   350         for setting in self.settings:
       
   351             record = HcrRecord(setting.type, setting.value, self.category_uid, setting.id)
       
   352             flag = setting.flag
       
   353             if flag:
       
   354                 record.flags = 0
       
   355                 if flag.Uninitialised == '1':   record.flags |= HcrRecord.FLAG_UNINITIALIZED
       
   356                 if flag.Modifiable == '1':      record.flags |= HcrRecord.FLAG_MODIFIABLE
       
   357                 if flag.Persistent == '1':      record.flags |= HcrRecord.FLAG_PERSISTENT
       
   358             result.append(record)
       
   359         return result 
       
   360         
       
   361 
       
   362 class Output(object):
       
   363     def __init__(self):
       
   364         self.file = None
       
   365         self.type = None
       
   366         self.version = None
       
   367         self.read_only = None
       
   368         self.categories = []
       
   369     
       
   370     def get_hcr_records(self):
       
   371         """
       
   372         Return a list of HcrRecord objects created based on this output object's categories.
       
   373         """
       
   374         result = []
       
   375         for category in self.categories:
       
   376             result.extend(category.get_hcr_records())
       
   377         return result
       
   378     
       
   379     def get_hcr_repository(self):
       
   380         """
       
   381         Return a HcrRepository object created based on this output.
       
   382         
       
   383         The type of this Output object should be 'hcr', otherwise and an exception is raised.
       
   384         """
       
   385         if self.type != 'hcr':
       
   386             raise RuntimeError("get_hcr_repository() called on an Output object with type '%s' (should be 'hcr')" % self.type)
       
   387         
       
   388         return HcrRepository(self.get_hcr_records())
       
   389