Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Utility classes for serialization""" | 5 """Utility classes for serialization""" |
| 6 | 6 |
| 7 import struct | 7 import struct |
| 8 | 8 |
| 9 | 9 |
| 10 # Format of a header for a struct or an array. | 10 # Format of a header for a struct, array or union. |
| 11 HEADER_STRUCT = struct.Struct("<II") | 11 HEADER_STRUCT = struct.Struct("<II") |
| 12 | 12 |
| 13 # Format for a pointer. | |
| 14 POINTER_STRUCT = struct.Struct("<Q") | |
| 15 | |
| 13 | 16 |
| 14 def Flatten(value): | 17 def Flatten(value): |
| 15 """Flattens nested lists/tuples into an one-level list. If value is not a | 18 """Flattens nested lists/tuples into an one-level list. If value is not a |
| 16 list/tuple, it is converted to an one-item list. For example, | 19 list/tuple, it is converted to an one-item list. For example, |
| 17 (1, 2, [3, 4, ('56', '7')]) is converted to [1, 2, 3, 4, '56', '7']; | 20 (1, 2, [3, 4, ('56', '7')]) is converted to [1, 2, 3, 4, '56', '7']; |
| 18 1 is converted to [1]. | 21 1 is converted to [1]. |
| 19 """ | 22 """ |
| 20 if isinstance(value, (list, tuple)): | 23 if isinstance(value, (list, tuple)): |
| 21 result = [] | 24 result = [] |
| 22 for item in value: | 25 for item in value: |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 needed_padding = NeededPaddingForAlignment(index, group.GetAlignment()) | 214 needed_padding = NeededPaddingForAlignment(index, group.GetAlignment()) |
| 212 if needed_padding: | 215 if needed_padding: |
| 213 codes.append('x' * needed_padding) | 216 codes.append('x' * needed_padding) |
| 214 index = index + needed_padding | 217 index = index + needed_padding |
| 215 codes.append(code) | 218 codes.append(code) |
| 216 index = index + group.GetByteSize() | 219 index = index + group.GetByteSize() |
| 217 alignment_needed = NeededPaddingForAlignment(index) | 220 alignment_needed = NeededPaddingForAlignment(index) |
| 218 if alignment_needed: | 221 if alignment_needed: |
| 219 codes.append('x' * alignment_needed) | 222 codes.append('x' * alignment_needed) |
| 220 return struct.Struct(''.join(codes)) | 223 return struct.Struct(''.join(codes)) |
| 224 | |
| 225 | |
| 226 class UnionSerializer(object): | |
| 227 """ | |
| 228 Helper class to serialize/deserialize a union. | |
| 229 """ | |
| 230 def __init__(self, fields): | |
| 231 self._fields = {field.index: field for field in fields} | |
| 232 | |
| 233 def SerializeInline(self, union, handle_offset): | |
| 234 data = bytearray() | |
| 235 field = self._fields[union.tag] | |
| 236 | |
| 237 # If the union value is a simple type or a nested union, it is returned as | |
| 238 # entry. | |
| 239 # Otherwise, the serialized value is appended to data and the value of entry | |
| 240 # is -1. The caller will need to set entry to the location where the | |
| 241 # caller will append data. | |
| 242 (entry, handles) = field.field_type.Serialize( | |
| 243 union.data, -1, data, handle_offset) | |
| 244 | |
| 245 # If the value contained in the union is itself a union, we append its | |
| 246 # serialized value to data and set entry to -1. The caller will need to set | |
| 247 # entry to the location where the caller will append data. | |
| 248 if field.field_type.IsUnion(): | |
| 249 nested_union = bytearray(16) | |
| 250 HEADER_STRUCT.pack_into(nested_union, 0, entry[0], entry[1]) | |
| 251 POINTER_STRUCT.pack_into(nested_union, 8, entry[2]) | |
| 252 | |
| 253 data = nested_union + data | |
| 254 | |
| 255 # Since we do not know where the caller will append the nested union, | |
| 256 # we set entry to an invalid value and let the caller figure out the right | |
| 257 # value. | |
| 258 entry = -1 | |
| 259 | |
| 260 return (16, union.tag, entry, data), handles | |
| 261 | |
| 262 def Serialize(self, union, handle_offset): | |
| 263 (size, tag, entry, extra_data), handles = self.SerializeInline( | |
| 264 union, handle_offset) | |
| 265 data = bytearray(16) | |
| 266 if extra_data: | |
| 267 entry = 8 | |
| 268 data.extend(extra_data) | |
| 269 | |
| 270 field = self._fields[union.tag] | |
| 271 | |
| 272 HEADER_STRUCT.pack_into(data, 0, size, tag) | |
| 273 typecode = field.GetTypeCode() | |
| 274 | |
| 275 # If the value is a nested union, we store a 64 bits pointer to it. | |
| 276 if field.field_type.IsUnion(): | |
| 277 typecode = 'Q' | |
| 278 | |
| 279 struct.pack_into('<%s' % typecode, data, 8, entry) | |
| 280 return data, handles | |
| 281 | |
| 282 def Deserialize(self, context, union_class): | |
| 283 if len(context.data) < HEADER_STRUCT.size: | |
| 284 raise DeserializationException( | |
| 285 'Available data too short to contain header.') | |
| 286 (size, tag) = HEADER_STRUCT.unpack_from(context.data) | |
| 287 | |
| 288 if size == 0: | |
| 289 return None | |
| 290 | |
| 291 if size != 16: | |
| 292 raise DeserializationException('Invalid union size %s' % size) | |
| 293 | |
| 294 union = union_class.__new__(union_class) | |
| 295 if tag not in self._fields: | |
|
qsr
2015/07/20 23:08:27
Do the test pass? _fields is not in the union anym
azani
2015/07/20 23:12:13
This is the UnionSerializer class. You're thinking
qsr
2015/07/20 23:16:15
Oh. Sorry you are perfectly right.
| |
| 296 union.SetInternals(None, None) | |
| 297 return union | |
| 298 | |
| 299 field = self._fields[tag] | |
| 300 if field.field_type.IsUnion(): | |
| 301 ptr = POINTER_STRUCT.unpack_from(context.data, 8)[0] | |
| 302 value = field.field_type.Deserialize(ptr, context.GetSubContext(ptr+8)) | |
| 303 else: | |
| 304 raw_value = struct.unpack_from( | |
| 305 field.GetTypeCode(), context.data, 8)[0] | |
| 306 value = field.field_type.Deserialize(raw_value, context.GetSubContext(8)) | |
| 307 | |
| 308 union.SetInternals(field, value) | |
| 309 return union | |
| OLD | NEW |