view python/ppci/core/bitreader.py @ 139:2ec4d4332b7a

Improve hexedit
author Windel Bouwman
date Sat, 26 Jan 2013 19:44:36 +0100
parents 6a303f835c6d
children
line wrap: on
line source

from .errors import CompilerException
from .module import Module
import struct

def enum(**enums):
   return type('Enum', (), enums)

BitCodes = enum(END_BLOCK=0, ENTER_SUBBLOCK=1)

class BitstreamReader:
   def __init__(self, f):
      self.f = f
      # Initialize the bitreader:
      self.bitsInCurrent = 32
      self.curWord = self.getWord()
      self.curCodeSize = 2
   def getWord(self):
      bts = self.f.read(4)
      return struct.unpack('<I', bts)[0]
   def Read(self, numbits):
      if numbits > 32:
         raise CompilerException("Cannot read more than 32 bits")
      if self.bitsInCurrent >= numbits:
         # numbits inside the current word:
         R = self.curWord & ((1 << numbits) - 1)
         self.curWord = self.curWord >> numbits
         self.bitsInCurrent -= numbits
         return R 
      R = self.curWord
      self.curWord = self.getWord()
      bitsLeft = numbits - self.bitsInCurrent
      
      # Add remaining bits:
      R |= (self.curWord & (0xFFFFFFFF >> (32 - bitsLeft))) << self.bitsInCurrent

      # Update curword and bits in current:
      self.curWord = self.curWord >> bitsLeft
      self.bitsInCurrent = 32 - bitsLeft
      return R
   def ReadVBR(self, numbits):
      """ Read variable bits, checking for the last bit is zero. """
      piece = self.Read(numbits)
      if (piece & (1 << (numbits - 1))) == 0:
         return piece
      result = 0
      nextbit = 0
      while True:
         mask = (1 << (numbits - 1)) - 1
         result |= ( piece & mask ) << nextbit
         if (piece & (1 << (numbits - 1))) == 0:
            return result
         nextbit += numbits - 1
         piece = self.Read(numbits)
   def ReadCode(self):
      """ Read the code depending on the current code size """
      return self.Read(self.curCodeSize)
   def ReadSubBlockId(self):
      return self.ReadVBR(8)
   def EnterSubBlock(self, blockId):
      pass

BLOCKINFO_BLOCKID = 0
FIRST_APPLICATION_BLOCKID = 8
MODULE_BLOCKID = FIRST_APPLICATION_BLOCKID

class BitcodeReader:
   def __init__(self, f):
      self.stream = BitstreamReader(f)
   def parseModule(self):
      for bitsig in [ord('B'), ord('C')]:
         if self.stream.Read(8) != bitsig:
            raise CompilerException('Invalid bitcode signature')
      for bitsig in [0x0, 0xC, 0xE, 0xD]:
         if self.stream.Read(4) != bitsig:
            raise CompilerException('Invalid bitcode signature')
      while True:
         code = self.stream.ReadCode()
         if code != BitCodes.ENTER_SUBBLOCK:
            raise CompilerException('Invalid record at toplevel')
         blockId = self.stream.ReadSubBlockId()
         if blockId == MODULE_BLOCKID:
            print('module block')
            pass
         else:
            print('Block id:', blockId)
            raise 
      return Module()

class BitstreamWriter:
   def __init__(self, f):
      self.f = f
      self.u32 = 0
      self.curpos = 0
   def Emit1(self, val):
      self.Emit(val, 1)
   def Emit(self, val, numbits):
      """ Emits value using numbits bits """
      if numbits == 1:
         if val != 0:
            self.u32 |= (0x1 << self.curpos)
         self.curpos += 1
         if self.curpos == 32:
            self.writeWord()
      elif numbits > 1:
         for i in range(numbits):
            if val & (1 << i) != 0:
               self.Emit1(1)
            else:
               self.Emit1(0)
   def writeWord(self):
      bts = struct.pack('<I', self.u32)
      self.f.write(bts)
      self.u32 = 0
      self.curpos = 0
   def flush(self):
      if self.curpos != 0:
         self.writeWord()

class BitcodeWriter:
   def __init__(self):
      pass
   def WriteModule(self, module):
      pass
   def WriteModuleToFile(self, module, f):
      s = BitstreamWriter(f)
      s.Emit(ord('B'), 8)
      s.Emit(ord('C'), 8)
      s.Emit(0x0, 4)
      s.Emit(0xC, 4)
      s.Emit(0xE, 4)
      s.Emit(0xD, 4)
      self.WriteModule(module)
      s.flush()