| # -*- coding: utf-8 -*- |
| # Copyright 2010-2014, Google Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # * Neither the name of Google Inc. nor the names of its |
| # contributors may be used to endorse or promote products derived from |
| # this software without specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| """Utilities to generate source codes.""" |
| |
| __author__ = "hidehiko" |
| |
| import struct |
| import types |
| |
| |
| def ToCppStringLiteral(s): |
| """Returns C-style string literal, or NULL if given s is None.""" |
| if s is None: |
| return 'NULL' |
| |
| if all(0x20 <= ord(c) <= 0x7E for c in s): |
| # All characters are in ascii code. |
| return '"%s"' % s.replace('\\', r'\\').replace('"', r'\"') |
| else: |
| # One or more characters are non-ascii. |
| return '"%s"' % ''.join(r'\x%02X' % ord(c) for c in s) |
| |
| |
| def FormatWithCppEscape(format_text, *args): |
| """Returns a string filling format with args.""" |
| literal_list = [] |
| for arg in args: |
| if isinstance(arg, (types.StringType, types.NoneType)): |
| arg = ToCppStringLiteral(arg) |
| literal_list.append(arg) |
| |
| return format_text % tuple(literal_list) |
| |
| |
| def WriteCppDataArray(data, variable_name, target_compiler, stream): |
| """Format data into C++ style array. |
| |
| Visual C++ does not support string literals longer than 65535 characters |
| so integer arrays (e.g. arrays of uint64) are used to represent byte arrays |
| on Windows. |
| |
| The generated code looks like: |
| const uint64 kVAR_data_wordtype[] = { |
| 0x0123456789ABCDEF, ... |
| }; |
| const char * const kVAR_data = |
| reinterpret_cast<const char *>(kVAR_data_wordtype); |
| const size_t kVAR_size = 123; |
| |
| This implementation works well with other toolchains, too, but we use |
| string literals for other toolchains. |
| |
| The generated code with a string literal looks like: |
| const char kVAR_data[] = |
| "\\x12\\x34\\x56\\x78..."; |
| const size_t kVAR_size = 123; |
| |
| Args: |
| data: original data to be formatted. |
| variable_name: the core name of variables. |
| target_compiler: the target compiler which will compile the formatted |
| code. |
| stream: output stream. |
| """ |
| |
| # To accept "target_compiler = None", check taget_compiler itself first. |
| if target_compiler and target_compiler.startswith('msvs'): |
| stream.write('const uint64 k%s_data_wordtype[] = {\n' % variable_name) |
| |
| for word_index in xrange(0, len(data), 8): |
| word_chunk = data[word_index:word_index + 8].ljust(8, '\x00') |
| stream.write('0x%016X, ' % struct.unpack('<Q', word_chunk)) |
| if (word_index / 8) % 4 == 3: |
| # Line feed for every 4 elements. |
| stream.write('\n') |
| |
| stream.write('};\n') |
| stream.write( |
| 'const char * const k%s_data = ' |
| 'reinterpret_cast<const char *>(k%s_data_wordtype);\n' % ( |
| variable_name, variable_name)) |
| else: |
| stream.write('const char k%s_data[] =\n' % variable_name) |
| # Output 16bytes per line. |
| chunk_size = 16 |
| for index in xrange(0, len(data), chunk_size): |
| chunk = data[index:index + chunk_size] |
| stream.write('"') |
| stream.writelines(r'\x%02X' % ord(c) for c in chunk) |
| stream.write('"\n') |
| stream.write(';\n') |
| |
| stream.write('const size_t k%s_size = %d;\n' % (variable_name, len(data))) |
| |
| |
| def ToJavaStringLiteral(codepoint): |
| """Returns string literal with surrogate pair support.""" |
| utf16_string = unichr(codepoint).encode('utf-16be') |
| if len(utf16_string) == 2: |
| (u0, l0) = utf16_string |
| return r'"\u%02X%02X"' % (ord(u0), ord(l0)) |
| else: |
| (u0, l0, u1, l1) = utf16_string |
| return r'"\u%02X%02X\u%02X%02X"' % (ord(u0), ord(l0), ord(u1), ord(l1)) |
| |
| |
| def SkipLineComment(stream, comment_prefix='#'): |
| """Skips line comments from stream.""" |
| for line in stream: |
| stripped_line = line.strip() |
| if stripped_line and not stripped_line.startswith(comment_prefix): |
| yield line.rstrip('\n') |
| |
| |
| def ParseColumnStream(stream, num_column=None, delimiter=None): |
| """Returns parsed columns read from stream.""" |
| if num_column is None: |
| for line in stream: |
| yield line.rstrip('\n').split(delimiter) |
| else: |
| for line in stream: |
| yield line.rstrip('\n').split(delimiter)[:num_column] |
| |
| |
| def SelectColumn(stream, column_index): |
| """Returns the tuple specified by the column_index from the tuple stream.""" |
| for columns in stream: |
| yield tuple(columns[i] for i in column_index) |
| |
| |
| def SplitChunk(iterable, n): |
| """Splits sequence to consecutive n-element chunks. |
| |
| Quite similar to grouper in itertools section of python manual, |
| but slightly different if len(iterable) is not factor of n. |
| grouper extends the last chunk to make it an n-element chunk by adding |
| appropriate value, but this returns truncated chunk. |
| """ |
| for index in xrange(0, len(iterable), n): |
| yield iterable[index:index + n] |