| #!/usr/bin/python2.4 |
| # |
| # Copyright 2011 Google Inc. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Serializes node and string tables. See class comment for more details.""" |
| |
| __author__ = 'bmcquade@google.com (Bryan McQuade)' |
| |
| |
| def _GetMaxValueForNumBits(num_bits): |
| """Return max value for an unsigned integer of width num_bits.""" |
| return 2**num_bits - 1 |
| |
| |
| class TableSerializer(object): |
| """TableSerializer serializes the table builders to C code.""" |
| |
| def __init__(self, |
| component_offset_bits, |
| child_node_offset_bits, |
| num_children_bits): |
| self.max_component_offset = _GetMaxValueForNumBits( |
| component_offset_bits) |
| self.max_child_node_offset = _GetMaxValueForNumBits( |
| child_node_offset_bits) |
| self.max_num_children = _GetMaxValueForNumBits(num_children_bits) |
| |
| def SerializeNodeTable(self, node_table_builder, string_table_builder): |
| """Generate a C representation of the node table. |
| |
| Args: |
| node_table_builder: The node table to use when serializing. |
| string_table_builder: The string table to use when serializing. |
| """ |
| out = [] |
| for node in node_table_builder.GetNodeTable(): |
| component_offset = ( |
| string_table_builder.GetHostnamePartOffset(node.GetName())) |
| num_children = len(node.GetChildren()) |
| if num_children > 0: |
| child_node_offset = node_table_builder.GetChildNodeOffset(node) |
| else: |
| child_node_offset = 0 |
| if node.IsTerminalNode(): |
| is_root = 1 |
| else: |
| is_root = 0 |
| if (component_offset > self.max_component_offset or |
| child_node_offset > self.max_child_node_offset or |
| num_children > self.max_num_children): |
| raise OverflowError( |
| 'Values %d %d %d out of range.' % |
| (component_offset, child_node_offset, num_children)) |
| out.append(r' { %5d, %5d, %5d, %d }, /* %s */' % ( |
| component_offset, |
| child_node_offset, |
| num_children, |
| is_root, |
| node.GetIdentifier('.'))) |
| return '\n'.join(out) |
| |
| def SerializeLeafChildNodeTable(self, |
| node_table_builder, |
| string_table_builder): |
| """Generate a C representation of the leaf node table. |
| |
| Args: |
| node_table_builder: The node table to use when serializing. |
| string_table_builder: The string table to use when serializing. |
| """ |
| out = [] |
| for node in node_table_builder.GetLeafNodeTable(): |
| component_offset = ( |
| string_table_builder.GetHostnamePartOffset(node.GetName())) |
| if component_offset > self.max_component_offset: |
| raise OverflowError( |
| 'component_offset %d out of range.' % component_offset) |
| out.append(r'%5d, /* %s */' % ( |
| component_offset, node.GetIdentifier('.'))) |
| return '\n'.join(out) |
| |
| @staticmethod |
| def SerializeStringTable(string_table_builder): |
| """Generate a C representation of the string table. |
| |
| Args: |
| string_table_builder: the string table to use when serializing. |
| """ |
| last_newline = 0 |
| out = ['"'] |
| for char in string_table_builder.GetStringTable(): |
| if ord(char) > 127: |
| raise ValueError("Encountered unexpected multibyte character.") |
| if char == '\0': |
| if len(out) - last_newline >= 60: |
| space_char = '\n' |
| else: |
| space_char = ' ' |
| # To prevent the compiler from interpreting subsequent |
| # characters as part of the hex code, we break the string |
| # literal. |
| # |
| # E.g. [?feet] --> ["\x3f" "feet"] instead of ["\x3ffeet"] |
| out.extend(['\\', '0', '"', space_char, '"']) |
| if space_char == '\n': |
| last_newline = len(out) - 1 |
| else: |
| out.append(char) |
| out.append('"') |
| return ''.join(out) |
| |
| @staticmethod |
| def SerializeTestTable(test_table_builder): |
| """Generate a C representation of the test table. |
| |
| Args: |
| test_table_builder: The test table to use when serializing. |
| """ |
| out = [] |
| for host, registry, is_exception_rule in test_table_builder.GetTestTable(): |
| parts = [ 'www', host ] |
| parts.extend(registry.split('.')) |
| out.append(r'{ "%s", %d, %d },' % ('.'.join(parts), |
| len(registry), |
| is_exception_rule)) |
| return '\n'.join(out) |