configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcrml_parser.py
#
# 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 logging
import pkg_resources
from hcrplugin.hcr_exceptions import *
from hcrplugin.hcrrepository import HcrRecord, HcrRepository
from hcrplugin.hcr_writer import HcrWriter
from hcrplugin.header_writer import *
from cone.public import plugin
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()
# 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 = context.create_file(outputfile, mode='wb')
#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(context)
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'
NAMESPACE_ID = 'hcrml'
ROOT_ELEMENT_NAME = 'hcr'
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
@classmethod
def get_schema_data(cls):
return pkg_resources.resource_string('hcrplugin', 'xsd/hcrml.xsd')
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())