|
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 import logging |
|
18 import __init__ |
|
19 from hcrplugin.hcrrepository import HcrRecord, HcrRepository |
|
20 from struct import pack, unpack |
|
21 from hcrplugin.hcr_writer import VALUE_TYPE_MAP,VALUE_TYPES_WITH_LSD,VALUE_TYPES_UNSIGNED_INT |
|
22 from hcrplugin.hcr_header import HcrHeader |
|
23 from hcrplugin.hcr_exceptions import * |
|
24 |
|
25 |
|
26 class HcrReader(object): |
|
27 |
|
28 def parse_repository_from_bindata(self, data): |
|
29 """ |
|
30 @return: HcrRepository object constructed from the given binary data. |
|
31 """ |
|
32 header_data = data[:32] |
|
33 header = HcrHeader() |
|
34 header.loads(header_data) |
|
35 |
|
36 expected_len = 32 + header.nrecords * 20 + header.lsd_size |
|
37 if len(data) < expected_len: |
|
38 raise InvalidHcrDataSizeError("File size is %d, expected at least %d based on header" \ |
|
39 % (len(data), expected_len)) |
|
40 |
|
41 expected_lsd_offset = 32 + header.nrecords * 20 |
|
42 if header.lsd_offset != expected_lsd_offset: |
|
43 raise InvalidLsdSectionOffsetError("LSD offset is %d, expected %d" \ |
|
44 % (header.lsd_offset, expected_lsd_offset)) |
|
45 |
|
46 records = [] |
|
47 for i in xrange(header.nrecords): |
|
48 record_offset = 32 + i * 20 |
|
49 record_data = data[record_offset:record_offset+20] |
|
50 record,lsd_pos = self.parse_record_from_bindata(record_data) |
|
51 if lsd_pos != None: |
|
52 if lsd_pos[0] > header.lsd_size or (lsd_pos[0] + lsd_pos[1]) > header.lsd_size: |
|
53 raise InvalidRecordLsdPositionError( |
|
54 "LSD offset of record %d (category=%d, element=%d) is %r, but LSD section size is %d" \ |
|
55 % (i, record.category_id, record.element_id, lsd_pos, header.lsd_size)) |
|
56 lsd_offset = lsd_pos[0] + header.lsd_offset |
|
57 lsd_data = data[lsd_offset:lsd_offset+lsd_pos[1]] |
|
58 record.value = self.parse_record_value_from_lsd_bindata(record.type,lsd_data) |
|
59 records.append(record) |
|
60 |
|
61 return HcrRepository(records,header.version,header.flags) |
|
62 |
|
63 def parse_record_from_bindata(self, data): |
|
64 """ |
|
65 @return: Tuple: (record, lsd_pos) where |
|
66 record = HcrRecord object constructed from the given binary data. |
|
67 lsd_pos = The position of the record's data in the LSD section in the |
|
68 form of a tuple (offset, size), or None if the record does |
|
69 not have any data in the LSD section. |
|
70 """ |
|
71 |
|
72 if len(data) != 20: |
|
73 raise HcrReaderError("Invalid record length: %d, expected 20" % len(data)) |
|
74 |
|
75 result = unpack("<IIIHH",data[:16]) |
|
76 |
|
77 category_id = result[0] |
|
78 element_id = result[1] |
|
79 value_type = result[2] |
|
80 flag = result[3] |
|
81 lsd_len = result[4] |
|
82 |
|
83 |
|
84 |
|
85 for key,val in VALUE_TYPE_MAP.iteritems(): |
|
86 if val == value_type: |
|
87 value_type = key |
|
88 break |
|
89 if value_type not in VALUE_TYPE_MAP: |
|
90 raise InvalidRecordValueTypeError("Invalid value type:%X" % value_type) |
|
91 |
|
92 value = None |
|
93 lsd_pos = None |
|
94 if value_type in VALUE_TYPES_WITH_LSD: |
|
95 lsd_offset = unpack("<I",data[16:])[0] |
|
96 lsd_pos = (lsd_offset,lsd_len) |
|
97 else: |
|
98 if value_type in VALUE_TYPES_UNSIGNED_INT: |
|
99 format = "<I" |
|
100 elif value_type == HcrRecord.VALTYPE_INT8: |
|
101 format = "<bxxx" |
|
102 elif value_type == HcrRecord.VALTYPE_INT16: |
|
103 format = "<hxx" |
|
104 else: |
|
105 format = "<i" |
|
106 |
|
107 value = unpack(format, data[16:])[0] |
|
108 |
|
109 if value_type == HcrRecord.VALTYPE_BOOL: |
|
110 value = bool(value) |
|
111 |
|
112 |
|
113 |
|
114 record = HcrRecord(value_type,value,category_id,element_id,flag) |
|
115 |
|
116 return record,lsd_pos |
|
117 |
|
118 |
|
119 def parse_record_value_from_lsd_bindata(self, record_type, data): |
|
120 """ |
|
121 @return: The record value parsed from the given binary data in the LSD section. |
|
122 @param type: The HCRML type of the record whose LSD data is to be parsed. |
|
123 """ |
|
124 if record_type == HcrRecord.VALTYPE_TEXT8: |
|
125 return data.decode("utf-8") |
|
126 |
|
127 elif record_type == HcrRecord.VALTYPE_BIN_DATA: |
|
128 return data |
|
129 |
|
130 elif record_type == HcrRecord.VALTYPE_ARRAY_INT32: |
|
131 if len(data) % 4 != 0: |
|
132 raise InvalidRecordLsdPositionError("Int32 array requires an amount of LSD data that is divisible by 4 (data with size %d was given)" % len(data)) |
|
133 return list(unpack("<%di"%(len(data)/4), data)) |
|
134 |
|
135 elif record_type == HcrRecord.VALTYPE_ARRAY_UINT32: |
|
136 if len(data) % 4 != 0: |
|
137 raise InvalidRecordLsdPositionError("Uint32 array requires an amount of LSD data that is divisible by 4 (data with size %d was given)" % len(data)) |
|
138 return list(unpack("<%dI"%(len(data)/4), data)) |
|
139 |
|
140 elif record_type == HcrRecord.VALTYPE_INT64: |
|
141 if len(data) != 8: |
|
142 raise InvalidRecordLsdPositionError("Int64 requires LSD data size to be 8 bytes (%d given)" % len(data)) |
|
143 return unpack("<q",data)[0] |
|
144 |
|
145 elif record_type == HcrRecord.VALTYPE_UINT64: |
|
146 if len(data) != 8: |
|
147 raise InvalidRecordLsdPositionError("Uint64 requires LSD data size to be 8 bytes (%d given)" % len(data)) |
|
148 return unpack("<Q",data)[0] |
|
149 |
|
150 else: |
|
151 return None |