def testReadList(self): s = CBS('0b10001111001') t = s.readlist('pad:1, uint:3, pad:4, uint:3') self.assertEqual(t, [0, 1]) s.pos = 0 t = s.readlist('pad:1, pad:5') self.assertEqual(t, []) self.assertEqual(s.pos, 6) s.pos = 0 t = s.readlist('pad:1, bin, pad:4, uint:3') self.assertEqual(t, ['000', 1]) s.pos = 0 t = s.readlist('pad, bin:3, pad:4, uint:3') self.assertEqual(t, ['000', 1])
def testReadList(self): s = CBS("0b10001111001") t = s.readlist("pad:1, uint:3, pad:4, uint:3") self.assertEqual(t, [0, 1]) s.pos = 0 t = s.readlist("pad:1, pad:5") self.assertEqual(t, []) self.assertEqual(s.pos, 6) s.pos = 0 t = s.readlist("pad:1, bin, pad:4, uint:3") self.assertEqual(t, ["000", 1]) s.pos = 0 t = s.readlist("pad, bin:3, pad:4, uint:3") self.assertEqual(t, ["000", 1])
def integer(self, N, M, offset=0): ''' Provide an array of random integers following uniform distribution. Parameters: N: int Amount of provided integers. M: int Upper range (exclusive) of the integers, Which can only take a value among 0, 1, ..., M-1. offset: int Amount of bits at the beginning of the file to be skipped over. Returns: result: 1d numpy array ''' width = int(np.ceil(np.log2(M))) blob = ConstBitStream(filename=self.source) result = np.empty(N, dtype="u4") # 32-bit unsigned integer in native endian blob.pos = offset for i in range(N): while True: number = blob.read(width).uint if number < M: result[i] = number break return result
def testNotAligned(self): a = CBS('0b00111001001010011011') a.pos = 1 self.assertEqual(a.readto('0b00'), '0b011100') self.assertEqual(a.readto('0b110'), '0b10010100110') with self.assertRaises(ValueError): a.readto('')
def testStringRepresentationFromFile(self): s = CBS(filename='test.m1v', pos=2001) self.assertEqual( s.__repr__(), "ConstBitStream(filename='test.m1v', length=1002400, pos=2001)") s.pos = 0 self.assertEqual( s.__repr__(), "ConstBitStream(filename='test.m1v', length=1002400)")
def _load_le_instr(self, bitstream: bitstring.ConstBitStream, numbits: int) -> str: # THUMB mode instructions swap endianness every two bytes! if (self.addr & 1) == 1 and numbits > 16: chunk = "" oldpos = bitstream.pos for _ in range(0, numbits, 16): chunk += bitstring.Bits(uint=bitstream.peek("uintle:%d" % 16), length=16).bin bitstream.pos += 16 bitstream.pos = oldpos return chunk return super()._load_le_instr(bitstream, numbits)
header = header + chr(int(bytes.read(8).hex, 16)) #print("0x00", header) # File header - always SpA1 #print("0x04", bytes.read('uintle:16')) # version maybe ? 31 is different than 61 (61 do not want to be parsed here) #print("0x06", bytes.read('uintle:16')) # real frame width #print("0x08", bytes.read('uintle:32')) # overall width #print("0x0C", bytes.read('uintle:32')) # overall height #print("0x10", bytes.read('uintle:32')) # 0 #print("0x14", bytes.read('uintle:32')) # number of frames #print("0x18", bytes.read('uintle:32')) # 0 #print("0x1C", bytes.read('uintle:32')) # 0 #print("0x20", bytes.read('uintle:32')) # streamsize #print("0x24", bytes.read('uintle:32')) # most of time 4 # version bytes.pos = 0x04 * 8 version = bytes.read('uintle:16') # image width bytes.pos = 0x08 * 8 width = bytes.read('uintle:32') # image height bytes.pos = 0x0C * 8 height = bytes.read('uintle:32') # number of frames bytes.pos = 0x14 * 8 frames = bytes.read('uintle:32') frameoff = int(width / frames)
#!/usr/bin/env python # -*- coding: utf-8 -*- from bitstring import ConstBitStream import sys c = ConstBitStream(filename=sys.argv[1]) #Most log entry ends with 0A, this helps us to seek to the beginning of an entry start = c.find('0x0A', bytealigned=True)[0] #Seek 8 byte into the stream to skip EOL from previus log entry start += 8 c.pos = start while True: #Read and print the binary log header header = c.readlist('8*uintle:32') print header #Get the size in bits of the log message msgSize = (header[0] * 8 - 256) #Move pointer after message c.pos += msgSize #Check if EOL is present after message, if true, move pointer 8 byte if c.peek(8).hex == '0a': c.pos += 8
def parse_font(font_num, spft_filename): FONT_DATA[font_num] = {} # spft_filename = "" # if font_num == 1: # spft_filename = os.path.join(FONT_FOLDER, FONT1_TABLE) # elif font_num == 2: # spft_filename = os.path.join(FONT_FOLDER, FONT2_TABLE) if not font_num in [1, 2]: print "Invalid font number. Valid values: 1, 2" return None # Header: # 74467053 -- Magic # 04000000 -- Magic # XXXXXXXX -- Number of entries in font table # XXXXXXXX -- Position of first entry in font table # # XXXXXXXX -- Number of chunks in the mappings table # XXXXXXXX -- Start position of mappings table (little-endian, as always) # ***0x20000000 in both fonts I've seen # XXXXXXXX -- ???? # XXXXXXXX -- ???? # # Character Mappings: from start pos (0x20) to (start pos + (# chunks * 2)) # * To avoid overcomplicating this, I'm just referring to the start pos as # 0x20 since I've only ever seen that value used. # * Two-byte chunks (XXXX) # * The position of each chunk, minus 0x20, divided by two (because they're # two-byte chunks), equals the UTF-16 representation of a character. # (i.e. pos 0x00A8: (0x00A8 - 0x20) / 2 = 0x0044 -> "A") # * The value of each chunk is the index of that character in the font table, # little-endian. # (i.e. if the character "A" is the 35th entry, zero-indexed = 0x2200) # * A chunk value of 0xFFFF means that character is not present in the font. spft = ConstBitStream(filename = spft_filename) magic = spft.read(64) if magic != SPFT_MAGIC: print "Didn't find SPFT magic." exit() num_entries = spft.read('uintle:32') table_start = spft.read('uintle:32') if num_entries == 0: print "No entries in SPFT table." return None if table_start * 8 > spft.len: print "Invalid SPFT table position." return None #print "Characters in font:", num_entries spft.pos = table_start * 8 # Table: # * Entry: # XXXX -- Character # XXXX -- X Pos # XXXX -- Y Pos # XXXX -- Width # XXXX -- Height # 0000 -- Padding # 0000 -- Padding # FA08 -- Something to do with rendering offset. FA -> -6 -> renders six pixels down #print " XXXX YYYY WWW HHH" for i in range(0, num_entries): char = spft.read(16) char = char.bytes.decode('utf-16le') xpos = spft.read('uintle:16') ypos = spft.read('uintle:16') width = spft.read('uintle:16') height = spft.read('uintle:16') dummy = spft.read('uintle:16') dummy = spft.read('uintle:16') yshift = spft.read('intle:8') dummy = spft.read('uintle:8') info = {'x': xpos, 'y': ypos, 'w': width, 'h': height} FONT_DATA[font_num][char] = info
def testNotAligned(self): a = CBS('0b00111001001010011011') a.pos = 1 self.assertEqual(a.readto('0b00'), '0b011100') self.assertEqual(a.readto('0b110'), '0b10010100110') self.assertRaises(ValueError, a.readto, '')
def parse_font(font_num, spft_filename): FONT_DATA[font_num] = {} # spft_filename = "" # if font_num == 1: # spft_filename = os.path.join(FONT_FOLDER, FONT1_TABLE) # elif font_num == 2: # spft_filename = os.path.join(FONT_FOLDER, FONT2_TABLE) if not font_num in [1, 2]: print "Invalid font number. Valid values: 1, 2" return None # Header: # 74467053 -- Magic # 04000000 -- Magic # XXXXXXXX -- Number of entries in font table # XXXXXXXX -- Position of first entry in font table # # XXXXXXXX -- Number of chunks in the mappings table # XXXXXXXX -- Start position of mappings table (little-endian, as always) # ***0x20000000 in both fonts I've seen # XXXXXXXX -- ???? # XXXXXXXX -- ???? # # Character Mappings: from start pos (0x20) to (start pos + (# chunks * 2)) # * To avoid overcomplicating this, I'm just referring to the start pos as # 0x20 since I've only ever seen that value used. # * Two-byte chunks (XXXX) # * The position of each chunk, minus 0x20, divided by two (because they're # two-byte chunks), equals the UTF-16 representation of a character. # (i.e. pos 0x00A8: (0x00A8 - 0x20) / 2 = 0x0044 -> "A") # * The value of each chunk is the index of that character in the font table, # little-endian. # (i.e. if the character "A" is the 35th entry, zero-indexed = 0x2200) # * A chunk value of 0xFFFF means that character is not present in the font. spft = ConstBitStream(filename = spft_filename) magic = spft.read(64) if magic != SPFT_MAGIC: print "Didn't find SPFT magic." exit() num_entries = spft.read('uintle:32') table_start = spft.read('uintle:32') if num_entries == 0: print "No entries in SPFT table." return None if table_start * 8 > spft.len: print "Invalid SPFT table position." return None #print "Characters in font:", num_entries spft.pos = table_start * 8 # Table: # * Entry: # XXXX -- Character # XXXX -- X Pos # XXXX -- Y Pos # XXXX -- Width # XXXX -- Height # 0000 -- Padding # 0000 -- Padding # FA08 -- Something to do with rendering offset. FA -> -6 -> renders six pixels down #print " XXXX YYYY WWW HHH" for i in range(0, num_entries): char = spft.read(16) char = char.bytes.decode('utf-16le') xpos = spft.read('uintle:16') ypos = spft.read('uintle:16') width = spft.read('uintle:16') height = spft.read('uintle:16') dummy = spft.read('uintle:16') dummy = spft.read('uintle:16') yshift = spft.read('intle:8') dummy = spft.read('uintle:8') info = {'x': xpos, 'y': ypos, 'w': width, 'h': height} FONT_DATA[font_num][char] = info
def testNotAligned(self): a = CBS("0b00111001001010011011") a.pos = 1 self.assertEqual(a.readto("0b00"), "0b011100") self.assertEqual(a.readto("0b110"), "0b10010100110") self.assertRaises(ValueError, a.readto, "")
quitWithError("ERROR: File does not exist: {}".format(pathToGBFile)) # Decode the base64 data in the projectData file nsData = xmlRoot.find(".//*[key='NS.data']/data") encodedText = nsData.text try: decodedData = base64.b64decode(encodedText) with open("decoded.bin", "wb") as fp: fp.write(decodedData) except Exception as ex: print(str(ex)) quitWithError("ERROR: Failed to decode data") # Open the decoded binary file for parsing s = ConstBitStream(filename='decoded.bin') s.pos = 0 if bDebug: dumphex(0x800, s) # Pull out the tempo, offset is number of BITS s.pos = TEMPO_OFFSET preciseBPM = s.read('uintle:24') songTempo = preciseBPM / 10000 debugPrint("Tempo BPM is {} ({})".format(songTempo, hex(preciseBPM))) # Pull out the time signature s.pos = TIME_SIGNATURE_OFFSET numerator = s.read('uintle:8') denominator = s.read('uintle:8') debugPrint("Time signature is {}/{}".format(numerator, 2**denominator))