diff -r 000000000000 -r 2e8eeb919028 configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcr_writer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configurationengine/source/plugins/symbian/ConeHCRPlugin/hcrplugin/hcr_writer.py Thu Mar 11 17:04:37 2010 +0200 @@ -0,0 +1,217 @@ +# +# 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 logging +import __init__ + + +from struct import pack, unpack + +from cone.public import exceptions,plugin,utils,api +from hcrplugin.hcrrepository import HcrRecord +from hcrplugin.hcr_exceptions import * +from hcrplugin.hcr_header import HcrHeader + +# Dictionary for mapping the HCRML value types to their +# implementation values +VALUE_TYPE_MAP = { + HcrRecord.VALTYPE_INT32 : 0x00000001, + HcrRecord.VALTYPE_INT16 : 0x00000002, + HcrRecord.VALTYPE_INT8 : 0x00000004, + HcrRecord.VALTYPE_BOOL : 0x00000008, + HcrRecord.VALTYPE_UINT32 : 0x00000010, + HcrRecord.VALTYPE_UINT16 : 0x00000020, + HcrRecord.VALTYPE_UINT8 : 0x00000040, + HcrRecord.VALTYPE_LIN_ADDR : 0x00000100, + HcrRecord.VALTYPE_BIN_DATA : 0x00010000, + HcrRecord.VALTYPE_TEXT8 : 0x00020000, + HcrRecord.VALTYPE_ARRAY_INT32 : 0x00040000, + HcrRecord.VALTYPE_ARRAY_UINT32 : 0x00080000, + HcrRecord.VALTYPE_INT64 : 0x01000000, + HcrRecord.VALTYPE_UINT64 : 0x02000000, + } + + +VALUE_TYPES_WITH_LSD = [ + HcrRecord.VALTYPE_BIN_DATA, + HcrRecord.VALTYPE_TEXT8, + HcrRecord.VALTYPE_ARRAY_INT32, + HcrRecord.VALTYPE_ARRAY_UINT32, + HcrRecord.VALTYPE_INT64, + HcrRecord.VALTYPE_UINT64 + ] + +VALUE_TYPES_UNSIGNED_INT = [ + HcrRecord.VALTYPE_UINT32, + HcrRecord.VALTYPE_UINT16, + HcrRecord.VALTYPE_UINT8, + HcrRecord.VALTYPE_LIN_ADDR, + HcrRecord.VALTYPE_UINT64, + ] + +NUMERIC_VALUE_RANGES = { + HcrRecord.VALTYPE_INT32 : (-2**31, 2**31-1), + HcrRecord.VALTYPE_INT16 : (-2**15, 2**15-1), + HcrRecord.VALTYPE_INT8 : (-2**7, 2**7-1), + HcrRecord.VALTYPE_UINT32 : (0, 2**32-1), + HcrRecord.VALTYPE_UINT16 : (0, 2**16-1), + HcrRecord.VALTYPE_UINT8 : (0, 2**8-1), + HcrRecord.VALTYPE_LIN_ADDR : (0, 2**32-1), + HcrRecord.VALTYPE_INT64 : (-2**63, 2**63-1), + HcrRecord.VALTYPE_UINT64 : (0, 2**64-1), + HcrRecord.VALTYPE_ARRAY_INT32 : (-2**31, 2**31-1), + HcrRecord.VALTYPE_ARRAY_UINT32 : (0, 2**32-1), +} + + + +class HcrWriter(object): + + # Maximum size of LSD section data for one record + LSD_MAX_SIZE_PER_RECORD = 512 + + def get_record_setting_id(self, record): + """ + Return the setting ID value used for sorting the records in the repository. + """ + return (record.category_id, record.element_id) + + def get_repository_bindata(self, repository): + """ + @return: The binary data to write into a file for the given repository. + """ + dup_ids = repository.get_duplicate_record_ids() + if len(dup_ids) > 0: + raise DuplicateRecordError("The repository contains the following duplicate records (category ID, element ID): %r" % dup_ids) + + header_data = None + header_size = 32 + record_data = [] + records_size = 0 + lsd_data = [] + lsd_size = 0 + lsd_offset = None + + # Generate the record and LSD section data + records = sorted(repository.records, key=self.get_record_setting_id) + for record in records: + lsd_pos = None + lsd = self.get_record_lsd_bindata(record) + if lsd != None: + # Store the position before adding the padding, + # because it shouldn't include the padding bytes + lsd_pos = (lsd_size, len(lsd)) + lsd += self._get_padding(len(lsd)) + lsd_data.append(lsd) + lsd_size += len(lsd) + + rdata = self.get_record_bindata(record, lsd_pos) + record_data.append(rdata) + records_size += len(rdata) + + lsd_offset = header_size + records_size + + header = HcrHeader() + header.version = repository.version + header.flags = repository.flags + header.nrecords = len(repository.records) + header.lsd_offset = lsd_offset + header.lsd_size = lsd_size + + header_data = header.dumps() + if len(header_data) != header_size: + raise RuntimeError("Internal logic error! Header size is %d and not %d as it should be!" % (len(header_data), header_size)) + + output = [] + output.append(header_data) + output.extend(record_data) + output.extend(lsd_data) + output = ''.join(output) + if len(output) % 4 != 0: + raise RuntimeError("Internal logic error! Output size is not divisible by 4 (%d)" % (len(output))) + + return output + + def _get_padding(self, size, padding_char='\x00'): + if size % 4 == 0: amount = 0 + else: amount = 4 - (size % 4) + return amount * padding_char + + + def get_record_bindata(self, record, lsd_pos=None): + """ + @param lsd_pos: The position of the record's data in the Large + Setting Data section. Should be a tuple: (offset, size). + @return: The binary data to write for the given record object. + """ + self._check_value_range(record) + + if record.type in VALUE_TYPES_WITH_LSD: + RECORD_FMT = " self.LSD_MAX_SIZE_PER_RECORD: + msg = "Data size for value in record (category=%d, element=%d) is too large: size %d bytes, but maximum is %d bytes" \ + % (record.category_id, record.element_id, len(result), self.LSD_MAX_SIZE_PER_RECORD) + raise TooLargeLsdDataError(msg) + return result + + def _check_value_range(self, record): + if record.type in NUMERIC_VALUE_RANGES: + range = NUMERIC_VALUE_RANGES[record.type] + + values = record.value + if not isinstance(values, list): values = [values] + + for val in values: + if val < range[0] or val > range[1]: + msg = "Value in record (category=%d, element=%d) is invalid for its type ('%s'): %d is not in the range %d-%d" \ + % (record.category_id, record.element_id, record.type, val, range[0], range[1]) + raise ValueNotInRangeError(msg)