#!/usr/bin/python # # Python utilities shared by the build scripts. # import datetime import json class BitEncoder: "Bitstream encoder." _bits = None def __init__(self): self._bits = [] def bits(self, x, nbits): if (x >> nbits) != 0: raise Exception('input value has too many bits (value: %d, bits: %d)' % (x, nbits)) for i in xrange(nbits): t = (x >> (nbits - i - 1)) & 0x01 self._bits.append(t) def string(self, x): nbits = len(x) * 8 for i in xrange(nbits): byteidx = i / 8 bitidx = i % 8 if byteidx < 0 or byteidx >= len(x): self._bits.append(0) else: t = (ord(x[byteidx]) >> (7 - bitidx)) & 0x01 self._bits.append(t) def getNumBits(self): "Get current number of encoded bits." return len(self._bits) def getNumBytes(self): "Get current number of encoded bytes, rounded up." nbits = len(self._bits) while (nbits % 8) != 0: nbits += 1 return nbits / 8 def getBytes(self): "Get current bitstream as a byte sequence, padded with zero bits." bytes = [] for i in xrange(self.getNumBytes()): t = 0 for j in xrange(8): off = i*8 + j if off >= len(self._bits): t = (t << 1) else: t = (t << 1) + self._bits[off] bytes.append(t) return bytes def getByteString(self): "Get current bitstream as a string." return ''.join([chr(i) for i in self.getBytes()]) class GenerateC: "Helper for generating C source and header files." _data = None wrap_col = 76 def __init__(self): self._data = [] def emitRaw(self, text): "Emit raw text (without automatic newline)." self._data.append(text) def emitLine(self, text): "Emit a raw line (with automatic newline)." self._data.append(text + '\n') def emitHeader(self, autogen_by): "Emit file header comments." # Note: a timestamp would be nice but it breaks incremental building self.emitLine('/*') self.emitLine(' * Automatically generated by %s, do not edit!' % autogen_by) self.emitLine(' */') self.emitLine('') def emitArray(self, data, tablename, typename='char', bytesize=None): "Emit an array as a C array." # lenient input if isinstance(data, unicode): data = data.encode('utf-8') if isinstance(data, str): tmp = [] for i in xrange(len(data)): tmp.append(ord(data[i])) data = tmp size_spec = '' if bytesize is not None: size_spec = '%d' % bytesize self.emitLine('%s %s[%s] = {' % (typename, tablename, size_spec)) line = '' for i in xrange(len(data)): t = "(%s)'\\x%02x', " % (typename, data[i]) if len(line) + len(t) >= self.wrap_col: self.emitLine(line) line = t else: line += t if line != '': self.emitLine(line) self.emitLine('};') def emitDefine(self, name, value, comment=None): "Emit a C define with an optional comment." # XXX: there is no escaping right now (for comment or value) if comment is not None: self.emitLine('#define %-60s %-30s /* %s */' % (name, value, comment)) else: self.emitLine('#define %-60s %s' % (name, value)) def getString(self): "Get the entire file as a string." return ''.join(self._data) def json_encode(x): "JSON encode a value." try: return json.dumps(x) except AttributeError: pass # for older library versions return json.write(x) def json_decode(x): "JSON decode a value." try: return json.loads(x) except AttributeError: pass # for older library versions return json.read(x)