|
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 from cone.public import exceptions, plugin |
|
18 import crml_impl |
|
19 from crml_model import * |
|
20 |
|
21 |
|
22 def get_required_attr(elem, attrname): |
|
23 """ |
|
24 Get a required attribute from an XML element or raise an exception. |
|
25 """ |
|
26 attr = elem.get(attrname) |
|
27 if attr is None: |
|
28 raise exceptions.ParseError("<%s> element does not have the required '%s' attribute!" % (elem.tag, attrname)) |
|
29 return attr |
|
30 |
|
31 def convert_num(string): |
|
32 """ |
|
33 Convert the given string into a number. |
|
34 |
|
35 - The number can be in decimal or hexadecimal format. |
|
36 - If None is passed, None is also returned. |
|
37 """ |
|
38 if string in ('', None): |
|
39 return None |
|
40 try: |
|
41 return long(string) |
|
42 except ValueError: |
|
43 return long(string, 16) |
|
44 |
|
45 class CrmlReader(plugin.ReaderBase): |
|
46 NAMESPACE = 'http://www.s60.com/xml/cenrep/1' |
|
47 FILE_EXTENSIONS = ['crml'] |
|
48 |
|
49 @classmethod |
|
50 def read_impl(cls, resource_ref, configuration, etree): |
|
51 reader = CrmlReader() |
|
52 repository = reader.read_repository(etree) |
|
53 return crml_impl.CrmlImpl(resource_ref, configuration, repository) |
|
54 |
|
55 def read_repository(self, elem): |
|
56 """ |
|
57 Read a CrmlRepository object from the given XML element. |
|
58 """ |
|
59 # Read repository attributes |
|
60 repo = CrmlRepository( |
|
61 uid_value = elem.get('uidValue'), |
|
62 uid_name = elem.get('uidName'), |
|
63 owner = elem.get('owner'), |
|
64 version = elem.get('initialisationFileVersion', '1'), |
|
65 access = self.read_access(elem)) |
|
66 if elem.get('backup') == 'true': repo.backup = True |
|
67 if elem.get('rfs') == 'true': repo.rfs = True |
|
68 |
|
69 # Read all keys |
|
70 for sub_elem in elem: |
|
71 key_obj = self.read_key(sub_elem) |
|
72 |
|
73 if key_obj is not None: |
|
74 # Read-only keys have always cap_wr=AlwaysFail. |
|
75 # the isinstance() check is for CT2 output compatibility |
|
76 if not isinstance(key_obj, CrmlKeyRange): |
|
77 if key_obj.read_only: |
|
78 key_obj.access.cap_wr = 'AlwaysFail' |
|
79 key_obj.access.sid_wr = None |
|
80 |
|
81 repo.keys.append(key_obj) |
|
82 |
|
83 if repo.access == CrmlAccess(cap_rd='AlwaysPass') and len(repo.keys) == 0: |
|
84 repo.access.cap_rd = None |
|
85 |
|
86 return repo |
|
87 |
|
88 def read_access(self, elem): |
|
89 """ |
|
90 Read a CrmlAccess object from the given XML element. |
|
91 @param elem: The element from which to parse an access definition. Should be any |
|
92 element that can contain an access definition (i.e. 'repository', 'key', or 'keyRange'). |
|
93 """ |
|
94 access = CrmlAccess() |
|
95 read_cap_found = False |
|
96 write_cap_found = False |
|
97 for access_elem in elem.findall('{%s}access' % self.NAMESPACE): |
|
98 type = access_elem.get('type') |
|
99 if type == 'R' and not read_cap_found: |
|
100 access.cap_rd = access_elem.get('capabilities') |
|
101 access.sid_rd = access_elem.get('sid') |
|
102 read_cap_found = True |
|
103 elif type == 'W' and not write_cap_found: |
|
104 access.cap_wr = access_elem.get('capabilities') |
|
105 access.sid_wr = access_elem.get('sid') |
|
106 write_cap_found = True |
|
107 |
|
108 return access |
|
109 |
|
110 def read_common_key_attrs(self, key_elem, key_obj): |
|
111 """ |
|
112 Read common attributes into an object of class CrmlKeyBase from an XML element. |
|
113 """ |
|
114 if not isinstance(key_obj, CrmlKeyBase): |
|
115 raise ValueError("Expected object of type %s" % CrmlKeyBase.__name__) |
|
116 |
|
117 if key_elem.get('readOnly') == 'true': key_obj.read_only = True |
|
118 if key_elem.get('backup') == 'true': key_obj.backup = True |
|
119 key_obj.access = self.read_access(key_elem) |
|
120 key_obj.name = key_elem.get('name') |
|
121 |
|
122 def read_key(self, key_elem): |
|
123 key_obj = None |
|
124 if key_elem.tag == '{%s}key' % self.NAMESPACE: |
|
125 # Determine whether the key is a normal key or a bitmask key |
|
126 # based on the presence of <bit> elements |
|
127 tags = [e.tag for e in key_elem] |
|
128 if '{%s}bit' % self.NAMESPACE in tags: |
|
129 key_obj = self.read_bitmask_key(key_elem) |
|
130 else: |
|
131 key_obj = self.read_simple_key(key_elem) |
|
132 elif key_elem.tag == '{%s}keyRange' % self.NAMESPACE: |
|
133 key_obj = self.read_key_range(key_elem) |
|
134 |
|
135 return key_obj |
|
136 |
|
137 def read_simple_key(self, key_elem): |
|
138 """ |
|
139 Read a CrmlSimpleKey object from the given XML element. |
|
140 """ |
|
141 expected_tag = '{%s}key' % self.NAMESPACE |
|
142 if key_elem.tag != expected_tag: |
|
143 raise RuntimeError("Incorrect XML element passed to read_simple_key(): %s, expected %s" % (key_elem.tag, expected_tag)) |
|
144 |
|
145 key = CrmlSimpleKey( |
|
146 ref = get_required_attr(key_elem, 'ref').replace('/', '.'), |
|
147 int = get_required_attr(key_elem, 'int'), |
|
148 type = key_elem.get('type', 'int')) |
|
149 self.read_common_key_attrs(key_elem, key) |
|
150 |
|
151 return key |
|
152 |
|
153 def read_bitmask_key(self, key_elem): |
|
154 """ |
|
155 Read a CrmlBitmaskKey object from the given XML element. |
|
156 """ |
|
157 expected_tag = '{%s}key' % self.NAMESPACE |
|
158 if key_elem.tag != expected_tag: |
|
159 raise RuntimeError("Incorrect XML element passed to read_bitmask_key(): %s, expected %s" % (key_elem.tag, expected_tag)) |
|
160 |
|
161 # Read attributes |
|
162 key = CrmlBitmaskKey( |
|
163 int = get_required_attr(key_elem, 'int'), |
|
164 type = key_elem.get('type', 'int')) |
|
165 self.read_common_key_attrs(key_elem, key) |
|
166 |
|
167 # Read bits |
|
168 for bit_elem in key_elem.findall('{%s}bit' % self.NAMESPACE): |
|
169 ref = get_required_attr(bit_elem, 'ref').replace('/', '.') |
|
170 if bit_elem.get('value') == 'false': invert = True |
|
171 else: invert = False |
|
172 index = int(bit_elem.text.strip()) |
|
173 |
|
174 key.bits.append(CrmlBit(ref=ref, index=index, type=type, invert=invert)) |
|
175 |
|
176 return key |
|
177 |
|
178 def read_key_range(self, key_range_elem): |
|
179 """ |
|
180 Read a CrmlKeyRange object from the given XML element. |
|
181 """ |
|
182 expected_tag = '{%s}keyRange' % self.NAMESPACE |
|
183 if key_range_elem.tag != expected_tag: |
|
184 raise RuntimeError("Incorrect XML element passed to read_key_range(): %s, expected %s" % (key_range_elem.tag, expected_tag)) |
|
185 |
|
186 # Read attributes |
|
187 ref = key_range_elem.get('ref') |
|
188 if ref is not None: ref = ref.replace('/', '.') |
|
189 key_range = CrmlKeyRange( |
|
190 ref = ref, |
|
191 first_int = get_required_attr(key_range_elem, "firstInt"), |
|
192 last_int = get_required_attr(key_range_elem, "lastInt"), |
|
193 count_int = key_range_elem.get('countInt'), |
|
194 first_index = convert_num(key_range_elem.get('firstIndex', '0')), |
|
195 index_bits = convert_num(key_range_elem.get('indexBits'))) |
|
196 self.read_common_key_attrs(key_range_elem, key_range) |
|
197 |
|
198 # Read sub-keys |
|
199 for subkey_elem in key_range_elem.findall('{%s}key' % self.NAMESPACE): |
|
200 ref = get_required_attr(subkey_elem, 'ref').replace('/', '.') |
|
201 int = get_required_attr(subkey_elem, 'int') |
|
202 name = subkey_elem.get('name') |
|
203 type = subkey_elem.get('type', 'int') |
|
204 key_range.subkeys.append(CrmlKeyRangeSubKey(ref=ref, int=int, name=name, type=type)) |
|
205 |
|
206 return key_range |