1*f4ee7fbaSAndroid Build Coastguard Worker#!python3 2*f4ee7fbaSAndroid Build Coastguard Worker"""Program to dump contents of Brotli compressed files showing the compression format. 3*f4ee7fbaSAndroid Build Coastguard WorkerJurjen N.E. Bos, 2016. 4*f4ee7fbaSAndroid Build Coastguard WorkerI found the following issues with the Brotli format: 5*f4ee7fbaSAndroid Build Coastguard Worker- The distance alphabet has size 16+(48<<POSTFIX), 6*f4ee7fbaSAndroid Build Coastguard Worker but the last symbols are useless. 7*f4ee7fbaSAndroid Build Coastguard Worker It could be lowered to 16+(44-POSTFIX<<POSTFIX), and this could matter. 8*f4ee7fbaSAndroid Build Coastguard Worker- The block type code is useless if NBLTYPES==2, you would only need 1 symbol 9*f4ee7fbaSAndroid Build Coastguard Worker anyway, so why don't you just switch to "the other" type? 10*f4ee7fbaSAndroid Build Coastguard Worker""" 11*f4ee7fbaSAndroid Build Coastguard Workerimport struct 12*f4ee7fbaSAndroid Build Coastguard Workerfrom operator import itemgetter, methodcaller 13*f4ee7fbaSAndroid Build Coastguard Workerfrom itertools import accumulate, repeat 14*f4ee7fbaSAndroid Build Coastguard Workerfrom collections import defaultdict, deque 15*f4ee7fbaSAndroid Build Coastguard Workerfrom functools import partial 16*f4ee7fbaSAndroid Build Coastguard Worker 17*f4ee7fbaSAndroid Build Coastguard Workerclass InvalidStream(Exception): pass 18*f4ee7fbaSAndroid Build Coastguard Worker#lookup table 19*f4ee7fbaSAndroid Build Coastguard WorkerL, I, D = "literal", "insert©", "distance" 20*f4ee7fbaSAndroid Build Coastguard WorkerpL, pI, pD = 'P'+L, 'P'+I, 'P'+D 21*f4ee7fbaSAndroid Build Coastguard Worker 22*f4ee7fbaSAndroid Build Coastguard Workerdef outputCharFormatter(c): 23*f4ee7fbaSAndroid Build Coastguard Worker """Show character in readable format 24*f4ee7fbaSAndroid Build Coastguard Worker """ 25*f4ee7fbaSAndroid Build Coastguard Worker #TODO 2: allow hex only output 26*f4ee7fbaSAndroid Build Coastguard Worker if 32<c<127: return chr(c) 27*f4ee7fbaSAndroid Build Coastguard Worker elif c==10: return '\\n' 28*f4ee7fbaSAndroid Build Coastguard Worker elif c==13: return '\\r' 29*f4ee7fbaSAndroid Build Coastguard Worker elif c==32: return '" "' 30*f4ee7fbaSAndroid Build Coastguard Worker else: return '\\x{:02x}'.format(c) 31*f4ee7fbaSAndroid Build Coastguard Worker 32*f4ee7fbaSAndroid Build Coastguard Workerdef outputFormatter(s): 33*f4ee7fbaSAndroid Build Coastguard Worker """Show string or char. 34*f4ee7fbaSAndroid Build Coastguard Worker """ 35*f4ee7fbaSAndroid Build Coastguard Worker result = '' 36*f4ee7fbaSAndroid Build Coastguard Worker def formatSubString(s): 37*f4ee7fbaSAndroid Build Coastguard Worker for c in s: 38*f4ee7fbaSAndroid Build Coastguard Worker if c==32: yield ' ' 39*f4ee7fbaSAndroid Build Coastguard Worker else: yield outputCharFormatter(c) 40*f4ee7fbaSAndroid Build Coastguard Worker if len(result)<200: return ''.join(formatSubString(s)) 41*f4ee7fbaSAndroid Build Coastguard Worker else: 42*f4ee7fbaSAndroid Build Coastguard Worker return ''.join(formatSubString(s[:100]))+'...'+ \ 43*f4ee7fbaSAndroid Build Coastguard Worker ''.join(formatSubString(s[-100:])) 44*f4ee7fbaSAndroid Build Coastguard Worker 45*f4ee7fbaSAndroid Build Coastguard Worker 46*f4ee7fbaSAndroid Build Coastguard Workerclass BitStream: 47*f4ee7fbaSAndroid Build Coastguard Worker """Represent a bytes object. Can read bits and prefix codes the way 48*f4ee7fbaSAndroid Build Coastguard Worker Brotli does. 49*f4ee7fbaSAndroid Build Coastguard Worker """ 50*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, byteString): 51*f4ee7fbaSAndroid Build Coastguard Worker self.data = byteString 52*f4ee7fbaSAndroid Build Coastguard Worker #position in bits: byte pos is pos>>3, bit pos is pos&7 53*f4ee7fbaSAndroid Build Coastguard Worker self.pos = 0 54*f4ee7fbaSAndroid Build Coastguard Worker 55*f4ee7fbaSAndroid Build Coastguard Worker def __repr__(self): 56*f4ee7fbaSAndroid Build Coastguard Worker """Representation 57*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke 58*f4ee7fbaSAndroid Build Coastguard Worker BitStream(pos=0:0) 59*f4ee7fbaSAndroid Build Coastguard Worker """ 60*f4ee7fbaSAndroid Build Coastguard Worker return "BitStream(pos={:x}:{})".format(self.pos>>3, self.pos&7) 61*f4ee7fbaSAndroid Build Coastguard Worker 62*f4ee7fbaSAndroid Build Coastguard Worker def read(self, n): 63*f4ee7fbaSAndroid Build Coastguard Worker """Read n bits from the stream and return as an integer. 64*f4ee7fbaSAndroid Build Coastguard Worker Produces zero bits beyond the stream. 65*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.data[0]==27 66*f4ee7fbaSAndroid Build Coastguard Worker True 67*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.read(5) 68*f4ee7fbaSAndroid Build Coastguard Worker 27 69*f4ee7fbaSAndroid Build Coastguard Worker 70*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke 71*f4ee7fbaSAndroid Build Coastguard Worker BitStream(pos=0:5) 72*f4ee7fbaSAndroid Build Coastguard Worker """ 73*f4ee7fbaSAndroid Build Coastguard Worker value = self.peek(n) 74*f4ee7fbaSAndroid Build Coastguard Worker self.pos += n 75*f4ee7fbaSAndroid Build Coastguard Worker if self.pos>len(self.data)*8: 76*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('Read past end of stream') 77*f4ee7fbaSAndroid Build Coastguard Worker return value 78*f4ee7fbaSAndroid Build Coastguard Worker 79*f4ee7fbaSAndroid Build Coastguard Worker def peek(self, n): 80*f4ee7fbaSAndroid Build Coastguard Worker """Peek an n bit integer from the stream without updating the pointer. 81*f4ee7fbaSAndroid Build Coastguard Worker It is not an error to read beyond the end of the stream. 82*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.data[:2]==b'\x1b\x2e' and 0x2e1b==11803 83*f4ee7fbaSAndroid Build Coastguard Worker True 84*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.peek(15) 85*f4ee7fbaSAndroid Build Coastguard Worker 11803 86*f4ee7fbaSAndroid Build Coastguard Worker >>> hex(olleke.peek(32)) 87*f4ee7fbaSAndroid Build Coastguard Worker '0x2e1b' 88*f4ee7fbaSAndroid Build Coastguard Worker """ 89*f4ee7fbaSAndroid Build Coastguard Worker #read bytes that contain the data: self.data[self.pos>>3:self.pos+n+7>>3] 90*f4ee7fbaSAndroid Build Coastguard Worker #convert to int: int.from_bytes(..., 'little') 91*f4ee7fbaSAndroid Build Coastguard Worker #shift out the bits from the first byte: >>(self.pos&7) 92*f4ee7fbaSAndroid Build Coastguard Worker #mask unwanted bits: & (1<<n)-1 93*f4ee7fbaSAndroid Build Coastguard Worker return int.from_bytes( 94*f4ee7fbaSAndroid Build Coastguard Worker self.data[self.pos>>3:self.pos+n+7>>3], 95*f4ee7fbaSAndroid Build Coastguard Worker 'little')>>(self.pos&7) & (1<<n)-1 96*f4ee7fbaSAndroid Build Coastguard Worker 97*f4ee7fbaSAndroid Build Coastguard Worker def readBytes(self, n): 98*f4ee7fbaSAndroid Build Coastguard Worker """Read n bytes from the stream on a byte boundary. 99*f4ee7fbaSAndroid Build Coastguard Worker """ 100*f4ee7fbaSAndroid Build Coastguard Worker if self.pos&7: raise ValueError('readBytes: need byte boundary') 101*f4ee7fbaSAndroid Build Coastguard Worker result = self.data[self.pos>>3:(self.pos>>3)+n] 102*f4ee7fbaSAndroid Build Coastguard Worker self.pos += 8*n 103*f4ee7fbaSAndroid Build Coastguard Worker return result 104*f4ee7fbaSAndroid Build Coastguard Worker 105*f4ee7fbaSAndroid Build Coastguard Worker#-----------------------Symbol------------------------------------------- 106*f4ee7fbaSAndroid Build Coastguard Workerclass Symbol: 107*f4ee7fbaSAndroid Build Coastguard Worker """A symbol in a code. 108*f4ee7fbaSAndroid Build Coastguard Worker Refers back to the code that contains it. 109*f4ee7fbaSAndroid Build Coastguard Worker Index is the place in the alphabet of the symbol. 110*f4ee7fbaSAndroid Build Coastguard Worker """ 111*f4ee7fbaSAndroid Build Coastguard Worker __slots__ = 'code', 'index' 112*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, code, value): 113*f4ee7fbaSAndroid Build Coastguard Worker self.code = code 114*f4ee7fbaSAndroid Build Coastguard Worker self.index = value 115*f4ee7fbaSAndroid Build Coastguard Worker 116*f4ee7fbaSAndroid Build Coastguard Worker def __repr__(self): 117*f4ee7fbaSAndroid Build Coastguard Worker return 'Symbol({}, {})'.format(self.code.name, self.index) 118*f4ee7fbaSAndroid Build Coastguard Worker 119*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): 120*f4ee7fbaSAndroid Build Coastguard Worker """Number of bits in the prefix notation of this symbol 121*f4ee7fbaSAndroid Build Coastguard Worker """ 122*f4ee7fbaSAndroid Build Coastguard Worker return self.code.length(self.index) 123*f4ee7fbaSAndroid Build Coastguard Worker 124*f4ee7fbaSAndroid Build Coastguard Worker def __int__(self): 125*f4ee7fbaSAndroid Build Coastguard Worker return self.index 126*f4ee7fbaSAndroid Build Coastguard Worker 127*f4ee7fbaSAndroid Build Coastguard Worker #these routines call equivalent routine in Code class 128*f4ee7fbaSAndroid Build Coastguard Worker def bitPattern(self): 129*f4ee7fbaSAndroid Build Coastguard Worker """Value of the symbol in the stream 130*f4ee7fbaSAndroid Build Coastguard Worker """ 131*f4ee7fbaSAndroid Build Coastguard Worker return self.code.bitPattern(self.index) 132*f4ee7fbaSAndroid Build Coastguard Worker 133*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self): 134*f4ee7fbaSAndroid Build Coastguard Worker """Number of extra bits to read for this symbol 135*f4ee7fbaSAndroid Build Coastguard Worker """ 136*f4ee7fbaSAndroid Build Coastguard Worker return self.code.extraBits(self.index) 137*f4ee7fbaSAndroid Build Coastguard Worker 138*f4ee7fbaSAndroid Build Coastguard Worker def __str__(self): 139*f4ee7fbaSAndroid Build Coastguard Worker """Short descriptor of the symbol without extra bits. 140*f4ee7fbaSAndroid Build Coastguard Worker """ 141*f4ee7fbaSAndroid Build Coastguard Worker return self.code.mnemonic(self.index) 142*f4ee7fbaSAndroid Build Coastguard Worker 143*f4ee7fbaSAndroid Build Coastguard Worker #requiring optional extra bits, if self.code supports them 144*f4ee7fbaSAndroid Build Coastguard Worker def value(self, extra=None): 145*f4ee7fbaSAndroid Build Coastguard Worker """The value used for processing. Can be a tuple. 146*f4ee7fbaSAndroid Build Coastguard Worker with optional extra bits 147*f4ee7fbaSAndroid Build Coastguard Worker """ 148*f4ee7fbaSAndroid Build Coastguard Worker if isinstance(self.code, WithExtra): 149*f4ee7fbaSAndroid Build Coastguard Worker if not 0<=extra<1<<self.extraBits(): 150*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError("value: extra value doesn't fit in extraBits") 151*f4ee7fbaSAndroid Build Coastguard Worker return self.code.value(self.index, extra) 152*f4ee7fbaSAndroid Build Coastguard Worker if extra is not None: 153*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: no extra bits for this code') 154*f4ee7fbaSAndroid Build Coastguard Worker return self.code.value(self.index) 155*f4ee7fbaSAndroid Build Coastguard Worker 156*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, extra=None): 157*f4ee7fbaSAndroid Build Coastguard Worker """Long explanation of the value from the numeric value 158*f4ee7fbaSAndroid Build Coastguard Worker with optional extra bits 159*f4ee7fbaSAndroid Build Coastguard Worker Used by Layout.verboseRead when printing the value 160*f4ee7fbaSAndroid Build Coastguard Worker """ 161*f4ee7fbaSAndroid Build Coastguard Worker if isinstance(self.code, WithExtra): 162*f4ee7fbaSAndroid Build Coastguard Worker return self.code.callback(self, extra) 163*f4ee7fbaSAndroid Build Coastguard Worker return self.code.callback(self) 164*f4ee7fbaSAndroid Build Coastguard Worker 165*f4ee7fbaSAndroid Build Coastguard Worker#========================Code definitions================================== 166*f4ee7fbaSAndroid Build Coastguard Workerclass RangeDecoder: 167*f4ee7fbaSAndroid Build Coastguard Worker """A decoder for the Code class that assumes the symbols 168*f4ee7fbaSAndroid Build Coastguard Worker are encoded consecutively in binary. 169*f4ee7fbaSAndroid Build Coastguard Worker It all depends on the "alphabetSize" property. 170*f4ee7fbaSAndroid Build Coastguard Worker The range runs from 0 to alphabetSize-1. 171*f4ee7fbaSAndroid Build Coastguard Worker This is the default decoder. 172*f4ee7fbaSAndroid Build Coastguard Worker """ 173*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, *, alphabetSize=None, bitLength=None, **args): 174*f4ee7fbaSAndroid Build Coastguard Worker if bitLength is not None: alphabetSize = 1<<bitLength 175*f4ee7fbaSAndroid Build Coastguard Worker if alphabetSize is not None: 176*f4ee7fbaSAndroid Build Coastguard Worker self.alphabetSize = alphabetSize 177*f4ee7fbaSAndroid Build Coastguard Worker self.maxLength = (alphabetSize-1).bit_length() 178*f4ee7fbaSAndroid Build Coastguard Worker 179*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): 180*f4ee7fbaSAndroid Build Coastguard Worker return self.alphabetSize 181*f4ee7fbaSAndroid Build Coastguard Worker 182*f4ee7fbaSAndroid Build Coastguard Worker def __iter__(self): 183*f4ee7fbaSAndroid Build Coastguard Worker """Produce all symbols. 184*f4ee7fbaSAndroid Build Coastguard Worker """ 185*f4ee7fbaSAndroid Build Coastguard Worker return map(partial(Symbol, self), range(len(self))) 186*f4ee7fbaSAndroid Build Coastguard Worker 187*f4ee7fbaSAndroid Build Coastguard Worker def __getitem__(self, index): 188*f4ee7fbaSAndroid Build Coastguard Worker if index>=self.alphabetSize: raise ValueError('index out of range') 189*f4ee7fbaSAndroid Build Coastguard Worker return Symbol(self, index) 190*f4ee7fbaSAndroid Build Coastguard Worker 191*f4ee7fbaSAndroid Build Coastguard Worker def bitPattern(self, index): 192*f4ee7fbaSAndroid Build Coastguard Worker return '{:0{}b}'.format(index, self.maxLength) 193*f4ee7fbaSAndroid Build Coastguard Worker 194*f4ee7fbaSAndroid Build Coastguard Worker def length(self, index): 195*f4ee7fbaSAndroid Build Coastguard Worker """Encoding length of given symbol. 196*f4ee7fbaSAndroid Build Coastguard Worker Does not depend on index in this case. 197*f4ee7fbaSAndroid Build Coastguard Worker """ 198*f4ee7fbaSAndroid Build Coastguard Worker return self.maxLength 199*f4ee7fbaSAndroid Build Coastguard Worker 200*f4ee7fbaSAndroid Build Coastguard Worker def decodePeek(self, data): 201*f4ee7fbaSAndroid Build Coastguard Worker """Find which symbol index matches the given data (from peek, as a number) 202*f4ee7fbaSAndroid Build Coastguard Worker and return the number of bits decoded. 203*f4ee7fbaSAndroid Build Coastguard Worker Can also be used to figure out length of a symbol. 204*f4ee7fbaSAndroid Build Coastguard Worker """ 205*f4ee7fbaSAndroid Build Coastguard Worker return self.maxLength, Symbol(self, data&(1<<self.maxLength)-1) 206*f4ee7fbaSAndroid Build Coastguard Worker 207*f4ee7fbaSAndroid Build Coastguard Workerclass PrefixDecoder: 208*f4ee7fbaSAndroid Build Coastguard Worker """A decoder for the Code class that uses a prefix code. 209*f4ee7fbaSAndroid Build Coastguard Worker The code is determined by encoding: 210*f4ee7fbaSAndroid Build Coastguard Worker encode[p] gives the index corresponding to bit pattern p. 211*f4ee7fbaSAndroid Build Coastguard Worker Used setDecode(decodeTable) to switch the decoder from the default 212*f4ee7fbaSAndroid Build Coastguard Worker to a prefix decoder, or pass decodeTable at init. 213*f4ee7fbaSAndroid Build Coastguard Worker You can also use setLength(lengthTable) 214*f4ee7fbaSAndroid Build Coastguard Worker to define the encoding from the lengths. 215*f4ee7fbaSAndroid Build Coastguard Worker The set of symbol values does not need to be consecutive. 216*f4ee7fbaSAndroid Build Coastguard Worker """ 217*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, *, decodeTable=None, **args): 218*f4ee7fbaSAndroid Build Coastguard Worker if decodeTable is not None: self.setDecode(decodeTable) 219*f4ee7fbaSAndroid Build Coastguard Worker 220*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): 221*f4ee7fbaSAndroid Build Coastguard Worker return len(self.decodeTable) 222*f4ee7fbaSAndroid Build Coastguard Worker 223*f4ee7fbaSAndroid Build Coastguard Worker def __iter__(self): 224*f4ee7fbaSAndroid Build Coastguard Worker def revBits(index): 225*f4ee7fbaSAndroid Build Coastguard Worker return self.bitPattern(index)[::-1] 226*f4ee7fbaSAndroid Build Coastguard Worker return ( 227*f4ee7fbaSAndroid Build Coastguard Worker Symbol(self, index) 228*f4ee7fbaSAndroid Build Coastguard Worker for index in sorted(self.decodeTable.values(), key=revBits) 229*f4ee7fbaSAndroid Build Coastguard Worker ) 230*f4ee7fbaSAndroid Build Coastguard Worker 231*f4ee7fbaSAndroid Build Coastguard Worker def __getitem__(self, index): 232*f4ee7fbaSAndroid Build Coastguard Worker if index not in self.lengthTable: 233*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('No symbol {}[{}]'.format( 234*f4ee7fbaSAndroid Build Coastguard Worker self.__class__.__name__, index)) 235*f4ee7fbaSAndroid Build Coastguard Worker return Symbol(self, index) 236*f4ee7fbaSAndroid Build Coastguard Worker 237*f4ee7fbaSAndroid Build Coastguard Worker def bitPattern(self, index): 238*f4ee7fbaSAndroid Build Coastguard Worker bits = next(b for (b,s) in self.decodeTable.items() if s==index) 239*f4ee7fbaSAndroid Build Coastguard Worker return '{:0{}b}'.format(bits, self.length(index)) 240*f4ee7fbaSAndroid Build Coastguard Worker 241*f4ee7fbaSAndroid Build Coastguard Worker def length(self, index): 242*f4ee7fbaSAndroid Build Coastguard Worker """Encoding length of given symbol. 243*f4ee7fbaSAndroid Build Coastguard Worker """ 244*f4ee7fbaSAndroid Build Coastguard Worker return self.lengthTable[index] 245*f4ee7fbaSAndroid Build Coastguard Worker 246*f4ee7fbaSAndroid Build Coastguard Worker def decodePeek(self, data): 247*f4ee7fbaSAndroid Build Coastguard Worker """Find which symbol index matches the given data (from peek, as a number) 248*f4ee7fbaSAndroid Build Coastguard Worker and return the number of bits decoded. 249*f4ee7fbaSAndroid Build Coastguard Worker Can also be used to figure out length of a symbol. 250*f4ee7fbaSAndroid Build Coastguard Worker """ 251*f4ee7fbaSAndroid Build Coastguard Worker #do binary search for word length 252*f4ee7fbaSAndroid Build Coastguard Worker #invariant: lo<=length<=hi 253*f4ee7fbaSAndroid Build Coastguard Worker lo, hi = self.minLength, self.maxLength 254*f4ee7fbaSAndroid Build Coastguard Worker while lo<=hi: 255*f4ee7fbaSAndroid Build Coastguard Worker mid = lo+hi>>1 256*f4ee7fbaSAndroid Build Coastguard Worker #note lo<=mid<hi at this point 257*f4ee7fbaSAndroid Build Coastguard Worker mask = (1<<mid)-1 258*f4ee7fbaSAndroid Build Coastguard Worker #lets see what happens if we guess length is mid 259*f4ee7fbaSAndroid Build Coastguard Worker try: index = self.decodeTable[data&mask] 260*f4ee7fbaSAndroid Build Coastguard Worker except KeyError: 261*f4ee7fbaSAndroid Build Coastguard Worker #too many bits specified, reduce estimated length 262*f4ee7fbaSAndroid Build Coastguard Worker hi = mid-1 263*f4ee7fbaSAndroid Build Coastguard Worker continue 264*f4ee7fbaSAndroid Build Coastguard Worker #we found a symbol, but there could be a longer match 265*f4ee7fbaSAndroid Build Coastguard Worker symbolLength = self.lengthTable[index] 266*f4ee7fbaSAndroid Build Coastguard Worker if symbolLength<=mid: 267*f4ee7fbaSAndroid Build Coastguard Worker #all bits match, symbol must be right 268*f4ee7fbaSAndroid Build Coastguard Worker return symbolLength, Symbol(self, index) 269*f4ee7fbaSAndroid Build Coastguard Worker #there must be more bits to match 270*f4ee7fbaSAndroid Build Coastguard Worker lo = mid+1 271*f4ee7fbaSAndroid Build Coastguard Worker return lo, Symbol(self, index) 272*f4ee7fbaSAndroid Build Coastguard Worker 273*f4ee7fbaSAndroid Build Coastguard Worker #routine to set up the tables 274*f4ee7fbaSAndroid Build Coastguard Worker def setDecode(self, decodeTable): 275*f4ee7fbaSAndroid Build Coastguard Worker """Store decodeTable, 276*f4ee7fbaSAndroid Build Coastguard Worker and compute lengthTable, minLength, maxLength from encodings. 277*f4ee7fbaSAndroid Build Coastguard Worker """ 278*f4ee7fbaSAndroid Build Coastguard Worker self.decodeTable = decodeTable 279*f4ee7fbaSAndroid Build Coastguard Worker #set of symbols with unknown length 280*f4ee7fbaSAndroid Build Coastguard Worker todo = set(decodeTable) 281*f4ee7fbaSAndroid Build Coastguard Worker #bit size under investigation 282*f4ee7fbaSAndroid Build Coastguard Worker maskLength = 0 283*f4ee7fbaSAndroid Build Coastguard Worker lengthTable = {} 284*f4ee7fbaSAndroid Build Coastguard Worker while todo: 285*f4ee7fbaSAndroid Build Coastguard Worker mask = (1<<maskLength)-1 286*f4ee7fbaSAndroid Build Coastguard Worker #split the encodings that we didn't find yet using b bits 287*f4ee7fbaSAndroid Build Coastguard Worker splitSymbols = defaultdict(list) 288*f4ee7fbaSAndroid Build Coastguard Worker for s in todo: splitSymbols[s&mask].append(s) 289*f4ee7fbaSAndroid Build Coastguard Worker #unique encodings have a length of maskLength bits 290*f4ee7fbaSAndroid Build Coastguard Worker #set length, and remove from todo list 291*f4ee7fbaSAndroid Build Coastguard Worker for s,subset in splitSymbols.items(): 292*f4ee7fbaSAndroid Build Coastguard Worker if len(subset)==1: 293*f4ee7fbaSAndroid Build Coastguard Worker lengthTable[self.decodeTable[s]] = maskLength 294*f4ee7fbaSAndroid Build Coastguard Worker todo.remove(s) 295*f4ee7fbaSAndroid Build Coastguard Worker #now investigate with longer mask 296*f4ee7fbaSAndroid Build Coastguard Worker maskLength +=1 297*f4ee7fbaSAndroid Build Coastguard Worker #save result 298*f4ee7fbaSAndroid Build Coastguard Worker self.lengthTable = lengthTable 299*f4ee7fbaSAndroid Build Coastguard Worker self.minLength = min(lengthTable.values()) 300*f4ee7fbaSAndroid Build Coastguard Worker self.maxLength = max(lengthTable.values()) 301*f4ee7fbaSAndroid Build Coastguard Worker self.switchToPrefix() 302*f4ee7fbaSAndroid Build Coastguard Worker 303*f4ee7fbaSAndroid Build Coastguard Worker def setLength(self, lengthTable): 304*f4ee7fbaSAndroid Build Coastguard Worker """Given the bit pattern lengths for symbols given in lengthTable, 305*f4ee7fbaSAndroid Build Coastguard Worker set decodeTable, minLength, maxLength 306*f4ee7fbaSAndroid Build Coastguard Worker """ 307*f4ee7fbaSAndroid Build Coastguard Worker self.lengthTable = lengthTable 308*f4ee7fbaSAndroid Build Coastguard Worker self.minLength = min(lengthTable.values()) 309*f4ee7fbaSAndroid Build Coastguard Worker self.maxLength = max(lengthTable.values()) 310*f4ee7fbaSAndroid Build Coastguard Worker #compute the backwards codes first; then reverse them 311*f4ee7fbaSAndroid Build Coastguard Worker #compute (backwards) first code for every separate lengths 312*f4ee7fbaSAndroid Build Coastguard Worker nextCodes = [] 313*f4ee7fbaSAndroid Build Coastguard Worker #build codes for each length, from right to left 314*f4ee7fbaSAndroid Build Coastguard Worker code = 0 315*f4ee7fbaSAndroid Build Coastguard Worker for bits in range(self.maxLength+1): 316*f4ee7fbaSAndroid Build Coastguard Worker code <<= 1 317*f4ee7fbaSAndroid Build Coastguard Worker nextCodes.append(code) 318*f4ee7fbaSAndroid Build Coastguard Worker code += sum(x==bits for x in lengthTable.values()) 319*f4ee7fbaSAndroid Build Coastguard Worker self.decodeTable = {} 320*f4ee7fbaSAndroid Build Coastguard Worker #count codes for each length, and store reversed in the table 321*f4ee7fbaSAndroid Build Coastguard Worker for symbol in sorted(lengthTable): 322*f4ee7fbaSAndroid Build Coastguard Worker bits = lengthTable[symbol] 323*f4ee7fbaSAndroid Build Coastguard Worker bitpattern = '{:0{}b}'.format(nextCodes[bits], bits) 324*f4ee7fbaSAndroid Build Coastguard Worker self.decodeTable[int(bitpattern[::-1], 2)] = symbol 325*f4ee7fbaSAndroid Build Coastguard Worker nextCodes[bits] += 1 326*f4ee7fbaSAndroid Build Coastguard Worker self.switchToPrefix() 327*f4ee7fbaSAndroid Build Coastguard Worker 328*f4ee7fbaSAndroid Build Coastguard Worker def switchToPrefix(self): 329*f4ee7fbaSAndroid Build Coastguard Worker """This routine makes sure the prefix decoder is activated. 330*f4ee7fbaSAndroid Build Coastguard Worker """ 331*f4ee7fbaSAndroid Build Coastguard Worker self.mode = PrefixDecoder 332*f4ee7fbaSAndroid Build Coastguard Worker 333*f4ee7fbaSAndroid Build Coastguard Workerclass Code(RangeDecoder, PrefixDecoder): 334*f4ee7fbaSAndroid Build Coastguard Worker """An alphabet of symbols, that can be read from a stream. 335*f4ee7fbaSAndroid Build Coastguard Worker If you use setDecode or setLength, you have a prefix code, 336*f4ee7fbaSAndroid Build Coastguard Worker otherwise you have a range code. 337*f4ee7fbaSAndroid Build Coastguard Worker Features: 338*f4ee7fbaSAndroid Build Coastguard Worker code[index] produces symbol with given index 339*f4ee7fbaSAndroid Build Coastguard Worker value(index): value of symbol 340*f4ee7fbaSAndroid Build Coastguard Worker mnemonic(index): short description of symbol 341*f4ee7fbaSAndroid Build Coastguard Worker explanation(index): show meaning of symbol, shown in Layout.verboseRead 342*f4ee7fbaSAndroid Build Coastguard Worker iter(code): produce all symbols in some order 343*f4ee7fbaSAndroid Build Coastguard Worker name: show as context in Layout.verboseRead 344*f4ee7fbaSAndroid Build Coastguard Worker """ 345*f4ee7fbaSAndroid Build Coastguard Worker name = '?' 346*f4ee7fbaSAndroid Build Coastguard Worker #callback is a function that gets the symbol and the extra bits 347*f4ee7fbaSAndroid Build Coastguard Worker #default callback calls explanation 348*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, *, callback=None, description='', **args): 349*f4ee7fbaSAndroid Build Coastguard Worker """Don't forget to set either alphabetSize or decodeTable 350*f4ee7fbaSAndroid Build Coastguard Worker """ 351*f4ee7fbaSAndroid Build Coastguard Worker #set name when provided, otherwise take class variable 352*f4ee7fbaSAndroid Build Coastguard Worker if name is not None: self.name = name 353*f4ee7fbaSAndroid Build Coastguard Worker if callback is not None: self.callback = callback 354*f4ee7fbaSAndroid Build Coastguard Worker self.description = description 355*f4ee7fbaSAndroid Build Coastguard Worker #mode switch 356*f4ee7fbaSAndroid Build Coastguard Worker if 'bitLength' in args or 'alphabetSize' in args: 357*f4ee7fbaSAndroid Build Coastguard Worker self.mode = RangeDecoder 358*f4ee7fbaSAndroid Build Coastguard Worker RangeDecoder.__init__(self, **args) 359*f4ee7fbaSAndroid Build Coastguard Worker elif 'decodeTable' in args: 360*f4ee7fbaSAndroid Build Coastguard Worker self.mode = PrefixDecoder 361*f4ee7fbaSAndroid Build Coastguard Worker PrefixDecoder.__init__(self, **args) 362*f4ee7fbaSAndroid Build Coastguard Worker else: 363*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(**args) 364*f4ee7fbaSAndroid Build Coastguard Worker 365*f4ee7fbaSAndroid Build Coastguard Worker def __repr__(self): 366*f4ee7fbaSAndroid Build Coastguard Worker return self.__class__.__name__+' '+self.name 367*f4ee7fbaSAndroid Build Coastguard Worker 368*f4ee7fbaSAndroid Build Coastguard Worker #the routines that get switched between RangeDecoder and PrefixDecoder 369*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): return self.mode.__len__(self) 370*f4ee7fbaSAndroid Build Coastguard Worker def __iter__(self): return self.mode.__iter__(self) 371*f4ee7fbaSAndroid Build Coastguard Worker def __getitem__(self, index): return self.mode.__getitem__(self, index) 372*f4ee7fbaSAndroid Build Coastguard Worker def bitPattern(self, index): return self.mode.bitPattern(self, index) 373*f4ee7fbaSAndroid Build Coastguard Worker def length(self, index): return self.mode.length(self, index) 374*f4ee7fbaSAndroid Build Coastguard Worker def decodePeek(self, data): return self.mode.decodePeek(self, data) 375*f4ee7fbaSAndroid Build Coastguard Worker #general routines 376*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra=None): 377*f4ee7fbaSAndroid Build Coastguard Worker """Get value of symbol for computations. 378*f4ee7fbaSAndroid Build Coastguard Worker Override where needed. 379*f4ee7fbaSAndroid Build Coastguard Worker """ 380*f4ee7fbaSAndroid Build Coastguard Worker if extra is not None: 381*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: no extra for this symbol') 382*f4ee7fbaSAndroid Build Coastguard Worker return index 383*f4ee7fbaSAndroid Build Coastguard Worker 384*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 385*f4ee7fbaSAndroid Build Coastguard Worker """Give mnemonic of symbol. 386*f4ee7fbaSAndroid Build Coastguard Worker Override where needed. 387*f4ee7fbaSAndroid Build Coastguard Worker """ 388*f4ee7fbaSAndroid Build Coastguard Worker return str(self.value(index)) 389*f4ee7fbaSAndroid Build Coastguard Worker 390*f4ee7fbaSAndroid Build Coastguard Worker def callback(self, symbol): 391*f4ee7fbaSAndroid Build Coastguard Worker return self.explanation(symbol.index) 392*f4ee7fbaSAndroid Build Coastguard Worker 393*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 394*f4ee7fbaSAndroid Build Coastguard Worker """Long explanation of the value from the numeric value 395*f4ee7fbaSAndroid Build Coastguard Worker This is a default routine. 396*f4ee7fbaSAndroid Build Coastguard Worker You can customize in three ways: 397*f4ee7fbaSAndroid Build Coastguard Worker - set description to add some text 398*f4ee7fbaSAndroid Build Coastguard Worker - override to get more control 399*f4ee7fbaSAndroid Build Coastguard Worker - set callback to make it dependent on you local variables 400*f4ee7fbaSAndroid Build Coastguard Worker """ 401*f4ee7fbaSAndroid Build Coastguard Worker value = self.value(index) 402*f4ee7fbaSAndroid Build Coastguard Worker return '{0}{1}: {2}'.format( 403*f4ee7fbaSAndroid Build Coastguard Worker self.description and self.description+': ', 404*f4ee7fbaSAndroid Build Coastguard Worker self.bitPattern(index), 405*f4ee7fbaSAndroid Build Coastguard Worker value, 406*f4ee7fbaSAndroid Build Coastguard Worker ) 407*f4ee7fbaSAndroid Build Coastguard Worker 408*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 409*f4ee7fbaSAndroid Build Coastguard Worker return 0 410*f4ee7fbaSAndroid Build Coastguard Worker 411*f4ee7fbaSAndroid Build Coastguard Worker #Routines that use the decode interface 412*f4ee7fbaSAndroid Build Coastguard Worker def showCode(self, width=80): 413*f4ee7fbaSAndroid Build Coastguard Worker """Show all words of the code in a nice format. 414*f4ee7fbaSAndroid Build Coastguard Worker """ 415*f4ee7fbaSAndroid Build Coastguard Worker #make table of all symbols with binary strings 416*f4ee7fbaSAndroid Build Coastguard Worker symbolStrings = [ 417*f4ee7fbaSAndroid Build Coastguard Worker (self.bitPattern(s.index), self.mnemonic(s.index)) 418*f4ee7fbaSAndroid Build Coastguard Worker for s in self 419*f4ee7fbaSAndroid Build Coastguard Worker ] 420*f4ee7fbaSAndroid Build Coastguard Worker #determine column widths the way Lisp programmers do it 421*f4ee7fbaSAndroid Build Coastguard Worker leftColWidth, rightColWidth = map(max, map( 422*f4ee7fbaSAndroid Build Coastguard Worker map, 423*f4ee7fbaSAndroid Build Coastguard Worker repeat(len), 424*f4ee7fbaSAndroid Build Coastguard Worker zip(*symbolStrings) 425*f4ee7fbaSAndroid Build Coastguard Worker )) 426*f4ee7fbaSAndroid Build Coastguard Worker colwidth = leftColWidth+rightColWidth 427*f4ee7fbaSAndroid Build Coastguard Worker columns = 81//(colwidth+2) 428*f4ee7fbaSAndroid Build Coastguard Worker rows = -(-len(symbolStrings)//columns) 429*f4ee7fbaSAndroid Build Coastguard Worker def justify(bs): 430*f4ee7fbaSAndroid Build Coastguard Worker b,s = bs 431*f4ee7fbaSAndroid Build Coastguard Worker return b.rjust(leftColWidth)+':'+s.ljust(rightColWidth) 432*f4ee7fbaSAndroid Build Coastguard Worker for i in range(rows): 433*f4ee7fbaSAndroid Build Coastguard Worker print(' '.join(map(justify, symbolStrings[i::rows])).rstrip()) 434*f4ee7fbaSAndroid Build Coastguard Worker 435*f4ee7fbaSAndroid Build Coastguard Worker def readTuple(self, stream): 436*f4ee7fbaSAndroid Build Coastguard Worker """Read symbol from stream. Returns symbol, length. 437*f4ee7fbaSAndroid Build Coastguard Worker """ 438*f4ee7fbaSAndroid Build Coastguard Worker length, symbol = self.decodePeek(stream.peek(self.maxLength)) 439*f4ee7fbaSAndroid Build Coastguard Worker stream.pos += length 440*f4ee7fbaSAndroid Build Coastguard Worker return length, symbol 441*f4ee7fbaSAndroid Build Coastguard Worker 442*f4ee7fbaSAndroid Build Coastguard Worker def readTupleAndExtra(self, stream): 443*f4ee7fbaSAndroid Build Coastguard Worker return self.readTuple(stream)+(0, None) 444*f4ee7fbaSAndroid Build Coastguard Worker 445*f4ee7fbaSAndroid Build Coastguard Workerclass WithExtra(Code): 446*f4ee7fbaSAndroid Build Coastguard Worker """Extension for Code so that symbol may have extra bits associated. 447*f4ee7fbaSAndroid Build Coastguard Worker If you supply an extraTable, you can use extraBits 448*f4ee7fbaSAndroid Build Coastguard Worker You can define an extraTable, 449*f4ee7fbaSAndroid Build Coastguard Worker which allows to call extraBits to get the number of extraBits. 450*f4ee7fbaSAndroid Build Coastguard Worker Otherwise, you can supply extraBits yourself. 451*f4ee7fbaSAndroid Build Coastguard Worker Routine readTupleAndExtra now reads the extra bits too. 452*f4ee7fbaSAndroid Build Coastguard Worker Value probably needs to be overridden; see Enumerator. 453*f4ee7fbaSAndroid Build Coastguard Worker Note: this does not give you an decodeTable. 454*f4ee7fbaSAndroid Build Coastguard Worker """ 455*f4ee7fbaSAndroid Build Coastguard Worker #redefine these if you don't want to use an extraTable 456*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 457*f4ee7fbaSAndroid Build Coastguard Worker """Get the number of extra bits for this symbol. 458*f4ee7fbaSAndroid Build Coastguard Worker """ 459*f4ee7fbaSAndroid Build Coastguard Worker return self.extraTable[index] 460*f4ee7fbaSAndroid Build Coastguard Worker 461*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 462*f4ee7fbaSAndroid Build Coastguard Worker """This value must be independent of extra. 463*f4ee7fbaSAndroid Build Coastguard Worker """ 464*f4ee7fbaSAndroid Build Coastguard Worker return str(index) 465*f4ee7fbaSAndroid Build Coastguard Worker 466*f4ee7fbaSAndroid Build Coastguard Worker def readTupleAndExtra(self, stream): 467*f4ee7fbaSAndroid Build Coastguard Worker """Read symbol and extrabits from stream. 468*f4ee7fbaSAndroid Build Coastguard Worker Returns symbol length, symbol, extraBits, extra 469*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.pos = 6 470*f4ee7fbaSAndroid Build Coastguard Worker >>> MetablockLengthAlphabet().readTupleAndExtra(olleke) 471*f4ee7fbaSAndroid Build Coastguard Worker (2, Symbol(MLEN, 4), 16, 46) 472*f4ee7fbaSAndroid Build Coastguard Worker """ 473*f4ee7fbaSAndroid Build Coastguard Worker length, symbol = self.decodePeek(stream.peek(self.maxLength)) 474*f4ee7fbaSAndroid Build Coastguard Worker stream.pos += length 475*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(symbol.index) 476*f4ee7fbaSAndroid Build Coastguard Worker return length, symbol, extraBits, stream.read(extraBits) 477*f4ee7fbaSAndroid Build Coastguard Worker 478*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra=None): 479*f4ee7fbaSAndroid Build Coastguard Worker """Expanded version of Code.explanation supporting extra bits. 480*f4ee7fbaSAndroid Build Coastguard Worker If you don't supply extra, it is not mentioned. 481*f4ee7fbaSAndroid Build Coastguard Worker """ 482*f4ee7fbaSAndroid Build Coastguard Worker extraBits = 0 if extra is None else self.extraBits(index) 483*f4ee7fbaSAndroid Build Coastguard Worker if not hasattr(self, 'extraTable'): 484*f4ee7fbaSAndroid Build Coastguard Worker formatString = '{0}{3}' 485*f4ee7fbaSAndroid Build Coastguard Worker lo = hi = value = self.value(index, extra) 486*f4ee7fbaSAndroid Build Coastguard Worker elif extraBits==0: 487*f4ee7fbaSAndroid Build Coastguard Worker formatString = '{0}{2}: {3}' 488*f4ee7fbaSAndroid Build Coastguard Worker lo, hi = self.span(index) 489*f4ee7fbaSAndroid Build Coastguard Worker value = lo 490*f4ee7fbaSAndroid Build Coastguard Worker else: 491*f4ee7fbaSAndroid Build Coastguard Worker formatString = '{0}{1} {2}: {3}-{4}; {3}+{5}={6}' 492*f4ee7fbaSAndroid Build Coastguard Worker lo, hi = self.span(index) 493*f4ee7fbaSAndroid Build Coastguard Worker value = lo+extra 494*f4ee7fbaSAndroid Build Coastguard Worker return formatString.format( 495*f4ee7fbaSAndroid Build Coastguard Worker self.description and self.description+': ', 496*f4ee7fbaSAndroid Build Coastguard Worker 'x'*extraBits, 497*f4ee7fbaSAndroid Build Coastguard Worker self.bitPattern(index), 498*f4ee7fbaSAndroid Build Coastguard Worker lo, hi, 499*f4ee7fbaSAndroid Build Coastguard Worker extra, 500*f4ee7fbaSAndroid Build Coastguard Worker value, 501*f4ee7fbaSAndroid Build Coastguard Worker ) 502*f4ee7fbaSAndroid Build Coastguard Worker 503*f4ee7fbaSAndroid Build Coastguard Worker def callback(self, symbol, extra): 504*f4ee7fbaSAndroid Build Coastguard Worker return self.explanation(symbol.index, extra) 505*f4ee7fbaSAndroid Build Coastguard Worker 506*f4ee7fbaSAndroid Build Coastguard Workerclass BoolCode(Code): 507*f4ee7fbaSAndroid Build Coastguard Worker """Same as Code(bitLength=1), but shows a boolean. 508*f4ee7fbaSAndroid Build Coastguard Worker """ 509*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, **args): 510*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, bitLength=1, **args) 511*f4ee7fbaSAndroid Build Coastguard Worker 512*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra=None): 513*f4ee7fbaSAndroid Build Coastguard Worker return bool(super().value(index, extra)) 514*f4ee7fbaSAndroid Build Coastguard Worker 515*f4ee7fbaSAndroid Build Coastguard Workerclass Enumerator(WithExtra): 516*f4ee7fbaSAndroid Build Coastguard Worker """Code that is defined by the ExtraTable. 517*f4ee7fbaSAndroid Build Coastguard Worker extraTable is a class variable that contains 518*f4ee7fbaSAndroid Build Coastguard Worker the extraBits of the symbols from 0 519*f4ee7fbaSAndroid Build Coastguard Worker value0 contains the value of symbol 0 520*f4ee7fbaSAndroid Build Coastguard Worker encodings is not neccessary, but allowed. 521*f4ee7fbaSAndroid Build Coastguard Worker Note: place for FixedCode to make sure extraBits works 522*f4ee7fbaSAndroid Build Coastguard Worker """ 523*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, **args): 524*f4ee7fbaSAndroid Build Coastguard Worker #if there is no decodeTable to determine length, compute it ourselves 525*f4ee7fbaSAndroid Build Coastguard Worker if 'decodeTable' not in args: 526*f4ee7fbaSAndroid Build Coastguard Worker args['alphabetSize'] = len(self.extraTable) 527*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, **args) 528*f4ee7fbaSAndroid Build Coastguard Worker 529*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): 530*f4ee7fbaSAndroid Build Coastguard Worker return len(self.extraTable) 531*f4ee7fbaSAndroid Build Coastguard Worker 532*f4ee7fbaSAndroid Build Coastguard Worker def __getitem__(self, index): 533*f4ee7fbaSAndroid Build Coastguard Worker """Faster than PrefixDecoder 534*f4ee7fbaSAndroid Build Coastguard Worker """ 535*f4ee7fbaSAndroid Build Coastguard Worker if index>=len(self.extraTable): 536*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError("No symbol {}[{}]".format( 537*f4ee7fbaSAndroid Build Coastguard Worker self.__class__.__name__, index)) 538*f4ee7fbaSAndroid Build Coastguard Worker return Symbol(self, index) 539*f4ee7fbaSAndroid Build Coastguard Worker 540*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 541*f4ee7fbaSAndroid Build Coastguard Worker """Override if you don't define value0 and extraTable 542*f4ee7fbaSAndroid Build Coastguard Worker """ 543*f4ee7fbaSAndroid Build Coastguard Worker lower, upper = self.span(index) 544*f4ee7fbaSAndroid Build Coastguard Worker value = lower+(extra or 0) 545*f4ee7fbaSAndroid Build Coastguard Worker if value>upper: 546*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 547*f4ee7fbaSAndroid Build Coastguard Worker return value 548*f4ee7fbaSAndroid Build Coastguard Worker 549*f4ee7fbaSAndroid Build Coastguard Worker def span(self, index): 550*f4ee7fbaSAndroid Build Coastguard Worker """Give the range of possible values in a tuple 551*f4ee7fbaSAndroid Build Coastguard Worker Useful for mnemonic and explanation 552*f4ee7fbaSAndroid Build Coastguard Worker """ 553*f4ee7fbaSAndroid Build Coastguard Worker lower = self.value0+sum(1<<x for x in self.extraTable[:index]) 554*f4ee7fbaSAndroid Build Coastguard Worker upper = lower+(1<<self.extraTable[index]) 555*f4ee7fbaSAndroid Build Coastguard Worker return lower, upper-1 556*f4ee7fbaSAndroid Build Coastguard Worker 557*f4ee7fbaSAndroid Build Coastguard Worker#======================Code subclasses====================================== 558*f4ee7fbaSAndroid Build Coastguard Worker#Alphabets used in the metablock header---------------------------------- 559*f4ee7fbaSAndroid Build Coastguard Worker#For prefix codes 560*f4ee7fbaSAndroid Build Coastguard Workerclass PrefixCodeHeader(WithExtra): 561*f4ee7fbaSAndroid Build Coastguard Worker """Header of prefix codes. 562*f4ee7fbaSAndroid Build Coastguard Worker """ 563*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, codename): 564*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('PFX', bitLength=2) 565*f4ee7fbaSAndroid Build Coastguard Worker #this is the name of the code that it describes 566*f4ee7fbaSAndroid Build Coastguard Worker self.codename = codename 567*f4ee7fbaSAndroid Build Coastguard Worker 568*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 569*f4ee7fbaSAndroid Build Coastguard Worker return 2 if index==1 else 0 570*f4ee7fbaSAndroid Build Coastguard Worker 571*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 572*f4ee7fbaSAndroid Build Coastguard Worker """Returns ('Simple', #codewords) or ('Complex', HSKIP) 573*f4ee7fbaSAndroid Build Coastguard Worker """ 574*f4ee7fbaSAndroid Build Coastguard Worker if index==1: 575*f4ee7fbaSAndroid Build Coastguard Worker if extra>3: 576*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 577*f4ee7fbaSAndroid Build Coastguard Worker return 'Simple', extra+1 578*f4ee7fbaSAndroid Build Coastguard Worker if extra: 579*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 580*f4ee7fbaSAndroid Build Coastguard Worker return 'Complex', index 581*f4ee7fbaSAndroid Build Coastguard Worker 582*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 583*f4ee7fbaSAndroid Build Coastguard Worker if index==1: 584*f4ee7fbaSAndroid Build Coastguard Worker return '{} is simple with {} code word{}'.format( 585*f4ee7fbaSAndroid Build Coastguard Worker self.codename, extra+1, 's' if extra else '') 586*f4ee7fbaSAndroid Build Coastguard Worker lengths = [1, 2, 3, 4, 0, 5, 17, 6] 587*f4ee7fbaSAndroid Build Coastguard Worker return '{} is complex with lengths {}...'.format( 588*f4ee7fbaSAndroid Build Coastguard Worker self.codename, 589*f4ee7fbaSAndroid Build Coastguard Worker ','.join( 590*f4ee7fbaSAndroid Build Coastguard Worker map(str, lengths[index:index+5])) 591*f4ee7fbaSAndroid Build Coastguard Worker ) 592*f4ee7fbaSAndroid Build Coastguard Worker 593*f4ee7fbaSAndroid Build Coastguard Workerclass TreeShapeAlhabet(BoolCode): 594*f4ee7fbaSAndroid Build Coastguard Worker """The bit used to indicate if four word code is "deep" or "wide" 595*f4ee7fbaSAndroid Build Coastguard Worker """ 596*f4ee7fbaSAndroid Build Coastguard Worker name = 'SHAPE' 597*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index): 598*f4ee7fbaSAndroid Build Coastguard Worker return [(2,2,2,2), (1,2,3,3)][index] 599*f4ee7fbaSAndroid Build Coastguard Worker 600*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 601*f4ee7fbaSAndroid Build Coastguard Worker return str(bool(index))+': lengths {},{},{},{}'.format(*self.value(index)) 602*f4ee7fbaSAndroid Build Coastguard Worker 603*f4ee7fbaSAndroid Build Coastguard Workerclass LengthOfLengthAlphabet(Code): 604*f4ee7fbaSAndroid Build Coastguard Worker """For use in decoding complex code descriptors. 605*f4ee7fbaSAndroid Build Coastguard Worker >>> lengthOfLengthAlphabet = LengthOfLengthAlphabet('') 606*f4ee7fbaSAndroid Build Coastguard Worker >>> print(lengthOfLengthAlphabet[2]) 607*f4ee7fbaSAndroid Build Coastguard Worker coded with 2 bits 608*f4ee7fbaSAndroid Build Coastguard Worker >>> len(lengthOfLengthAlphabet[0]) 609*f4ee7fbaSAndroid Build Coastguard Worker 2 610*f4ee7fbaSAndroid Build Coastguard Worker >>> [len(lengthOfLengthAlphabet[x]) for x in range(6)] 611*f4ee7fbaSAndroid Build Coastguard Worker [2, 4, 3, 2, 2, 4] 612*f4ee7fbaSAndroid Build Coastguard Worker >>> lengthOfLengthAlphabet.showCode() 613*f4ee7fbaSAndroid Build Coastguard Worker 00:skipped 01:coded with 4 bits 0111:coded with 1 bits 614*f4ee7fbaSAndroid Build Coastguard Worker 10:coded with 3 bits 011:coded with 2 bits 1111:coded with 5 bits 615*f4ee7fbaSAndroid Build Coastguard Worker """ 616*f4ee7fbaSAndroid Build Coastguard Worker decodeTable = { 617*f4ee7fbaSAndroid Build Coastguard Worker 0b00:0, 0b10:3, 618*f4ee7fbaSAndroid Build Coastguard Worker 0b0111:1, 0b01:4, 619*f4ee7fbaSAndroid Build Coastguard Worker 0b011:2, 0b1111:5, 620*f4ee7fbaSAndroid Build Coastguard Worker } 621*f4ee7fbaSAndroid Build Coastguard Worker 622*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, **args): 623*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, decodeTable=self.decodeTable, **args) 624*f4ee7fbaSAndroid Build Coastguard Worker 625*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 626*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'skipped' 627*f4ee7fbaSAndroid Build Coastguard Worker return 'coded with {} bits'.format(index) 628*f4ee7fbaSAndroid Build Coastguard Worker 629*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra=None): 630*f4ee7fbaSAndroid Build Coastguard Worker return self.description+': '+self.mnemonic(index) 631*f4ee7fbaSAndroid Build Coastguard Worker 632*f4ee7fbaSAndroid Build Coastguard Workerclass LengthAlphabet(WithExtra): 633*f4ee7fbaSAndroid Build Coastguard Worker """Length of symbols 634*f4ee7fbaSAndroid Build Coastguard Worker Used during construction of a code. 635*f4ee7fbaSAndroid Build Coastguard Worker """ 636*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name): 637*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, alphabetSize=18) 638*f4ee7fbaSAndroid Build Coastguard Worker 639*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 640*f4ee7fbaSAndroid Build Coastguard Worker return {16:2, 17:3}.get(index, 0) 641*f4ee7fbaSAndroid Build Coastguard Worker 642*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 643*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'unused' 644*f4ee7fbaSAndroid Build Coastguard Worker elif index==16: return 'rep xx' 645*f4ee7fbaSAndroid Build Coastguard Worker elif index==17: return 'zero xxx' 646*f4ee7fbaSAndroid Build Coastguard Worker else: return 'len {}'.format(index) 647*f4ee7fbaSAndroid Build Coastguard Worker 648*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 649*f4ee7fbaSAndroid Build Coastguard Worker return self.description.format(self[index], extra) 650*f4ee7fbaSAndroid Build Coastguard Worker 651*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 652*f4ee7fbaSAndroid Build Coastguard Worker #the caller got the length already, so extra is enough 653*f4ee7fbaSAndroid Build Coastguard Worker return extra 654*f4ee7fbaSAndroid Build Coastguard Worker 655*f4ee7fbaSAndroid Build Coastguard Worker#Stream header 656*f4ee7fbaSAndroid Build Coastguard Workerclass WindowSizeAlphabet(Code): 657*f4ee7fbaSAndroid Build Coastguard Worker """The alphabet used for window size in the stream header. 658*f4ee7fbaSAndroid Build Coastguard Worker >>> WindowSizeAlphabet()[10].explanation() 659*f4ee7fbaSAndroid Build Coastguard Worker 'windowsize=(1<<10)-16=1008' 660*f4ee7fbaSAndroid Build Coastguard Worker """ 661*f4ee7fbaSAndroid Build Coastguard Worker decodeTable = { 662*f4ee7fbaSAndroid Build Coastguard Worker 0b0100001: 10, 0b1100001: 14, 0b0011: 18, 0b1011: 22, 663*f4ee7fbaSAndroid Build Coastguard Worker 0b0110001: 11, 0b1110001: 15, 0b0101: 19, 0b1101: 23, 664*f4ee7fbaSAndroid Build Coastguard Worker 0b1000001: 12, 0b0: 16, 0b0111: 20, 0b1111: 24, 665*f4ee7fbaSAndroid Build Coastguard Worker 0b1010001: 13, 0b0000001: 17, 0b1001: 21, 666*f4ee7fbaSAndroid Build Coastguard Worker 0b0010001: None, 667*f4ee7fbaSAndroid Build Coastguard Worker } 668*f4ee7fbaSAndroid Build Coastguard Worker 669*f4ee7fbaSAndroid Build Coastguard Worker name = 'WSIZE' 670*f4ee7fbaSAndroid Build Coastguard Worker 671*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None): 672*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, decodeTable=self.decodeTable) 673*f4ee7fbaSAndroid Build Coastguard Worker 674*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index): 675*f4ee7fbaSAndroid Build Coastguard Worker #missing value gives index None 676*f4ee7fbaSAndroid Build Coastguard Worker if index is None: return None 677*f4ee7fbaSAndroid Build Coastguard Worker return (1<<index)-16 678*f4ee7fbaSAndroid Build Coastguard Worker 679*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 680*f4ee7fbaSAndroid Build Coastguard Worker return 'windowsize=(1<<{})-16={}'.format( 681*f4ee7fbaSAndroid Build Coastguard Worker index, (1<<index)-16) 682*f4ee7fbaSAndroid Build Coastguard Worker 683*f4ee7fbaSAndroid Build Coastguard Worker#Metablock 684*f4ee7fbaSAndroid Build Coastguard Workerclass MetablockLengthAlphabet(WithExtra): 685*f4ee7fbaSAndroid Build Coastguard Worker """Used for the meta block length; 686*f4ee7fbaSAndroid Build Coastguard Worker also indicates a block with no data 687*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet = MetablockLengthAlphabet() 688*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet[0]; str(metablockLengthAlphabet[0]) 689*f4ee7fbaSAndroid Build Coastguard Worker Symbol(MLEN, 0) 690*f4ee7fbaSAndroid Build Coastguard Worker 'empty' 691*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet[3] 692*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 693*f4ee7fbaSAndroid Build Coastguard Worker ... 694*f4ee7fbaSAndroid Build Coastguard Worker ValueError: No symbol MetablockLengthAlphabet[3] 695*f4ee7fbaSAndroid Build Coastguard Worker >>> print(metablockLengthAlphabet[4]) 696*f4ee7fbaSAndroid Build Coastguard Worker hhhh00 697*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet[4].value(0x1000) 698*f4ee7fbaSAndroid Build Coastguard Worker 4097 699*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet[5].value(0x1000) 700*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 701*f4ee7fbaSAndroid Build Coastguard Worker ... 702*f4ee7fbaSAndroid Build Coastguard Worker InvalidStream: Zeros in high nibble of MLEN 703*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet[5].explanation(0x12345) 704*f4ee7fbaSAndroid Build Coastguard Worker 'data length: 12345h+1=74566' 705*f4ee7fbaSAndroid Build Coastguard Worker >>> metablockLengthAlphabet.showCode() 706*f4ee7fbaSAndroid Build Coastguard Worker 00:hhhh00 10:hhhhhh10 01:hhhhh01 11:empty 707*f4ee7fbaSAndroid Build Coastguard Worker """ 708*f4ee7fbaSAndroid Build Coastguard Worker decodeTable = {0b11:0, 0b00:4, 0b01:5, 0b10:6} 709*f4ee7fbaSAndroid Build Coastguard Worker 710*f4ee7fbaSAndroid Build Coastguard Worker name = 'MLEN' 711*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None): 712*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, decodeTable=self.decodeTable) 713*f4ee7fbaSAndroid Build Coastguard Worker 714*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 715*f4ee7fbaSAndroid Build Coastguard Worker return index*4 716*f4ee7fbaSAndroid Build Coastguard Worker 717*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 718*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'empty' 719*f4ee7fbaSAndroid Build Coastguard Worker return 'h'*(self.extraBits(index)//4)+self.bitPattern(index) 720*f4ee7fbaSAndroid Build Coastguard Worker 721*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 722*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 723*f4ee7fbaSAndroid Build Coastguard Worker if not 0<=extra<1<<extraBits: 724*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 725*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 0 726*f4ee7fbaSAndroid Build Coastguard Worker if index>4 and extra>>extraBits-4==0: raise InvalidStream( 727*f4ee7fbaSAndroid Build Coastguard Worker 'Zeros in high nibble of MLEN') 728*f4ee7fbaSAndroid Build Coastguard Worker return extra+1 729*f4ee7fbaSAndroid Build Coastguard Worker 730*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 731*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return '11: empty block' 732*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 733*f4ee7fbaSAndroid Build Coastguard Worker return 'data length: {:0{}x}h+1={}'.format(extra, extraBits//4, extra+1) 734*f4ee7fbaSAndroid Build Coastguard Worker 735*f4ee7fbaSAndroid Build Coastguard Worker 736*f4ee7fbaSAndroid Build Coastguard Workerclass ReservedAlphabet(BoolCode): 737*f4ee7fbaSAndroid Build Coastguard Worker """The reserved bit that must be zero. 738*f4ee7fbaSAndroid Build Coastguard Worker """ 739*f4ee7fbaSAndroid Build Coastguard Worker name = 'RSVD' 740*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index): 741*f4ee7fbaSAndroid Build Coastguard Worker if index: raise ValueError('Reserved bit is not zero') 742*f4ee7fbaSAndroid Build Coastguard Worker 743*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 744*f4ee7fbaSAndroid Build Coastguard Worker return 'Reserved (must be zero)' 745*f4ee7fbaSAndroid Build Coastguard Worker 746*f4ee7fbaSAndroid Build Coastguard Workerclass FillerAlphabet(Code): 747*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, *, streamPos): 748*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('SKIP', bitLength=(-streamPos)&7) 749*f4ee7fbaSAndroid Build Coastguard Worker 750*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 751*f4ee7fbaSAndroid Build Coastguard Worker return '{} bit{} ignored'.format( 752*f4ee7fbaSAndroid Build Coastguard Worker self.length(index), 753*f4ee7fbaSAndroid Build Coastguard Worker '' if self.length(index)==1 else 's', 754*f4ee7fbaSAndroid Build Coastguard Worker ) 755*f4ee7fbaSAndroid Build Coastguard Worker 756*f4ee7fbaSAndroid Build Coastguard Workerclass SkipLengthAlphabet(WithExtra): 757*f4ee7fbaSAndroid Build Coastguard Worker """Used for the skip length in an empty metablock 758*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet = SkipLengthAlphabet() 759*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet[0]; str(skipLengthAlphabet[0]) 760*f4ee7fbaSAndroid Build Coastguard Worker Symbol(SKIP, 0) 761*f4ee7fbaSAndroid Build Coastguard Worker 'empty' 762*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet[4] 763*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 764*f4ee7fbaSAndroid Build Coastguard Worker ... 765*f4ee7fbaSAndroid Build Coastguard Worker ValueError: index out of range 766*f4ee7fbaSAndroid Build Coastguard Worker >>> print(skipLengthAlphabet[3]) 767*f4ee7fbaSAndroid Build Coastguard Worker hhhhhh11 768*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet[2].value(0x1000) 769*f4ee7fbaSAndroid Build Coastguard Worker 4097 770*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet[3].value(0x1000) 771*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 772*f4ee7fbaSAndroid Build Coastguard Worker ... 773*f4ee7fbaSAndroid Build Coastguard Worker InvalidStream: Zeros in high byte of SKIPBYTES 774*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet[3].explanation(0x12345) 775*f4ee7fbaSAndroid Build Coastguard Worker 'skip length: 12345h+1=74566' 776*f4ee7fbaSAndroid Build Coastguard Worker >>> skipLengthAlphabet.showCode() 777*f4ee7fbaSAndroid Build Coastguard Worker 00:empty 01:hh01 10:hhhh10 11:hhhhhh11 778*f4ee7fbaSAndroid Build Coastguard Worker """ 779*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self): 780*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('SKIP', bitLength=2) 781*f4ee7fbaSAndroid Build Coastguard Worker 782*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 783*f4ee7fbaSAndroid Build Coastguard Worker return index*8 784*f4ee7fbaSAndroid Build Coastguard Worker 785*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 786*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'empty' 787*f4ee7fbaSAndroid Build Coastguard Worker return 'h'*(self.extraBits(index)//4)+self.bitPattern(index) 788*f4ee7fbaSAndroid Build Coastguard Worker 789*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 790*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 791*f4ee7fbaSAndroid Build Coastguard Worker if not 0<=extra<1<<extraBits: 792*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 793*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 0 794*f4ee7fbaSAndroid Build Coastguard Worker if index>1 and extra>>extraBits-8==0: 795*f4ee7fbaSAndroid Build Coastguard Worker raise InvalidStream('Zeros in high byte of SKIPBYTES') 796*f4ee7fbaSAndroid Build Coastguard Worker return extra+1 797*f4ee7fbaSAndroid Build Coastguard Worker 798*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 799*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return '00: no skip' 800*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 801*f4ee7fbaSAndroid Build Coastguard Worker return 'skip length: {:{}x}h+1={}'.format(extra, extraBits//8, extra+1) 802*f4ee7fbaSAndroid Build Coastguard Worker 803*f4ee7fbaSAndroid Build Coastguard Worker 804*f4ee7fbaSAndroid Build Coastguard Workerclass TypeCountAlphabet(Enumerator): 805*f4ee7fbaSAndroid Build Coastguard Worker """Used for giving block type counts and tree counts. 806*f4ee7fbaSAndroid Build Coastguard Worker >>> TypeCountAlphabet(description='').showCode() 807*f4ee7fbaSAndroid Build Coastguard Worker 0:0 0101:xx,0101 1011:xxxxx,1011 808*f4ee7fbaSAndroid Build Coastguard Worker 0001:0001 1101:xxxxxx,1101 0111:xxx,0111 809*f4ee7fbaSAndroid Build Coastguard Worker 1001:xxxx,1001 0011:x,0011 1111:xxxxxxx,1111 810*f4ee7fbaSAndroid Build Coastguard Worker """ 811*f4ee7fbaSAndroid Build Coastguard Worker decodeTable = { 812*f4ee7fbaSAndroid Build Coastguard Worker 0b0: 0, 0b1001: 5, 813*f4ee7fbaSAndroid Build Coastguard Worker 0b0001: 1, 0b1011: 6, 814*f4ee7fbaSAndroid Build Coastguard Worker 0b0011: 2, 0b1101: 7, 815*f4ee7fbaSAndroid Build Coastguard Worker 0b0101: 3, 0b1111: 8, 816*f4ee7fbaSAndroid Build Coastguard Worker 0b0111: 4, 817*f4ee7fbaSAndroid Build Coastguard Worker } 818*f4ee7fbaSAndroid Build Coastguard Worker 819*f4ee7fbaSAndroid Build Coastguard Worker value0 = 1 820*f4ee7fbaSAndroid Build Coastguard Worker extraTable = [0, 0, 1, 2, 3, 4, 5, 6, 7] 821*f4ee7fbaSAndroid Build Coastguard Worker name = 'BT#' 822*f4ee7fbaSAndroid Build Coastguard Worker 823*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, *, description): 824*f4ee7fbaSAndroid Build Coastguard Worker super().__init__( 825*f4ee7fbaSAndroid Build Coastguard Worker name, 826*f4ee7fbaSAndroid Build Coastguard Worker decodeTable=self.decodeTable, 827*f4ee7fbaSAndroid Build Coastguard Worker description=description) 828*f4ee7fbaSAndroid Build Coastguard Worker 829*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 830*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return '0' 831*f4ee7fbaSAndroid Build Coastguard Worker if index==1: return '0001' 832*f4ee7fbaSAndroid Build Coastguard Worker return 'x'*(self.extraBits(index))+','+self.bitPattern(index) 833*f4ee7fbaSAndroid Build Coastguard Worker 834*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 835*f4ee7fbaSAndroid Build Coastguard Worker value = self.value(index, extra) 836*f4ee7fbaSAndroid Build Coastguard Worker description = self.description 837*f4ee7fbaSAndroid Build Coastguard Worker if value==1: description = description[:-1] 838*f4ee7fbaSAndroid Build Coastguard Worker return '{}: {} {}'.format( 839*f4ee7fbaSAndroid Build Coastguard Worker self.mnemonic(index), 840*f4ee7fbaSAndroid Build Coastguard Worker value, 841*f4ee7fbaSAndroid Build Coastguard Worker description) 842*f4ee7fbaSAndroid Build Coastguard Worker 843*f4ee7fbaSAndroid Build Coastguard Workerclass BlockTypeAlphabet(Code): 844*f4ee7fbaSAndroid Build Coastguard Worker """The block types; this code works for all three kinds. 845*f4ee7fbaSAndroid Build Coastguard Worker >>> b = BlockTypeAlphabet('T', NBLTYPES=5) 846*f4ee7fbaSAndroid Build Coastguard Worker >>> print(*(x for x in b)) 847*f4ee7fbaSAndroid Build Coastguard Worker prev +1 #0 #1 #2 #3 #4 848*f4ee7fbaSAndroid Build Coastguard Worker """ 849*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name, NBLTYPES, **args): 850*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, alphabetSize=NBLTYPES+2, **args) 851*f4ee7fbaSAndroid Build Coastguard Worker self.NBLTYPES = NBLTYPES 852*f4ee7fbaSAndroid Build Coastguard Worker 853*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 854*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'prev' 855*f4ee7fbaSAndroid Build Coastguard Worker elif index==1: return '+1' 856*f4ee7fbaSAndroid Build Coastguard Worker else: return '#'+str(index-2) 857*f4ee7fbaSAndroid Build Coastguard Worker 858*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index): 859*f4ee7fbaSAndroid Build Coastguard Worker return index-2 860*f4ee7fbaSAndroid Build Coastguard Worker 861*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 862*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return '0: previous' 863*f4ee7fbaSAndroid Build Coastguard Worker elif index==1: return '1: increment' 864*f4ee7fbaSAndroid Build Coastguard Worker else: return 'Set block type to: '+str(index-2) 865*f4ee7fbaSAndroid Build Coastguard Worker 866*f4ee7fbaSAndroid Build Coastguard Workerclass BlockCountAlphabet(Enumerator): 867*f4ee7fbaSAndroid Build Coastguard Worker """Block counts 868*f4ee7fbaSAndroid Build Coastguard Worker >>> b = BlockCountAlphabet('L') 869*f4ee7fbaSAndroid Build Coastguard Worker >>> print(b[25]) 870*f4ee7fbaSAndroid Build Coastguard Worker [24*x]: BC16625-16793840 871*f4ee7fbaSAndroid Build Coastguard Worker """ 872*f4ee7fbaSAndroid Build Coastguard Worker 873*f4ee7fbaSAndroid Build Coastguard Worker value0 = 1 874*f4ee7fbaSAndroid Build Coastguard Worker extraTable = [2,2,2,2,3, 3,3,3,4,4, 4,4,5,5,5, 5,6,6,7,8, 9,10,11,12,13, 24] 875*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name, **args): 876*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, alphabetSize=26, **args) 877*f4ee7fbaSAndroid Build Coastguard Worker 878*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 879*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 880*f4ee7fbaSAndroid Build Coastguard Worker return '{}: BC{}-{}'.format( 881*f4ee7fbaSAndroid Build Coastguard Worker 'x'*extraBits if index<5 else '[{}*x]'.format(extraBits), 882*f4ee7fbaSAndroid Build Coastguard Worker *self.span(index)) 883*f4ee7fbaSAndroid Build Coastguard Worker 884*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 885*f4ee7fbaSAndroid Build Coastguard Worker return 'Block count: '+super().explanation(index, extra) 886*f4ee7fbaSAndroid Build Coastguard Worker 887*f4ee7fbaSAndroid Build Coastguard Workerclass DistanceParamAlphabet(WithExtra): 888*f4ee7fbaSAndroid Build Coastguard Worker """The distance parameters NPOSTFIX and NDIRECT. 889*f4ee7fbaSAndroid Build Coastguard Worker Although these are treated as two in the description, this is easier. 890*f4ee7fbaSAndroid Build Coastguard Worker """ 891*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self): 892*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('DIST', bitLength=2) 893*f4ee7fbaSAndroid Build Coastguard Worker 894*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 895*f4ee7fbaSAndroid Build Coastguard Worker return 4 896*f4ee7fbaSAndroid Build Coastguard Worker 897*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 898*f4ee7fbaSAndroid Build Coastguard Worker """Returns NPOSTFIX and NDIRECT<<NPOSTFIX 899*f4ee7fbaSAndroid Build Coastguard Worker """ 900*f4ee7fbaSAndroid Build Coastguard Worker if extra>15: 901*f4ee7fbaSAndroid Build Coastguard Worker raise ValueError('value: extra out of range') 902*f4ee7fbaSAndroid Build Coastguard Worker return index, extra<<index 903*f4ee7fbaSAndroid Build Coastguard Worker 904*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 905*f4ee7fbaSAndroid Build Coastguard Worker return '{} postfix bits and {:04b}<<{}={} direct codes'.format( 906*f4ee7fbaSAndroid Build Coastguard Worker index, extra, index, extra<<index) 907*f4ee7fbaSAndroid Build Coastguard Worker 908*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 909*f4ee7fbaSAndroid Build Coastguard Worker return 'PF'+str(index) 910*f4ee7fbaSAndroid Build Coastguard Worker 911*f4ee7fbaSAndroid Build Coastguard Workerclass LiteralContextMode(Code): 912*f4ee7fbaSAndroid Build Coastguard Worker """For the literal context modes. 913*f4ee7fbaSAndroid Build Coastguard Worker >>> LiteralContextMode().showCode() 914*f4ee7fbaSAndroid Build Coastguard Worker 00:LSB6 01:MSB6 10:UTF8 11:Signed 915*f4ee7fbaSAndroid Build Coastguard Worker >>> LiteralContextMode().explanation(2) 916*f4ee7fbaSAndroid Build Coastguard Worker 'Context mode for type 9: 2(UTF8)' 917*f4ee7fbaSAndroid Build Coastguard Worker """ 918*f4ee7fbaSAndroid Build Coastguard Worker 919*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, *, number=9): 920*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('LC'+str(number), bitLength=2) 921*f4ee7fbaSAndroid Build Coastguard Worker self.number = number 922*f4ee7fbaSAndroid Build Coastguard Worker 923*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 924*f4ee7fbaSAndroid Build Coastguard Worker return ['LSB6', 'MSB6', 'UTF8', 'Signed'][index] 925*f4ee7fbaSAndroid Build Coastguard Worker 926*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index): 927*f4ee7fbaSAndroid Build Coastguard Worker return 'Context mode for type {}: {}({})'.format( 928*f4ee7fbaSAndroid Build Coastguard Worker self.number, 929*f4ee7fbaSAndroid Build Coastguard Worker index, 930*f4ee7fbaSAndroid Build Coastguard Worker self.mnemonic(index)) 931*f4ee7fbaSAndroid Build Coastguard Worker 932*f4ee7fbaSAndroid Build Coastguard Workerclass RLEmaxAlphabet(Enumerator): 933*f4ee7fbaSAndroid Build Coastguard Worker """Used for describing the run length encoding used for describing context maps. 934*f4ee7fbaSAndroid Build Coastguard Worker >>> RLEmaxAlphabet().showCode() 935*f4ee7fbaSAndroid Build Coastguard Worker 0:1 1:more 936*f4ee7fbaSAndroid Build Coastguard Worker """ 937*f4ee7fbaSAndroid Build Coastguard Worker value0 = 0 938*f4ee7fbaSAndroid Build Coastguard Worker extraTable = [0, 4] 939*f4ee7fbaSAndroid Build Coastguard Worker name = 'RLE#' 940*f4ee7fbaSAndroid Build Coastguard Worker 941*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 942*f4ee7fbaSAndroid Build Coastguard Worker return ['1', 'more'][index] 943*f4ee7fbaSAndroid Build Coastguard Worker 944*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 945*f4ee7fbaSAndroid Build Coastguard Worker description = self.description and self.description+': ' 946*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return description+'No RLE coding' 947*f4ee7fbaSAndroid Build Coastguard Worker return '{}xxxx 1: RLEMAX={}'.format(description, extra+1) 948*f4ee7fbaSAndroid Build Coastguard Worker 949*f4ee7fbaSAndroid Build Coastguard Workerclass TreeAlphabet(WithExtra): 950*f4ee7fbaSAndroid Build Coastguard Worker """The alphabet to enumerate entries (called trees) in the context map. 951*f4ee7fbaSAndroid Build Coastguard Worker parameters are RLEMAX and NTREES 952*f4ee7fbaSAndroid Build Coastguard Worker >>> t = TreeAlphabet('', RLEMAX=3, NTREES=5) 953*f4ee7fbaSAndroid Build Coastguard Worker >>> len(t) 954*f4ee7fbaSAndroid Build Coastguard Worker 8 955*f4ee7fbaSAndroid Build Coastguard Worker >>> print(t[2]) 956*f4ee7fbaSAndroid Build Coastguard Worker xx+4 zeroes 957*f4ee7fbaSAndroid Build Coastguard Worker >>> t[3].explanation(2) 958*f4ee7fbaSAndroid Build Coastguard Worker '8+010=10 zeroes' 959*f4ee7fbaSAndroid Build Coastguard Worker >>> t[0].value(0) 960*f4ee7fbaSAndroid Build Coastguard Worker (1, 0) 961*f4ee7fbaSAndroid Build Coastguard Worker """ 962*f4ee7fbaSAndroid Build Coastguard Worker name = 'CMI' 963*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, name=None, *, RLEMAX, NTREES, **args): 964*f4ee7fbaSAndroid Build Coastguard Worker super().__init__(name, alphabetSize=RLEMAX+NTREES, **args) 965*f4ee7fbaSAndroid Build Coastguard Worker self.RLEMAX = RLEMAX 966*f4ee7fbaSAndroid Build Coastguard Worker self.NTREES = NTREES 967*f4ee7fbaSAndroid Build Coastguard Worker 968*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 969*f4ee7fbaSAndroid Build Coastguard Worker if 0<index<=self.RLEMAX: return index 970*f4ee7fbaSAndroid Build Coastguard Worker return 0 971*f4ee7fbaSAndroid Build Coastguard Worker 972*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 973*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 'map #0' 974*f4ee7fbaSAndroid Build Coastguard Worker if index<=self.RLEMAX: 975*f4ee7fbaSAndroid Build Coastguard Worker return '{}+{} zeroes'.format('x'*index, 1<<index) 976*f4ee7fbaSAndroid Build Coastguard Worker return 'map #{}'.format(index-self.RLEMAX) 977*f4ee7fbaSAndroid Build Coastguard Worker 978*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 979*f4ee7fbaSAndroid Build Coastguard Worker """Give count and value.""" 980*f4ee7fbaSAndroid Build Coastguard Worker index = index 981*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return 1, 0 982*f4ee7fbaSAndroid Build Coastguard Worker if index<=self.RLEMAX: return (1<<index)+extra, 0 983*f4ee7fbaSAndroid Build Coastguard Worker return 1, index-self.RLEMAX 984*f4ee7fbaSAndroid Build Coastguard Worker 985*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 986*f4ee7fbaSAndroid Build Coastguard Worker description = self.description and self.description+': ' 987*f4ee7fbaSAndroid Build Coastguard Worker if index==0: return description+'map #0' 988*f4ee7fbaSAndroid Build Coastguard Worker if index<=self.RLEMAX: 989*f4ee7fbaSAndroid Build Coastguard Worker return '{}+{:0{}b}={} zeroes'.format( 990*f4ee7fbaSAndroid Build Coastguard Worker (1<<index), 991*f4ee7fbaSAndroid Build Coastguard Worker extra, self.extraBits(index), 992*f4ee7fbaSAndroid Build Coastguard Worker (1<<index)+extra) 993*f4ee7fbaSAndroid Build Coastguard Worker return '{}map #{}-{}={}'.format( 994*f4ee7fbaSAndroid Build Coastguard Worker description, 995*f4ee7fbaSAndroid Build Coastguard Worker index, self.RLEMAX, index-self.RLEMAX) 996*f4ee7fbaSAndroid Build Coastguard Worker 997*f4ee7fbaSAndroid Build Coastguard Worker#Prefix alphabets for the data stream---------------------------------- 998*f4ee7fbaSAndroid Build Coastguard Workerclass LiteralAlphabet(Code): 999*f4ee7fbaSAndroid Build Coastguard Worker """Alphabet of symbols. 1000*f4ee7fbaSAndroid Build Coastguard Worker """ 1001*f4ee7fbaSAndroid Build Coastguard Worker minLength = maxLength = 8 1002*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, number): 1003*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('L'+str(number), alphabetSize=1<<8) 1004*f4ee7fbaSAndroid Build Coastguard Worker 1005*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 1006*f4ee7fbaSAndroid Build Coastguard Worker return outputCharFormatter(index) 1007*f4ee7fbaSAndroid Build Coastguard Worker 1008*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra=None): 1009*f4ee7fbaSAndroid Build Coastguard Worker return index 1010*f4ee7fbaSAndroid Build Coastguard Worker 1011*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra=None): 1012*f4ee7fbaSAndroid Build Coastguard Worker return self.mnemonic(index) 1013*f4ee7fbaSAndroid Build Coastguard Worker 1014*f4ee7fbaSAndroid Build Coastguard Workerclass InsertLengthAlphabet(Enumerator): 1015*f4ee7fbaSAndroid Build Coastguard Worker """Intern code for insert counts 1016*f4ee7fbaSAndroid Build Coastguard Worker """ 1017*f4ee7fbaSAndroid Build Coastguard Worker value0 = 0 1018*f4ee7fbaSAndroid Build Coastguard Worker extraTable = [0,0,0,0,0, 0,1,1,2,2, 3,3,4,4,5, 5,6,7,8,9, 10,12,14,24] 1019*f4ee7fbaSAndroid Build Coastguard Worker 1020*f4ee7fbaSAndroid Build Coastguard Workerclass CopyLengthAlphabet(Enumerator): 1021*f4ee7fbaSAndroid Build Coastguard Worker value0 = 2 1022*f4ee7fbaSAndroid Build Coastguard Worker extraTable = [0,0,0,0,0, 0,0,0,1,1, 2,2,3,3,4, 4,5,5,6,7, 8,9,10,24] 1023*f4ee7fbaSAndroid Build Coastguard Worker 1024*f4ee7fbaSAndroid Build Coastguard Workerclass InsertAndCopyAlphabet(WithExtra): 1025*f4ee7fbaSAndroid Build Coastguard Worker """The insert and copy code 1026*f4ee7fbaSAndroid Build Coastguard Worker >>> for x in range(0,704,704//13): 1027*f4ee7fbaSAndroid Build Coastguard Worker ... print('{:10b}'.format(x), InsertAndCopyAlphabet()[x]) 1028*f4ee7fbaSAndroid Build Coastguard Worker 0 I0C2&D=0 1029*f4ee7fbaSAndroid Build Coastguard Worker 110110 I6+xC8&D=0 1030*f4ee7fbaSAndroid Build Coastguard Worker 1101100 I5C22+xxx&D=0 1031*f4ee7fbaSAndroid Build Coastguard Worker 10100010 I4C4 1032*f4ee7fbaSAndroid Build Coastguard Worker 11011000 I3C10+x 1033*f4ee7fbaSAndroid Build Coastguard Worker 100001110 I14+xxC8 1034*f4ee7fbaSAndroid Build Coastguard Worker 101000100 I10+xxC22+xxx 1035*f4ee7fbaSAndroid Build Coastguard Worker 101111010 I98+xxxxxC14+xx 1036*f4ee7fbaSAndroid Build Coastguard Worker 110110000 I6+xC70+xxxxx 1037*f4ee7fbaSAndroid Build Coastguard Worker 111100110 I1090+[10*x]C8 1038*f4ee7fbaSAndroid Build Coastguard Worker 1000011100 I26+xxxC326+[8*x] 1039*f4ee7fbaSAndroid Build Coastguard Worker 1001010010 I322+[8*x]C14+xx 1040*f4ee7fbaSAndroid Build Coastguard Worker 1010001000 I194+[7*x]C70+xxxxx 1041*f4ee7fbaSAndroid Build Coastguard Worker 1010111110 I22594+[24*x]C1094+[10*x] 1042*f4ee7fbaSAndroid Build Coastguard Worker """ 1043*f4ee7fbaSAndroid Build Coastguard Worker insertLengthAlphabet = InsertLengthAlphabet(None) 1044*f4ee7fbaSAndroid Build Coastguard Worker copyLengthAlphabet = CopyLengthAlphabet(None) 1045*f4ee7fbaSAndroid Build Coastguard Worker 1046*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, number=''): 1047*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('IC'+str(number), bitLength=10) 1048*f4ee7fbaSAndroid Build Coastguard Worker 1049*f4ee7fbaSAndroid Build Coastguard Worker def __len__(self): 1050*f4ee7fbaSAndroid Build Coastguard Worker return 704 1051*f4ee7fbaSAndroid Build Coastguard Worker 1052*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 1053*f4ee7fbaSAndroid Build Coastguard Worker insertSymbol, copySymbol, dist0 = self.splitSymbol(index) 1054*f4ee7fbaSAndroid Build Coastguard Worker return InsertLengthAlphabet.extraTable[insertSymbol.index] + \ 1055*f4ee7fbaSAndroid Build Coastguard Worker CopyLengthAlphabet.extraTable[copySymbol.index] 1056*f4ee7fbaSAndroid Build Coastguard Worker 1057*f4ee7fbaSAndroid Build Coastguard Worker def splitSymbol(self, index): 1058*f4ee7fbaSAndroid Build Coastguard Worker """Give relevant values for computations: 1059*f4ee7fbaSAndroid Build Coastguard Worker (insertSymbol, copySymbol, dist0flag) 1060*f4ee7fbaSAndroid Build Coastguard Worker """ 1061*f4ee7fbaSAndroid Build Coastguard Worker #determine insert and copy upper bits from table 1062*f4ee7fbaSAndroid Build Coastguard Worker row = [0,0,1,1,2,2,1,3,2,3,3][index>>6] 1063*f4ee7fbaSAndroid Build Coastguard Worker col = [0,1,0,1,0,1,2,0,2,1,2][index>>6] 1064*f4ee7fbaSAndroid Build Coastguard Worker #determine inserts and copy sub codes 1065*f4ee7fbaSAndroid Build Coastguard Worker insertLengthCode = row<<3 | index>>3&7 1066*f4ee7fbaSAndroid Build Coastguard Worker if row: insertLengthCode -= 8 1067*f4ee7fbaSAndroid Build Coastguard Worker copyLengthCode = col<<3 | index&7 1068*f4ee7fbaSAndroid Build Coastguard Worker return ( 1069*f4ee7fbaSAndroid Build Coastguard Worker Symbol(self.insertLengthAlphabet, insertLengthCode), 1070*f4ee7fbaSAndroid Build Coastguard Worker Symbol(self.copyLengthAlphabet, copyLengthCode), 1071*f4ee7fbaSAndroid Build Coastguard Worker row==0 1072*f4ee7fbaSAndroid Build Coastguard Worker ) 1073*f4ee7fbaSAndroid Build Coastguard Worker 1074*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index): 1075*f4ee7fbaSAndroid Build Coastguard Worker """Make a nice mnemonic 1076*f4ee7fbaSAndroid Build Coastguard Worker """ 1077*f4ee7fbaSAndroid Build Coastguard Worker i,c,d0 = self.splitSymbol(index) 1078*f4ee7fbaSAndroid Build Coastguard Worker iLower, _ = i.code.span(i.index) 1079*f4ee7fbaSAndroid Build Coastguard Worker iExtra = i.extraBits() 1080*f4ee7fbaSAndroid Build Coastguard Worker cLower, _ = c.code.span(c.index) 1081*f4ee7fbaSAndroid Build Coastguard Worker cExtra = c.extraBits() 1082*f4ee7fbaSAndroid Build Coastguard Worker return 'I{}{}{}C{}{}{}{}'.format( 1083*f4ee7fbaSAndroid Build Coastguard Worker iLower, 1084*f4ee7fbaSAndroid Build Coastguard Worker '+' if iExtra else '', 1085*f4ee7fbaSAndroid Build Coastguard Worker 'x'*iExtra if iExtra<6 else '[{}*x]'.format(iExtra), 1086*f4ee7fbaSAndroid Build Coastguard Worker cLower, 1087*f4ee7fbaSAndroid Build Coastguard Worker '+' if cExtra else '', 1088*f4ee7fbaSAndroid Build Coastguard Worker 'x'*cExtra if cExtra<6 else '[{}*x]'.format(cExtra), 1089*f4ee7fbaSAndroid Build Coastguard Worker '&D=0' if d0 else '') 1090*f4ee7fbaSAndroid Build Coastguard Worker 1091*f4ee7fbaSAndroid Build Coastguard Worker def value(self, index, extra): 1092*f4ee7fbaSAndroid Build Coastguard Worker i,c,d0 = self.splitSymbol(index) 1093*f4ee7fbaSAndroid Build Coastguard Worker iExtra = i.extraBits() 1094*f4ee7fbaSAndroid Build Coastguard Worker ce, ie = extra>>iExtra, extra&(1<<iExtra)-1 1095*f4ee7fbaSAndroid Build Coastguard Worker insert = i.value(ie) 1096*f4ee7fbaSAndroid Build Coastguard Worker copy = c.value(ce) 1097*f4ee7fbaSAndroid Build Coastguard Worker return insert, copy, d0 1098*f4ee7fbaSAndroid Build Coastguard Worker 1099*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 1100*f4ee7fbaSAndroid Build Coastguard Worker insert, copy, d0 = self.value(index, extra) 1101*f4ee7fbaSAndroid Build Coastguard Worker if d0: return 'Literal: {}, copy: {}, same distance'.format(insert, copy) 1102*f4ee7fbaSAndroid Build Coastguard Worker else: return 'Literal: {}, copy: {}'.format(insert, copy) 1103*f4ee7fbaSAndroid Build Coastguard Worker 1104*f4ee7fbaSAndroid Build Coastguard Workerclass DistanceAlphabet(WithExtra): 1105*f4ee7fbaSAndroid Build Coastguard Worker """Represent the distance encoding. 1106*f4ee7fbaSAndroid Build Coastguard Worker Dynamically generated alphabet. 1107*f4ee7fbaSAndroid Build Coastguard Worker This is what the documentation should have said: 1108*f4ee7fbaSAndroid Build Coastguard Worker Ignoring offsets for the moment, the "long" encoding works as follows: 1109*f4ee7fbaSAndroid Build Coastguard Worker Write the distance in binary as follows: 1110*f4ee7fbaSAndroid Build Coastguard Worker 1xy..yz..z, then the distance symbol consists of n..nxz..z 1111*f4ee7fbaSAndroid Build Coastguard Worker Where: 1112*f4ee7fbaSAndroid Build Coastguard Worker n is one less than number of bits in y 1113*f4ee7fbaSAndroid Build Coastguard Worker x is a single bit 1114*f4ee7fbaSAndroid Build Coastguard Worker y..y are n+1 extra bits (encoded in the bit stream) 1115*f4ee7fbaSAndroid Build Coastguard Worker z..z is NPOSTFIX bits that are part of the symbol 1116*f4ee7fbaSAndroid Build Coastguard Worker The offsets are so as to start at the lowest useable value: 1117*f4ee7fbaSAndroid Build Coastguard Worker if 1xyyyyz = distance +(4<<POSTFIX)-NDIRECT-1 1118*f4ee7fbaSAndroid Build Coastguard Worker then n..nxz..z is symbol -NDIRECT-16 1119*f4ee7fbaSAndroid Build Coastguard Worker >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10) 1120*f4ee7fbaSAndroid Build Coastguard Worker >>> print(d[4], d[17], d[34]) 1121*f4ee7fbaSAndroid Build Coastguard Worker last-1 1 10xx00-5 1122*f4ee7fbaSAndroid Build Coastguard Worker >>> [str(d[x]) for x in range(26, 32)] 1123*f4ee7fbaSAndroid Build Coastguard Worker ['10x00-5', '10x01-5', '10x10-5', '10x11-5', '11x00-5', '11x01-5'] 1124*f4ee7fbaSAndroid Build Coastguard Worker """ 1125*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, number, *, NPOSTFIX, NDIRECT): 1126*f4ee7fbaSAndroid Build Coastguard Worker self.NPOSTFIX = NPOSTFIX 1127*f4ee7fbaSAndroid Build Coastguard Worker self.NDIRECT = NDIRECT 1128*f4ee7fbaSAndroid Build Coastguard Worker #set length 1129*f4ee7fbaSAndroid Build Coastguard Worker #Actually, not all symbols are used, 1130*f4ee7fbaSAndroid Build Coastguard Worker #only NDIRECT+16+(44-2*POSTFIX<<NPOSTFIX) 1131*f4ee7fbaSAndroid Build Coastguard Worker super().__init__('D'+str(number), 1132*f4ee7fbaSAndroid Build Coastguard Worker alphabetSize=self.NDIRECT+16+(48<<self.NPOSTFIX)) 1133*f4ee7fbaSAndroid Build Coastguard Worker 1134*f4ee7fbaSAndroid Build Coastguard Worker def extraBits(self, index): 1135*f4ee7fbaSAndroid Build Coastguard Worker """Indicate how many extra bits are needed to interpret symbol 1136*f4ee7fbaSAndroid Build Coastguard Worker >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10) 1137*f4ee7fbaSAndroid Build Coastguard Worker >>> [d[i].extraBits() for i in range(26)] 1138*f4ee7fbaSAndroid Build Coastguard Worker [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1139*f4ee7fbaSAndroid Build Coastguard Worker >>> [d[i].extraBits() for i in range(26,36)] 1140*f4ee7fbaSAndroid Build Coastguard Worker [1, 1, 1, 1, 1, 1, 1, 1, 2, 2] 1141*f4ee7fbaSAndroid Build Coastguard Worker """ 1142*f4ee7fbaSAndroid Build Coastguard Worker if index<16+self.NDIRECT: return 0 1143*f4ee7fbaSAndroid Build Coastguard Worker return 1 + ((index - self.NDIRECT - 16) >> (self.NPOSTFIX + 1)) 1144*f4ee7fbaSAndroid Build Coastguard Worker 1145*f4ee7fbaSAndroid Build Coastguard Worker def value(self, dcode, dextra): 1146*f4ee7fbaSAndroid Build Coastguard Worker """Decode value of symbol together with the extra bits. 1147*f4ee7fbaSAndroid Build Coastguard Worker >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10) 1148*f4ee7fbaSAndroid Build Coastguard Worker >>> d[34].value(2) 1149*f4ee7fbaSAndroid Build Coastguard Worker (0, 35) 1150*f4ee7fbaSAndroid Build Coastguard Worker """ 1151*f4ee7fbaSAndroid Build Coastguard Worker if dcode<16: 1152*f4ee7fbaSAndroid Build Coastguard Worker return [(1,0),(2,0),(3,0),(4,0), 1153*f4ee7fbaSAndroid Build Coastguard Worker (1,-1),(1,+1),(1,-2),(1,+2),(1,-3),(1,+3), 1154*f4ee7fbaSAndroid Build Coastguard Worker (2,-1),(2,+1),(2,-2),(2,+2),(2,-3),(2,+3) 1155*f4ee7fbaSAndroid Build Coastguard Worker ][dcode] 1156*f4ee7fbaSAndroid Build Coastguard Worker if dcode<16+self.NDIRECT: 1157*f4ee7fbaSAndroid Build Coastguard Worker return (0,dcode-16) 1158*f4ee7fbaSAndroid Build Coastguard Worker #we use the original formulas, instead of my clear explanation 1159*f4ee7fbaSAndroid Build Coastguard Worker POSTFIX_MASK = (1 << self.NPOSTFIX) - 1 1160*f4ee7fbaSAndroid Build Coastguard Worker ndistbits = 1 + ((dcode - self.NDIRECT - 16) >> (self.NPOSTFIX + 1)) 1161*f4ee7fbaSAndroid Build Coastguard Worker hcode = (dcode - self.NDIRECT - 16) >> self.NPOSTFIX 1162*f4ee7fbaSAndroid Build Coastguard Worker lcode = (dcode - self.NDIRECT - 16) & POSTFIX_MASK 1163*f4ee7fbaSAndroid Build Coastguard Worker offset = ((2 + (hcode & 1)) << ndistbits) - 4 1164*f4ee7fbaSAndroid Build Coastguard Worker distance = ((offset + dextra) << self.NPOSTFIX) + lcode + self.NDIRECT + 1 1165*f4ee7fbaSAndroid Build Coastguard Worker return (0,distance) 1166*f4ee7fbaSAndroid Build Coastguard Worker 1167*f4ee7fbaSAndroid Build Coastguard Worker def mnemonic(self, index, verbose=False): 1168*f4ee7fbaSAndroid Build Coastguard Worker """Give mnemonic representation of meaning. 1169*f4ee7fbaSAndroid Build Coastguard Worker verbose compresses strings of x's 1170*f4ee7fbaSAndroid Build Coastguard Worker """ 1171*f4ee7fbaSAndroid Build Coastguard Worker if index<16: 1172*f4ee7fbaSAndroid Build Coastguard Worker return ['last', '2last', '3last', '4last', 1173*f4ee7fbaSAndroid Build Coastguard Worker 'last-1', 'last+1', 'last-2', 'last+2', 'last-3', 'last+3', 1174*f4ee7fbaSAndroid Build Coastguard Worker '2last-1', '2last+1', '2last-2', '2last+2', '2last-3', '2last+3' 1175*f4ee7fbaSAndroid Build Coastguard Worker ][index] 1176*f4ee7fbaSAndroid Build Coastguard Worker if index<16+self.NDIRECT: 1177*f4ee7fbaSAndroid Build Coastguard Worker return str(index-16) 1178*f4ee7fbaSAndroid Build Coastguard Worker #construct strings like "1xx01-15" 1179*f4ee7fbaSAndroid Build Coastguard Worker index -= self.NDIRECT+16 1180*f4ee7fbaSAndroid Build Coastguard Worker hcode = index >> self.NPOSTFIX 1181*f4ee7fbaSAndroid Build Coastguard Worker lcode = index & (1<<self.NPOSTFIX)-1 1182*f4ee7fbaSAndroid Build Coastguard Worker if self.NPOSTFIX: formatString = '1{0}{1}{2:0{3}b}{4:+d}' 1183*f4ee7fbaSAndroid Build Coastguard Worker else: formatString = '1{0}{1}{4:+d}' 1184*f4ee7fbaSAndroid Build Coastguard Worker return formatString.format( 1185*f4ee7fbaSAndroid Build Coastguard Worker hcode&1, 1186*f4ee7fbaSAndroid Build Coastguard Worker 'x'*(2+hcode>>1) if hcode<13 or verbose else '[{}*x]'.format(2+hcode>>1), 1187*f4ee7fbaSAndroid Build Coastguard Worker lcode, self.NPOSTFIX, 1188*f4ee7fbaSAndroid Build Coastguard Worker self.NDIRECT+1-(4<<self.NPOSTFIX)) 1189*f4ee7fbaSAndroid Build Coastguard Worker 1190*f4ee7fbaSAndroid Build Coastguard Worker def explanation(self, index, extra): 1191*f4ee7fbaSAndroid Build Coastguard Worker """ 1192*f4ee7fbaSAndroid Build Coastguard Worker >>> d = DistanceAlphabet('D', NPOSTFIX=2, NDIRECT=10) 1193*f4ee7fbaSAndroid Build Coastguard Worker >>> d[55].explanation(13) 1194*f4ee7fbaSAndroid Build Coastguard Worker '11[1101]01-5: [0]+240' 1195*f4ee7fbaSAndroid Build Coastguard Worker """ 1196*f4ee7fbaSAndroid Build Coastguard Worker extraBits = self.extraBits(index) 1197*f4ee7fbaSAndroid Build Coastguard Worker extraString = '[{:0{}b}]'.format(extra, extraBits) 1198*f4ee7fbaSAndroid Build Coastguard Worker return '{0}: [{1[0]}]{1[1]:+d}'.format( 1199*f4ee7fbaSAndroid Build Coastguard Worker self.mnemonic(index, True).replace('x'*(extraBits or 1), extraString), 1200*f4ee7fbaSAndroid Build Coastguard Worker self.value(index, extra)) 1201*f4ee7fbaSAndroid Build Coastguard Worker 1202*f4ee7fbaSAndroid Build Coastguard Worker#Classes for doing actual work------------------------------------------ 1203*f4ee7fbaSAndroid Build Coastguard Workerclass ContextModeKeeper: 1204*f4ee7fbaSAndroid Build Coastguard Worker """For computing the literal context mode. 1205*f4ee7fbaSAndroid Build Coastguard Worker You feed it characters, and it computes indices in the context map. 1206*f4ee7fbaSAndroid Build Coastguard Worker """ 1207*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, mode): 1208*f4ee7fbaSAndroid Build Coastguard Worker self.chars = deque([0,0], maxlen=2) 1209*f4ee7fbaSAndroid Build Coastguard Worker self.mode = mode 1210*f4ee7fbaSAndroid Build Coastguard Worker 1211*f4ee7fbaSAndroid Build Coastguard Worker def setContextMode(self, mode): 1212*f4ee7fbaSAndroid Build Coastguard Worker """Switch to given context mode (0..3)""" 1213*f4ee7fbaSAndroid Build Coastguard Worker self.mode = mode 1214*f4ee7fbaSAndroid Build Coastguard Worker def getIndex(self): 1215*f4ee7fbaSAndroid Build Coastguard Worker if self.mode==0: #LSB6 1216*f4ee7fbaSAndroid Build Coastguard Worker return self.chars[1]&0x3f 1217*f4ee7fbaSAndroid Build Coastguard Worker elif self.mode==1: #MSB6 1218*f4ee7fbaSAndroid Build Coastguard Worker return self.chars[1]>>2 1219*f4ee7fbaSAndroid Build Coastguard Worker elif self.mode==2: #UTF8: character class of previous and a bit of the second 1220*f4ee7fbaSAndroid Build Coastguard Worker p2,p1 = self.chars 1221*f4ee7fbaSAndroid Build Coastguard Worker return self.lut0[p1]|self.lut1[p2] 1222*f4ee7fbaSAndroid Build Coastguard Worker elif self.mode==3: #Signed: initial bits of last two bytes 1223*f4ee7fbaSAndroid Build Coastguard Worker p2,p1 = self.chars 1224*f4ee7fbaSAndroid Build Coastguard Worker return self.lut2[p1]<<3|self.lut2[p2] 1225*f4ee7fbaSAndroid Build Coastguard Worker 1226*f4ee7fbaSAndroid Build Coastguard Worker def add(self, index): 1227*f4ee7fbaSAndroid Build Coastguard Worker """Adjust the context for output char (as int).""" 1228*f4ee7fbaSAndroid Build Coastguard Worker self.chars.append(index) 1229*f4ee7fbaSAndroid Build Coastguard Worker 1230*f4ee7fbaSAndroid Build Coastguard Worker #0: control #16: quote #32: ,:; #48: AEIOU 1231*f4ee7fbaSAndroid Build Coastguard Worker #4: tab/lf/cr #20: % #36: . #52: BC..Z 1232*f4ee7fbaSAndroid Build Coastguard Worker #8: space #24: (<[{ #40: = #56: aeiou 1233*f4ee7fbaSAndroid Build Coastguard Worker #12:!#$&*+-/?@| #28: )>]} #44: 0-9 #60: bc..z 1234*f4ee7fbaSAndroid Build Coastguard Worker lut0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, 1235*f4ee7fbaSAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1236*f4ee7fbaSAndroid Build Coastguard Worker 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, 1237*f4ee7fbaSAndroid Build Coastguard Worker 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, 1238*f4ee7fbaSAndroid Build Coastguard Worker 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, 1239*f4ee7fbaSAndroid Build Coastguard Worker 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, 1240*f4ee7fbaSAndroid Build Coastguard Worker 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, 1241*f4ee7fbaSAndroid Build Coastguard Worker 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0 1242*f4ee7fbaSAndroid Build Coastguard Worker ]+[0,1]*32+[2,3]*32 1243*f4ee7fbaSAndroid Build Coastguard Worker #0: space 1:punctuation 2:digit/upper 3:lower 1244*f4ee7fbaSAndroid Build Coastguard Worker lut1 = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1245*f4ee7fbaSAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1246*f4ee7fbaSAndroid Build Coastguard Worker 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1247*f4ee7fbaSAndroid Build Coastguard Worker 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1248*f4ee7fbaSAndroid Build Coastguard Worker 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1249*f4ee7fbaSAndroid Build Coastguard Worker 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1250*f4ee7fbaSAndroid Build Coastguard Worker 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1251*f4ee7fbaSAndroid Build Coastguard Worker 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0 1252*f4ee7fbaSAndroid Build Coastguard Worker ]+[0]*96+[2]*32 1253*f4ee7fbaSAndroid Build Coastguard Worker #initial bits: 8*0, 4*0, 2*0, 1*0, 1*1, 2*1, 4*1, 8*1 1254*f4ee7fbaSAndroid Build Coastguard Worker lut2 = [0]+[1]*15+[2]*48+[3]*64+[4]*64+[5]*48+[6]*15+[7] 1255*f4ee7fbaSAndroid Build Coastguard Worker assert len(lut0)==len(lut1)==len(lut2)==256 1256*f4ee7fbaSAndroid Build Coastguard Worker 1257*f4ee7fbaSAndroid Build Coastguard Workerclass WordList: 1258*f4ee7fbaSAndroid Build Coastguard Worker """Word list. 1259*f4ee7fbaSAndroid Build Coastguard Worker >>> WordList().word(7, 35555) 1260*f4ee7fbaSAndroid Build Coastguard Worker b'Program to ' 1261*f4ee7fbaSAndroid Build Coastguard Worker """ 1262*f4ee7fbaSAndroid Build Coastguard Worker NDBITS = [0, 0, 0, 0, 10, 10, 11, 11, 10, 10, 1263*f4ee7fbaSAndroid Build Coastguard Worker 10, 10, 10, 9, 9, 8, 7, 7, 8, 7, 1264*f4ee7fbaSAndroid Build Coastguard Worker 7, 6, 6, 5, 5] 1265*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self): 1266*f4ee7fbaSAndroid Build Coastguard Worker self.file = open('dict', 'rb') 1267*f4ee7fbaSAndroid Build Coastguard Worker self.compileActions() 1268*f4ee7fbaSAndroid Build Coastguard Worker 1269*f4ee7fbaSAndroid Build Coastguard Worker def word(self, size, dist): 1270*f4ee7fbaSAndroid Build Coastguard Worker """Get word 1271*f4ee7fbaSAndroid Build Coastguard Worker """ 1272*f4ee7fbaSAndroid Build Coastguard Worker #split dist in index and action 1273*f4ee7fbaSAndroid Build Coastguard Worker ndbits = self.NDBITS[size] 1274*f4ee7fbaSAndroid Build Coastguard Worker index = dist&(1<<ndbits)-1 1275*f4ee7fbaSAndroid Build Coastguard Worker action = dist>>ndbits 1276*f4ee7fbaSAndroid Build Coastguard Worker #compute position in file 1277*f4ee7fbaSAndroid Build Coastguard Worker position = sum(n<<self.NDBITS[n] for n in range(4,size))+size*index 1278*f4ee7fbaSAndroid Build Coastguard Worker self.file.seek(position) 1279*f4ee7fbaSAndroid Build Coastguard Worker return self.doAction(self.file.read(size), action) 1280*f4ee7fbaSAndroid Build Coastguard Worker 1281*f4ee7fbaSAndroid Build Coastguard Worker def upperCase1(self, word): 1282*f4ee7fbaSAndroid Build Coastguard Worker word = word.decode('utf8') 1283*f4ee7fbaSAndroid Build Coastguard Worker word = word[0].upper()+word[1:] 1284*f4ee7fbaSAndroid Build Coastguard Worker return word.encode('utf8') 1285*f4ee7fbaSAndroid Build Coastguard Worker 1286*f4ee7fbaSAndroid Build Coastguard Worker 1287*f4ee7fbaSAndroid Build Coastguard Worker #Super compact form of action table. 1288*f4ee7fbaSAndroid Build Coastguard Worker #_ means space, .U means UpperCaseAll, U(w) means UpperCaseFirst 1289*f4ee7fbaSAndroid Build Coastguard Worker actionTable = r""" 1290*f4ee7fbaSAndroid Build Coastguard Worker 0:w 25:w+_for_ 50:w+\n\t 75:w+. This_100:w+ize_ 1291*f4ee7fbaSAndroid Build Coastguard Worker 1:w+_ 26:w[3:] 51:w+: 76:w+, 101:w.U+. 1292*f4ee7fbaSAndroid Build Coastguard Worker 2:_+w+_ 27:w[:-2] 52:_+w+._ 77:.+w+_ 102:\xc2\xa0+w 1293*f4ee7fbaSAndroid Build Coastguard Worker 3:w[1:] 28:w+_a_ 53:w+ed_ 78:U(w)+( 103:_+w+, 1294*f4ee7fbaSAndroid Build Coastguard Worker 4:U(w)+_ 29:w+_that_ 54:w[9:] 79:U(w)+. 104:U(w)+=" 1295*f4ee7fbaSAndroid Build Coastguard Worker 5:w+_the_ 30:_+U(w) 55:w[7:] 80:w+_not_ 105:w.U+=" 1296*f4ee7fbaSAndroid Build Coastguard Worker 6:_+w 31:w+._ 56:w[:-6] 81:_+w+=" 106:w+ous_ 1297*f4ee7fbaSAndroid Build Coastguard Worker 7:s_+w+_ 32:.+w 57:w+( 82:w+er_ 107:w.U+,_ 1298*f4ee7fbaSAndroid Build Coastguard Worker 8:w+_of_ 33:_+w+,_ 58:U(w)+,_ 83:_+w.U+_ 108:U(w)+=\' 1299*f4ee7fbaSAndroid Build Coastguard Worker 9:U(w) 34:w[4:] 59:w[:-8] 84:w+al_ 109:_+U(w)+, 1300*f4ee7fbaSAndroid Build Coastguard Worker 10:w+_and_ 35:w+_with_ 60:w+_at_ 85:_+w.U 110:_+w.U+=" 1301*f4ee7fbaSAndroid Build Coastguard Worker 11:w[2:] 36:w+\' 61:w+ly_ 86:w+=\' 111:_+w.U+,_ 1302*f4ee7fbaSAndroid Build Coastguard Worker 12:w[:-1] 37:w+_from_ 62:_the_+w+_of_ 87:w.U+" 112:_+w.U+, 1303*f4ee7fbaSAndroid Build Coastguard Worker 13:,_+w+_ 38:w+_by_ 63:w[:-5] 88:U(w)+._ 113:w.U+( 1304*f4ee7fbaSAndroid Build Coastguard Worker 14:w+,_ 39:w[5:] 64:w[:-9] 89:_+w+( 114:w.U+._ 1305*f4ee7fbaSAndroid Build Coastguard Worker 15:_+U(w)+_ 40:w[6:] 65:_+U(w)+,_ 90:w+ful_ 115:_+w.U+. 1306*f4ee7fbaSAndroid Build Coastguard Worker 16:w+_in_ 41:_the_+w 66:U(w)+" 91:_+U(w)+._116:w.U+=\' 1307*f4ee7fbaSAndroid Build Coastguard Worker 17:w+_to_ 42:w[:-4] 67:.+w+( 92:w+ive_ 117:_+w.U+._ 1308*f4ee7fbaSAndroid Build Coastguard Worker 18:e_+w+_ 43:w+. The_ 68:w.U+_ 93:w+less_ 118:_+U(w)+=" 1309*f4ee7fbaSAndroid Build Coastguard Worker 19:w+" 44:w.U 69:U(w)+"> 94:w.U+\' 119:_+w.U+=\' 1310*f4ee7fbaSAndroid Build Coastguard Worker 20:w+. 45:w+_on_ 70:w+=" 95:w+est_ 120:_+U(w)+=\' 1311*f4ee7fbaSAndroid Build Coastguard Worker 21:w+"> 46:w+_as_ 71:_+w+. 96:_+U(w)+. 1312*f4ee7fbaSAndroid Build Coastguard Worker 22:w+\n 47:w+_is_ 72:.com/+w 97:w.U+"> 1313*f4ee7fbaSAndroid Build Coastguard Worker 23:w[:-3] 48:w[:-7] 98:_+w+=\' 1314*f4ee7fbaSAndroid Build Coastguard Worker 24:w+] 49:w[:-1]+ing_ 74:U(w)+\' 99:U(w)+, 1315*f4ee7fbaSAndroid Build Coastguard Worker """ 1316*f4ee7fbaSAndroid Build Coastguard Worker 1317*f4ee7fbaSAndroid Build Coastguard Worker def compileActions(self): 1318*f4ee7fbaSAndroid Build Coastguard Worker """Build the action table from the text above 1319*f4ee7fbaSAndroid Build Coastguard Worker """ 1320*f4ee7fbaSAndroid Build Coastguard Worker import re 1321*f4ee7fbaSAndroid Build Coastguard Worker self.actionList = actions = [None]*121 1322*f4ee7fbaSAndroid Build Coastguard Worker #Action 73, which is too long, looks like this when expanded: 1323*f4ee7fbaSAndroid Build Coastguard Worker actions[73] = "b' the '+w+b' of the '" 1324*f4ee7fbaSAndroid Build Coastguard Worker #find out what the columns are 1325*f4ee7fbaSAndroid Build Coastguard Worker actionLines = self.actionTable.splitlines() 1326*f4ee7fbaSAndroid Build Coastguard Worker colonPositions = [m.start() 1327*f4ee7fbaSAndroid Build Coastguard Worker for m in re.finditer(':',actionLines[1]) 1328*f4ee7fbaSAndroid Build Coastguard Worker ]+[100] 1329*f4ee7fbaSAndroid Build Coastguard Worker columns = [(colonPositions[i]-3,colonPositions[i+1]-3) 1330*f4ee7fbaSAndroid Build Coastguard Worker for i in range(len(colonPositions)-1)] 1331*f4ee7fbaSAndroid Build Coastguard Worker for line in self.actionTable.splitlines(keepends=False): 1332*f4ee7fbaSAndroid Build Coastguard Worker for start,end in columns: 1333*f4ee7fbaSAndroid Build Coastguard Worker action = line[start:end] 1334*f4ee7fbaSAndroid Build Coastguard Worker #skip empty actions 1335*f4ee7fbaSAndroid Build Coastguard Worker if not action or action.isspace(): continue 1336*f4ee7fbaSAndroid Build Coastguard Worker #chop it up, and check if the colon is properly placed 1337*f4ee7fbaSAndroid Build Coastguard Worker index, colon, action = action[:3], action[3], action[4:] 1338*f4ee7fbaSAndroid Build Coastguard Worker assert colon==':' 1339*f4ee7fbaSAndroid Build Coastguard Worker #remove filler spaces at right 1340*f4ee7fbaSAndroid Build Coastguard Worker action = action.rstrip() 1341*f4ee7fbaSAndroid Build Coastguard Worker #replace space symbols 1342*f4ee7fbaSAndroid Build Coastguard Worker action = action.replace('_', ' ') 1343*f4ee7fbaSAndroid Build Coastguard Worker wPos = action.index('w') 1344*f4ee7fbaSAndroid Build Coastguard Worker #add quotes around left string when present 1345*f4ee7fbaSAndroid Build Coastguard Worker #translation: any pattern from beginning, up to 1346*f4ee7fbaSAndroid Build Coastguard Worker #(but not including) a + following by a w later on 1347*f4ee7fbaSAndroid Build Coastguard Worker action = re.sub(r"^(.*)(?=\+[U(]*w)", r"b'\1'", action) 1348*f4ee7fbaSAndroid Build Coastguard Worker #add quotes around right string when present 1349*f4ee7fbaSAndroid Build Coastguard Worker #translation: anything with a w in it, followed by a + 1350*f4ee7fbaSAndroid Build Coastguard Worker #and a pattern up to the end 1351*f4ee7fbaSAndroid Build Coastguard Worker #(there is no variable lookbehind assertion, 1352*f4ee7fbaSAndroid Build Coastguard Worker #so we have to copy the pattern) 1353*f4ee7fbaSAndroid Build Coastguard Worker action = re.sub(r"(w[[:\-1\]).U]*)\+(.*)$", r"\1+b'\2'", action) 1354*f4ee7fbaSAndroid Build Coastguard Worker #expand shortcut for uppercaseAll 1355*f4ee7fbaSAndroid Build Coastguard Worker action = action.replace(".U", ".upper()") 1356*f4ee7fbaSAndroid Build Coastguard Worker #store action 1357*f4ee7fbaSAndroid Build Coastguard Worker actions[int(index)] = action 1358*f4ee7fbaSAndroid Build Coastguard Worker 1359*f4ee7fbaSAndroid Build Coastguard Worker def doAction(self, w, action): 1360*f4ee7fbaSAndroid Build Coastguard Worker """Perform the proper action 1361*f4ee7fbaSAndroid Build Coastguard Worker """ 1362*f4ee7fbaSAndroid Build Coastguard Worker #set environment for the UpperCaseFirst 1363*f4ee7fbaSAndroid Build Coastguard Worker U = self.upperCase1 1364*f4ee7fbaSAndroid Build Coastguard Worker return eval(self.actionList[action], locals()) 1365*f4ee7fbaSAndroid Build Coastguard Worker 1366*f4ee7fbaSAndroid Build Coastguard Workerclass Layout: 1367*f4ee7fbaSAndroid Build Coastguard Worker """Class to layout the output. 1368*f4ee7fbaSAndroid Build Coastguard Worker """ 1369*f4ee7fbaSAndroid Build Coastguard Worker #display width of hexdata+bitdata 1370*f4ee7fbaSAndroid Build Coastguard Worker width = 25 1371*f4ee7fbaSAndroid Build Coastguard Worker #general 1372*f4ee7fbaSAndroid Build Coastguard Worker def __init__(self, stream): 1373*f4ee7fbaSAndroid Build Coastguard Worker self.stream = stream 1374*f4ee7fbaSAndroid Build Coastguard Worker self.bitPtr = self.width 1375*f4ee7fbaSAndroid Build Coastguard Worker 1376*f4ee7fbaSAndroid Build Coastguard Worker def makeHexData(self, pos): 1377*f4ee7fbaSAndroid Build Coastguard Worker """Produce hex dump of all data containing the bits 1378*f4ee7fbaSAndroid Build Coastguard Worker from pos to stream.pos 1379*f4ee7fbaSAndroid Build Coastguard Worker """ 1380*f4ee7fbaSAndroid Build Coastguard Worker firstAddress = pos+7>>3 1381*f4ee7fbaSAndroid Build Coastguard Worker lastAddress = self.stream.pos+7>>3 1382*f4ee7fbaSAndroid Build Coastguard Worker return ''.join(map('{:02x} '.format, 1383*f4ee7fbaSAndroid Build Coastguard Worker self.stream.data[firstAddress:lastAddress])) 1384*f4ee7fbaSAndroid Build Coastguard Worker 1385*f4ee7fbaSAndroid Build Coastguard Worker def formatBitData(self, pos, width1, width2=0): 1386*f4ee7fbaSAndroid Build Coastguard Worker """Show formatted bit data: 1387*f4ee7fbaSAndroid Build Coastguard Worker Bytes are separated by commas 1388*f4ee7fbaSAndroid Build Coastguard Worker whole bytes are displayed in hex 1389*f4ee7fbaSAndroid Build Coastguard Worker >>> Layout(olleke).formatBitData(6, 2, 16) 1390*f4ee7fbaSAndroid Build Coastguard Worker '|00h|2Eh,|00' 1391*f4ee7fbaSAndroid Build Coastguard Worker >>> Layout(olleke).formatBitData(4, 1, 0) 1392*f4ee7fbaSAndroid Build Coastguard Worker '1' 1393*f4ee7fbaSAndroid Build Coastguard Worker """ 1394*f4ee7fbaSAndroid Build Coastguard Worker result = [] 1395*f4ee7fbaSAndroid Build Coastguard Worker #make empty prefix code explicit 1396*f4ee7fbaSAndroid Build Coastguard Worker if width1==0: result = ['()', ','] 1397*f4ee7fbaSAndroid Build Coastguard Worker for width in width1, width2: 1398*f4ee7fbaSAndroid Build Coastguard Worker #skip empty width2 1399*f4ee7fbaSAndroid Build Coastguard Worker if width==0: continue 1400*f4ee7fbaSAndroid Build Coastguard Worker #build result backwards in a list 1401*f4ee7fbaSAndroid Build Coastguard Worker while width>0: 1402*f4ee7fbaSAndroid Build Coastguard Worker availableBits = 8-(pos&7) 1403*f4ee7fbaSAndroid Build Coastguard Worker if width<availableBits: 1404*f4ee7fbaSAndroid Build Coastguard Worker #read partial byte, beginning nor ending at boundary 1405*f4ee7fbaSAndroid Build Coastguard Worker data = self.stream.data[pos>>3] >> (pos&7) & (1<<width)-1 1406*f4ee7fbaSAndroid Build Coastguard Worker result.append('{:0{}b}'.format(data, width)) 1407*f4ee7fbaSAndroid Build Coastguard Worker elif availableBits<8: 1408*f4ee7fbaSAndroid Build Coastguard Worker #read rest of byte, ending at boundary 1409*f4ee7fbaSAndroid Build Coastguard Worker data = self.stream.data[pos>>3] >> (pos&7) 1410*f4ee7fbaSAndroid Build Coastguard Worker result.append('|{:0{}b}'.format(data, availableBits)) 1411*f4ee7fbaSAndroid Build Coastguard Worker else: 1412*f4ee7fbaSAndroid Build Coastguard Worker #read whole byte (in hex), beginning and ending at boundary 1413*f4ee7fbaSAndroid Build Coastguard Worker data = self.stream.data[pos>>3] 1414*f4ee7fbaSAndroid Build Coastguard Worker result.append('|{:02X}h'.format(data)) 1415*f4ee7fbaSAndroid Build Coastguard Worker width -= availableBits 1416*f4ee7fbaSAndroid Build Coastguard Worker pos += availableBits 1417*f4ee7fbaSAndroid Build Coastguard Worker #if width overshot from the availableBits subtraction, fix it 1418*f4ee7fbaSAndroid Build Coastguard Worker pos += width 1419*f4ee7fbaSAndroid Build Coastguard Worker #add comma to separate fields 1420*f4ee7fbaSAndroid Build Coastguard Worker result.append(',') 1421*f4ee7fbaSAndroid Build Coastguard Worker #concatenate pieces, reversed, skipping the last space 1422*f4ee7fbaSAndroid Build Coastguard Worker return ''.join(result[-2::-1]) 1423*f4ee7fbaSAndroid Build Coastguard Worker 1424*f4ee7fbaSAndroid Build Coastguard Worker def readPrefixCode(self, alphabet): 1425*f4ee7fbaSAndroid Build Coastguard Worker """give alphabet the prefix code that is read from the stream 1426*f4ee7fbaSAndroid Build Coastguard Worker Called for the following alphabets, in this order: 1427*f4ee7fbaSAndroid Build Coastguard Worker The alphabet in question must have a "logical" order, 1428*f4ee7fbaSAndroid Build Coastguard Worker otherwise the assignment of symbols doesn't work. 1429*f4ee7fbaSAndroid Build Coastguard Worker """ 1430*f4ee7fbaSAndroid Build Coastguard Worker mode, numberOfSymbols = self.verboseRead(PrefixCodeHeader(alphabet.name)) 1431*f4ee7fbaSAndroid Build Coastguard Worker if mode=='Complex': 1432*f4ee7fbaSAndroid Build Coastguard Worker #for a complex code, numberOfSymbols means hskip 1433*f4ee7fbaSAndroid Build Coastguard Worker self.readComplexCode(numberOfSymbols, alphabet) 1434*f4ee7fbaSAndroid Build Coastguard Worker return alphabet 1435*f4ee7fbaSAndroid Build Coastguard Worker else: 1436*f4ee7fbaSAndroid Build Coastguard Worker table = [] 1437*f4ee7fbaSAndroid Build Coastguard Worker #Set table of lengths for mnemonic function 1438*f4ee7fbaSAndroid Build Coastguard Worker lengths = [[0], [1,1], [1,2,2], '????'][numberOfSymbols-1] 1439*f4ee7fbaSAndroid Build Coastguard Worker #adjust mnemonic function of alphabet class 1440*f4ee7fbaSAndroid Build Coastguard Worker def myMnemonic(index): 1441*f4ee7fbaSAndroid Build Coastguard Worker return '{} bit{}: {}'.format( 1442*f4ee7fbaSAndroid Build Coastguard Worker lengths[i], 1443*f4ee7fbaSAndroid Build Coastguard Worker '' if lengths[i]==1 else 's', 1444*f4ee7fbaSAndroid Build Coastguard Worker alphabet.__class__.mnemonic(alphabet, index) 1445*f4ee7fbaSAndroid Build Coastguard Worker ) 1446*f4ee7fbaSAndroid Build Coastguard Worker alphabet.mnemonic = myMnemonic 1447*f4ee7fbaSAndroid Build Coastguard Worker for i in range(numberOfSymbols): 1448*f4ee7fbaSAndroid Build Coastguard Worker table.append(self.verboseRead(alphabet, skipExtra=True).index) 1449*f4ee7fbaSAndroid Build Coastguard Worker #restore mnemonic 1450*f4ee7fbaSAndroid Build Coastguard Worker del alphabet.mnemonic 1451*f4ee7fbaSAndroid Build Coastguard Worker if numberOfSymbols==4: 1452*f4ee7fbaSAndroid Build Coastguard Worker #read tree shape to redefine lengths 1453*f4ee7fbaSAndroid Build Coastguard Worker lengths = self.verboseRead(TreeShapeAlhabet()) 1454*f4ee7fbaSAndroid Build Coastguard Worker #construct the alphabet prefix code 1455*f4ee7fbaSAndroid Build Coastguard Worker alphabet.setLength(dict(zip(table, lengths))) 1456*f4ee7fbaSAndroid Build Coastguard Worker return alphabet 1457*f4ee7fbaSAndroid Build Coastguard Worker 1458*f4ee7fbaSAndroid Build Coastguard Worker def readComplexCode(self, hskip, alphabet): 1459*f4ee7fbaSAndroid Build Coastguard Worker """Read complex code""" 1460*f4ee7fbaSAndroid Build Coastguard Worker stream = self.stream 1461*f4ee7fbaSAndroid Build Coastguard Worker #read the lengths for the length code 1462*f4ee7fbaSAndroid Build Coastguard Worker lengths = [1,2,3,4,0,5,17,6,16,7,8,9,10,11,12,13,14,15][hskip:] 1463*f4ee7fbaSAndroid Build Coastguard Worker codeLengths = {} 1464*f4ee7fbaSAndroid Build Coastguard Worker total = 0 1465*f4ee7fbaSAndroid Build Coastguard Worker lol = LengthOfLengthAlphabet('##'+alphabet.name) 1466*f4ee7fbaSAndroid Build Coastguard Worker #lengthCode will be used for coding the lengths of the new code 1467*f4ee7fbaSAndroid Build Coastguard Worker #we use it for display until now; definition comes below 1468*f4ee7fbaSAndroid Build Coastguard Worker lengthCode = LengthAlphabet('#'+alphabet.name) 1469*f4ee7fbaSAndroid Build Coastguard Worker lengthIter = iter(lengths) 1470*f4ee7fbaSAndroid Build Coastguard Worker lengthsLeft = len(lengths) 1471*f4ee7fbaSAndroid Build Coastguard Worker while total<32 and lengthsLeft>0: 1472*f4ee7fbaSAndroid Build Coastguard Worker lengthsLeft -= 1 1473*f4ee7fbaSAndroid Build Coastguard Worker newSymbol = next(lengthIter) 1474*f4ee7fbaSAndroid Build Coastguard Worker lol.description = str(lengthCode[newSymbol]) 1475*f4ee7fbaSAndroid Build Coastguard Worker length = self.verboseRead(lol) 1476*f4ee7fbaSAndroid Build Coastguard Worker if length: 1477*f4ee7fbaSAndroid Build Coastguard Worker codeLengths[newSymbol] = length 1478*f4ee7fbaSAndroid Build Coastguard Worker total += 32>>length 1479*f4ee7fbaSAndroid Build Coastguard Worker if total>32: raise ValueError("Stream format") 1480*f4ee7fbaSAndroid Build Coastguard Worker if len(codeLengths)==1: codeLengths[list(codeLengths.keys())[0]] = 0 1481*f4ee7fbaSAndroid Build Coastguard Worker #Now set the encoding of the lengthCode 1482*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.setLength(codeLengths) 1483*f4ee7fbaSAndroid Build Coastguard Worker print("***** Lengths for {} will be coded as:".format(alphabet.name)) 1484*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.showCode() 1485*f4ee7fbaSAndroid Build Coastguard Worker #Now determine the symbol lengths with the lengthCode 1486*f4ee7fbaSAndroid Build Coastguard Worker symbolLengths = {} 1487*f4ee7fbaSAndroid Build Coastguard Worker total = 0 1488*f4ee7fbaSAndroid Build Coastguard Worker lastLength = 8 1489*f4ee7fbaSAndroid Build Coastguard Worker alphabetIter = iter(alphabet) 1490*f4ee7fbaSAndroid Build Coastguard Worker while total<32768: 1491*f4ee7fbaSAndroid Build Coastguard Worker #look ahead to see what is going to happen 1492*f4ee7fbaSAndroid Build Coastguard Worker length = lengthCode.decodePeek( 1493*f4ee7fbaSAndroid Build Coastguard Worker self.stream.peek(lengthCode.maxLength))[1].index 1494*f4ee7fbaSAndroid Build Coastguard Worker #in every branch, set lengthCode.description to explanatory text 1495*f4ee7fbaSAndroid Build Coastguard Worker #lengthCode calls format(symbol, extra) with this string 1496*f4ee7fbaSAndroid Build Coastguard Worker if length==0: 1497*f4ee7fbaSAndroid Build Coastguard Worker symbol = next(alphabetIter) 1498*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = 'symbol {} unused'.format(symbol) 1499*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(lengthCode) 1500*f4ee7fbaSAndroid Build Coastguard Worker #unused symbol 1501*f4ee7fbaSAndroid Build Coastguard Worker continue 1502*f4ee7fbaSAndroid Build Coastguard Worker if length==16: 1503*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = \ 1504*f4ee7fbaSAndroid Build Coastguard Worker '{1}+3 symbols of length '+str(lastLength) 1505*f4ee7fbaSAndroid Build Coastguard Worker extra = self.verboseRead(lengthCode) 1506*f4ee7fbaSAndroid Build Coastguard Worker #scan series of 16s (repeat counts) 1507*f4ee7fbaSAndroid Build Coastguard Worker #start with repeat count 2 1508*f4ee7fbaSAndroid Build Coastguard Worker repeat = 2 1509*f4ee7fbaSAndroid Build Coastguard Worker startSymbol = next(alphabetIter) 1510*f4ee7fbaSAndroid Build Coastguard Worker endSymbol = next(alphabetIter) 1511*f4ee7fbaSAndroid Build Coastguard Worker symbolLengths[startSymbol.index] = \ 1512*f4ee7fbaSAndroid Build Coastguard Worker symbolLengths[endSymbol.index] = lastLength 1513*f4ee7fbaSAndroid Build Coastguard Worker #count the two just defined symbols 1514*f4ee7fbaSAndroid Build Coastguard Worker total += 2*32768>>lastLength 1515*f4ee7fbaSAndroid Build Coastguard Worker #note: loop may end because we're there 1516*f4ee7fbaSAndroid Build Coastguard Worker #even if a 16 _appears_ to follow 1517*f4ee7fbaSAndroid Build Coastguard Worker while True: 1518*f4ee7fbaSAndroid Build Coastguard Worker #determine last symbol 1519*f4ee7fbaSAndroid Build Coastguard Worker oldRepeat = repeat 1520*f4ee7fbaSAndroid Build Coastguard Worker repeat = (repeat-2<<2)+extra+3 1521*f4ee7fbaSAndroid Build Coastguard Worker #read as many symbols as repeat increased 1522*f4ee7fbaSAndroid Build Coastguard Worker for i in range(oldRepeat, repeat): 1523*f4ee7fbaSAndroid Build Coastguard Worker endSymbol = next(alphabetIter) 1524*f4ee7fbaSAndroid Build Coastguard Worker symbolLengths[endSymbol.index] = lastLength 1525*f4ee7fbaSAndroid Build Coastguard Worker #compute new total; it may be end of loop 1526*f4ee7fbaSAndroid Build Coastguard Worker total += (repeat-oldRepeat)*32768>>lastLength 1527*f4ee7fbaSAndroid Build Coastguard Worker if total>=32768: break 1528*f4ee7fbaSAndroid Build Coastguard Worker #see if there is more to do 1529*f4ee7fbaSAndroid Build Coastguard Worker length = lengthCode.decodePeek( 1530*f4ee7fbaSAndroid Build Coastguard Worker self.stream.peek(lengthCode.maxLength))[1].index 1531*f4ee7fbaSAndroid Build Coastguard Worker if length!=16: break 1532*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = 'total {}+{{1}} symbols'.format( 1533*f4ee7fbaSAndroid Build Coastguard Worker (repeat-2<<2)+3) 1534*f4ee7fbaSAndroid Build Coastguard Worker extra = self.verboseRead(lengthCode) 1535*f4ee7fbaSAndroid Build Coastguard Worker elif length==17: 1536*f4ee7fbaSAndroid Build Coastguard Worker #read, and show explanation 1537*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = '{1}+3 unused' 1538*f4ee7fbaSAndroid Build Coastguard Worker extra = self.verboseRead(lengthCode) 1539*f4ee7fbaSAndroid Build Coastguard Worker #scan series of 17s (groups of zero counts) 1540*f4ee7fbaSAndroid Build Coastguard Worker #start with repeat count 2 1541*f4ee7fbaSAndroid Build Coastguard Worker repeat = 2 1542*f4ee7fbaSAndroid Build Coastguard Worker startSymbol = next(alphabetIter) 1543*f4ee7fbaSAndroid Build Coastguard Worker endSymbol = next(alphabetIter) 1544*f4ee7fbaSAndroid Build Coastguard Worker #note: loop will not end with total==32768, 1545*f4ee7fbaSAndroid Build Coastguard Worker #since total doesn't change here 1546*f4ee7fbaSAndroid Build Coastguard Worker while True: 1547*f4ee7fbaSAndroid Build Coastguard Worker #determine last symbol 1548*f4ee7fbaSAndroid Build Coastguard Worker oldRepeat = repeat 1549*f4ee7fbaSAndroid Build Coastguard Worker repeat = (repeat-2<<3)+extra+3 1550*f4ee7fbaSAndroid Build Coastguard Worker #read as many symbols as repeat increases 1551*f4ee7fbaSAndroid Build Coastguard Worker for i in range(repeat-oldRepeat): 1552*f4ee7fbaSAndroid Build Coastguard Worker endSymbol = next(alphabetIter) 1553*f4ee7fbaSAndroid Build Coastguard Worker #see if there is more to do 1554*f4ee7fbaSAndroid Build Coastguard Worker length = lengthCode.decodePeek( 1555*f4ee7fbaSAndroid Build Coastguard Worker self.stream.peek(lengthCode.maxLength))[1].index 1556*f4ee7fbaSAndroid Build Coastguard Worker if length!=17: break 1557*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = 'total {}+{{1}} unused'.format( 1558*f4ee7fbaSAndroid Build Coastguard Worker (repeat-2<<3)+3) 1559*f4ee7fbaSAndroid Build Coastguard Worker extra = self.verboseRead(lengthCode) 1560*f4ee7fbaSAndroid Build Coastguard Worker else: 1561*f4ee7fbaSAndroid Build Coastguard Worker symbol = next(alphabetIter) 1562*f4ee7fbaSAndroid Build Coastguard Worker #double braces for format 1563*f4ee7fbaSAndroid Build Coastguard Worker char = str(symbol) 1564*f4ee7fbaSAndroid Build Coastguard Worker if char in '{}': char *= 2 1565*f4ee7fbaSAndroid Build Coastguard Worker lengthCode.description = \ 1566*f4ee7fbaSAndroid Build Coastguard Worker 'Length for {} is {{0.index}} bits'.format(char) 1567*f4ee7fbaSAndroid Build Coastguard Worker #output is not needed (will be 0) 1568*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(lengthCode) 1569*f4ee7fbaSAndroid Build Coastguard Worker symbolLengths[symbol.index] = length 1570*f4ee7fbaSAndroid Build Coastguard Worker total += 32768>>length 1571*f4ee7fbaSAndroid Build Coastguard Worker lastLength = length 1572*f4ee7fbaSAndroid Build Coastguard Worker assert total==32768 1573*f4ee7fbaSAndroid Build Coastguard Worker alphabet.setLength(symbolLengths) 1574*f4ee7fbaSAndroid Build Coastguard Worker print('End of table. Prefix code '+alphabet.name+':') 1575*f4ee7fbaSAndroid Build Coastguard Worker alphabet.showCode() 1576*f4ee7fbaSAndroid Build Coastguard Worker 1577*f4ee7fbaSAndroid Build Coastguard Worker #stream 1578*f4ee7fbaSAndroid Build Coastguard Worker def processStream(self): 1579*f4ee7fbaSAndroid Build Coastguard Worker """Process a brotli stream. 1580*f4ee7fbaSAndroid Build Coastguard Worker """ 1581*f4ee7fbaSAndroid Build Coastguard Worker print('addr hex{:{}s}binary context explanation'.format( 1582*f4ee7fbaSAndroid Build Coastguard Worker '', self.width-10)) 1583*f4ee7fbaSAndroid Build Coastguard Worker print('Stream header'.center(60, '-')) 1584*f4ee7fbaSAndroid Build Coastguard Worker self.windowSize = self.verboseRead(WindowSizeAlphabet()) 1585*f4ee7fbaSAndroid Build Coastguard Worker print('Metablock header'.center(60, '=')) 1586*f4ee7fbaSAndroid Build Coastguard Worker self.ISLAST = False 1587*f4ee7fbaSAndroid Build Coastguard Worker self.output = bytearray() 1588*f4ee7fbaSAndroid Build Coastguard Worker while not self.ISLAST: 1589*f4ee7fbaSAndroid Build Coastguard Worker self.ISLAST = self.verboseRead( 1590*f4ee7fbaSAndroid Build Coastguard Worker BoolCode('LAST', description="Last block")) 1591*f4ee7fbaSAndroid Build Coastguard Worker if self.ISLAST: 1592*f4ee7fbaSAndroid Build Coastguard Worker if self.verboseRead( 1593*f4ee7fbaSAndroid Build Coastguard Worker BoolCode('EMPTY', description="Empty block")): break 1594*f4ee7fbaSAndroid Build Coastguard Worker if self.metablockLength(): continue 1595*f4ee7fbaSAndroid Build Coastguard Worker if not self.ISLAST and self.uncompressed(): continue 1596*f4ee7fbaSAndroid Build Coastguard Worker print('Block type descriptors'.center(60, '-')) 1597*f4ee7fbaSAndroid Build Coastguard Worker self.numberOfBlockTypes = {} 1598*f4ee7fbaSAndroid Build Coastguard Worker self.currentBlockCounts = {} 1599*f4ee7fbaSAndroid Build Coastguard Worker self.blockTypeCodes = {} 1600*f4ee7fbaSAndroid Build Coastguard Worker self.blockCountCodes = {} 1601*f4ee7fbaSAndroid Build Coastguard Worker for blockType in (L,I,D): self.blockType(blockType) 1602*f4ee7fbaSAndroid Build Coastguard Worker print('Distance code parameters'.center(60, '-')) 1603*f4ee7fbaSAndroid Build Coastguard Worker self.NPOSTFIX, self.NDIRECT = self.verboseRead(DistanceParamAlphabet()) 1604*f4ee7fbaSAndroid Build Coastguard Worker self.readLiteralContextModes() 1605*f4ee7fbaSAndroid Build Coastguard Worker print('Context maps'.center(60, '-')) 1606*f4ee7fbaSAndroid Build Coastguard Worker self.cmaps = {} 1607*f4ee7fbaSAndroid Build Coastguard Worker #keep the number of each kind of prefix tree for the last loop 1608*f4ee7fbaSAndroid Build Coastguard Worker numberOfTrees = {I: self.numberOfBlockTypes[I]} 1609*f4ee7fbaSAndroid Build Coastguard Worker for blockType in (L,D): 1610*f4ee7fbaSAndroid Build Coastguard Worker numberOfTrees[blockType] = self.contextMap(blockType) 1611*f4ee7fbaSAndroid Build Coastguard Worker print('Prefix code lists'.center(60, '-')) 1612*f4ee7fbaSAndroid Build Coastguard Worker self.prefixCodes = {} 1613*f4ee7fbaSAndroid Build Coastguard Worker for blockType in (L,I,D): 1614*f4ee7fbaSAndroid Build Coastguard Worker self.readPrefixArray(blockType, numberOfTrees[blockType]) 1615*f4ee7fbaSAndroid Build Coastguard Worker self.metablock() 1616*f4ee7fbaSAndroid Build Coastguard Worker 1617*f4ee7fbaSAndroid Build Coastguard Worker #metablock header 1618*f4ee7fbaSAndroid Build Coastguard Worker def verboseRead(self, alphabet, context='', skipExtra=False): 1619*f4ee7fbaSAndroid Build Coastguard Worker """Read symbol and extra from stream and explain what happens. 1620*f4ee7fbaSAndroid Build Coastguard Worker Returns the value of the symbol 1621*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.pos = 0 1622*f4ee7fbaSAndroid Build Coastguard Worker >>> l = Layout(olleke) 1623*f4ee7fbaSAndroid Build Coastguard Worker >>> l.verboseRead(WindowSizeAlphabet()) 1624*f4ee7fbaSAndroid Build Coastguard Worker 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288 1625*f4ee7fbaSAndroid Build Coastguard Worker 4194288 1626*f4ee7fbaSAndroid Build Coastguard Worker """ 1627*f4ee7fbaSAndroid Build Coastguard Worker #TODO 2: verbosity level, e.g. show only codes and maps in header 1628*f4ee7fbaSAndroid Build Coastguard Worker stream = self.stream 1629*f4ee7fbaSAndroid Build Coastguard Worker pos = stream.pos 1630*f4ee7fbaSAndroid Build Coastguard Worker if skipExtra: 1631*f4ee7fbaSAndroid Build Coastguard Worker length, symbol = alphabet.readTuple(stream) 1632*f4ee7fbaSAndroid Build Coastguard Worker extraBits, extra = 0, None 1633*f4ee7fbaSAndroid Build Coastguard Worker else: 1634*f4ee7fbaSAndroid Build Coastguard Worker length, symbol, extraBits, extra = alphabet.readTupleAndExtra( 1635*f4ee7fbaSAndroid Build Coastguard Worker stream) 1636*f4ee7fbaSAndroid Build Coastguard Worker #fields: address, hex data, binary data, name of alphabet, explanation 1637*f4ee7fbaSAndroid Build Coastguard Worker hexdata = self.makeHexData(pos) 1638*f4ee7fbaSAndroid Build Coastguard Worker addressField = '{:04x}'.format(pos+7>>3) if hexdata else '' 1639*f4ee7fbaSAndroid Build Coastguard Worker bitdata = self.formatBitData(pos, length, extraBits) 1640*f4ee7fbaSAndroid Build Coastguard Worker #bitPtr moves bitdata so that the bytes are easier to read 1641*f4ee7fbaSAndroid Build Coastguard Worker #jump back to right if a new byte starts 1642*f4ee7fbaSAndroid Build Coastguard Worker if '|' in bitdata[1:]: 1643*f4ee7fbaSAndroid Build Coastguard Worker #start over on the right side 1644*f4ee7fbaSAndroid Build Coastguard Worker self.bitPtr = self.width 1645*f4ee7fbaSAndroid Build Coastguard Worker fillWidth = self.bitPtr-(len(hexdata)+len(bitdata)) 1646*f4ee7fbaSAndroid Build Coastguard Worker if fillWidth<0: fillWidth = 0 1647*f4ee7fbaSAndroid Build Coastguard Worker print('{:<5s} {:<{}s} {:7s} {}'.format( 1648*f4ee7fbaSAndroid Build Coastguard Worker addressField, 1649*f4ee7fbaSAndroid Build Coastguard Worker hexdata+' '*fillWidth+bitdata, self.width, 1650*f4ee7fbaSAndroid Build Coastguard Worker context+alphabet.name, 1651*f4ee7fbaSAndroid Build Coastguard Worker symbol if skipExtra else symbol.explanation(extra), 1652*f4ee7fbaSAndroid Build Coastguard Worker )) 1653*f4ee7fbaSAndroid Build Coastguard Worker #jump to the right if we started with a '|' 1654*f4ee7fbaSAndroid Build Coastguard Worker #because we didn't jump before printing 1655*f4ee7fbaSAndroid Build Coastguard Worker if bitdata.startswith('|'): self.bitPtr = self.width 1656*f4ee7fbaSAndroid Build Coastguard Worker else: self.bitPtr -= len(bitdata) 1657*f4ee7fbaSAndroid Build Coastguard Worker return symbol if skipExtra else symbol.value(extra) 1658*f4ee7fbaSAndroid Build Coastguard Worker 1659*f4ee7fbaSAndroid Build Coastguard Worker def metablockLength(self): 1660*f4ee7fbaSAndroid Build Coastguard Worker """Read MNIBBLES and meta block length; 1661*f4ee7fbaSAndroid Build Coastguard Worker if empty block, skip block and return true. 1662*f4ee7fbaSAndroid Build Coastguard Worker """ 1663*f4ee7fbaSAndroid Build Coastguard Worker self.MLEN = self.verboseRead(MetablockLengthAlphabet()) 1664*f4ee7fbaSAndroid Build Coastguard Worker if self.MLEN: 1665*f4ee7fbaSAndroid Build Coastguard Worker return False 1666*f4ee7fbaSAndroid Build Coastguard Worker #empty block; skip and return False 1667*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(ReservedAlphabet()) 1668*f4ee7fbaSAndroid Build Coastguard Worker MSKIP = self.verboseRead(SkipLengthAlphabet()) 1669*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(FillerAlphabet(streamPos=self.stream.pos)) 1670*f4ee7fbaSAndroid Build Coastguard Worker self.stream.pos += 8*MSKIP 1671*f4ee7fbaSAndroid Build Coastguard Worker print("Skipping to {:x}".format(self.stream.pos>>3)) 1672*f4ee7fbaSAndroid Build Coastguard Worker return True 1673*f4ee7fbaSAndroid Build Coastguard Worker 1674*f4ee7fbaSAndroid Build Coastguard Worker def uncompressed(self): 1675*f4ee7fbaSAndroid Build Coastguard Worker """If true, handle uncompressed data 1676*f4ee7fbaSAndroid Build Coastguard Worker """ 1677*f4ee7fbaSAndroid Build Coastguard Worker ISUNCOMPRESSED = self.verboseRead( 1678*f4ee7fbaSAndroid Build Coastguard Worker BoolCode('UNCMPR', description='Is uncompressed?')) 1679*f4ee7fbaSAndroid Build Coastguard Worker if ISUNCOMPRESSED: 1680*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(FillerAlphabet(streamPos=self.stream.pos)) 1681*f4ee7fbaSAndroid Build Coastguard Worker print('Uncompressed data:') 1682*f4ee7fbaSAndroid Build Coastguard Worker self.output += self.stream.readBytes(self.MLEN) 1683*f4ee7fbaSAndroid Build Coastguard Worker print(outputFormatter(self.output[-self.MLEN:])) 1684*f4ee7fbaSAndroid Build Coastguard Worker return ISUNCOMPRESSED 1685*f4ee7fbaSAndroid Build Coastguard Worker 1686*f4ee7fbaSAndroid Build Coastguard Worker def blockType(self, kind): 1687*f4ee7fbaSAndroid Build Coastguard Worker """Read block type switch descriptor for given kind of blockType.""" 1688*f4ee7fbaSAndroid Build Coastguard Worker NBLTYPES = self.verboseRead(TypeCountAlphabet( 1689*f4ee7fbaSAndroid Build Coastguard Worker 'BT#'+kind[0].upper(), 1690*f4ee7fbaSAndroid Build Coastguard Worker description='{} block types'.format(kind), 1691*f4ee7fbaSAndroid Build Coastguard Worker )) 1692*f4ee7fbaSAndroid Build Coastguard Worker self.numberOfBlockTypes[kind] = NBLTYPES 1693*f4ee7fbaSAndroid Build Coastguard Worker if NBLTYPES>=2: 1694*f4ee7fbaSAndroid Build Coastguard Worker self.blockTypeCodes[kind] = self.readPrefixCode( 1695*f4ee7fbaSAndroid Build Coastguard Worker BlockTypeAlphabet('BT'+kind[0].upper(), NBLTYPES)) 1696*f4ee7fbaSAndroid Build Coastguard Worker self.blockCountCodes[kind] = self.readPrefixCode( 1697*f4ee7fbaSAndroid Build Coastguard Worker BlockCountAlphabet('BC'+kind[0].upper())) 1698*f4ee7fbaSAndroid Build Coastguard Worker blockCount = self.verboseRead(self.blockCountCodes[kind]) 1699*f4ee7fbaSAndroid Build Coastguard Worker else: 1700*f4ee7fbaSAndroid Build Coastguard Worker blockCount = 1<<24 1701*f4ee7fbaSAndroid Build Coastguard Worker self.currentBlockCounts[kind] = blockCount 1702*f4ee7fbaSAndroid Build Coastguard Worker 1703*f4ee7fbaSAndroid Build Coastguard Worker def readLiteralContextModes(self): 1704*f4ee7fbaSAndroid Build Coastguard Worker """Read literal context modes. 1705*f4ee7fbaSAndroid Build Coastguard Worker LSB6: lower 6 bits of last char 1706*f4ee7fbaSAndroid Build Coastguard Worker MSB6: upper 6 bits of last char 1707*f4ee7fbaSAndroid Build Coastguard Worker UTF8: rougly dependent on categories: 1708*f4ee7fbaSAndroid Build Coastguard Worker upper 4 bits depend on category of last char: 1709*f4ee7fbaSAndroid Build Coastguard Worker control/whitespace/space/ punctuation/quote/%/open/close/ 1710*f4ee7fbaSAndroid Build Coastguard Worker comma/period/=/digits/ VOWEL/CONSONANT/vowel/consonant 1711*f4ee7fbaSAndroid Build Coastguard Worker lower 2 bits depend on category of 2nd last char: 1712*f4ee7fbaSAndroid Build Coastguard Worker space/punctuation/digit or upper/lowercase 1713*f4ee7fbaSAndroid Build Coastguard Worker signed: hamming weight of last 2 chars 1714*f4ee7fbaSAndroid Build Coastguard Worker """ 1715*f4ee7fbaSAndroid Build Coastguard Worker print('Context modes'.center(60, '-')) 1716*f4ee7fbaSAndroid Build Coastguard Worker self.literalContextModes = [] 1717*f4ee7fbaSAndroid Build Coastguard Worker for i in range(self.numberOfBlockTypes[L]): 1718*f4ee7fbaSAndroid Build Coastguard Worker self.literalContextModes.append( 1719*f4ee7fbaSAndroid Build Coastguard Worker self.verboseRead(LiteralContextMode(number=i))) 1720*f4ee7fbaSAndroid Build Coastguard Worker 1721*f4ee7fbaSAndroid Build Coastguard Worker def contextMap(self, kind): 1722*f4ee7fbaSAndroid Build Coastguard Worker """Read context maps 1723*f4ee7fbaSAndroid Build Coastguard Worker Returns the number of differnt values on the context map 1724*f4ee7fbaSAndroid Build Coastguard Worker (In other words, the number of prefix trees) 1725*f4ee7fbaSAndroid Build Coastguard Worker """ 1726*f4ee7fbaSAndroid Build Coastguard Worker NTREES = self.verboseRead(TypeCountAlphabet( 1727*f4ee7fbaSAndroid Build Coastguard Worker kind[0].upper()+'T#', 1728*f4ee7fbaSAndroid Build Coastguard Worker description='{} prefix trees'.format(kind))) 1729*f4ee7fbaSAndroid Build Coastguard Worker mapSize = {L:64, D:4}[kind] 1730*f4ee7fbaSAndroid Build Coastguard Worker if NTREES<2: 1731*f4ee7fbaSAndroid Build Coastguard Worker self.cmaps[kind] = [0]*mapSize 1732*f4ee7fbaSAndroid Build Coastguard Worker else: 1733*f4ee7fbaSAndroid Build Coastguard Worker #read CMAPkind 1734*f4ee7fbaSAndroid Build Coastguard Worker RLEMAX = self.verboseRead(RLEmaxAlphabet( 1735*f4ee7fbaSAndroid Build Coastguard Worker 'RLE#'+kind[0].upper(), 1736*f4ee7fbaSAndroid Build Coastguard Worker description=kind+' context map')) 1737*f4ee7fbaSAndroid Build Coastguard Worker alphabet = TreeAlphabet('CM'+kind[0].upper(), NTREES=NTREES, RLEMAX=RLEMAX) 1738*f4ee7fbaSAndroid Build Coastguard Worker cmapCode = self.readPrefixCode(alphabet) 1739*f4ee7fbaSAndroid Build Coastguard Worker tableSize = mapSize*self.numberOfBlockTypes[kind] 1740*f4ee7fbaSAndroid Build Coastguard Worker cmap = [] 1741*f4ee7fbaSAndroid Build Coastguard Worker while len(cmap)<tableSize: 1742*f4ee7fbaSAndroid Build Coastguard Worker cmapCode.description = 'map {}, entry {}'.format( 1743*f4ee7fbaSAndroid Build Coastguard Worker *divmod(len(cmap), mapSize)) 1744*f4ee7fbaSAndroid Build Coastguard Worker count, value = self.verboseRead(cmapCode) 1745*f4ee7fbaSAndroid Build Coastguard Worker cmap.extend([value]*count) 1746*f4ee7fbaSAndroid Build Coastguard Worker assert len(cmap)==tableSize 1747*f4ee7fbaSAndroid Build Coastguard Worker IMTF = self.verboseRead(BoolCode('IMTF', description='Apply inverse MTF')) 1748*f4ee7fbaSAndroid Build Coastguard Worker if IMTF: 1749*f4ee7fbaSAndroid Build Coastguard Worker self.IMTF(cmap) 1750*f4ee7fbaSAndroid Build Coastguard Worker if kind==L: 1751*f4ee7fbaSAndroid Build Coastguard Worker print('Context maps for literal data:') 1752*f4ee7fbaSAndroid Build Coastguard Worker for i in range(0, len(cmap), 64): 1753*f4ee7fbaSAndroid Build Coastguard Worker print(*( 1754*f4ee7fbaSAndroid Build Coastguard Worker ''.join(map(str, cmap[j:j+8])) 1755*f4ee7fbaSAndroid Build Coastguard Worker for j in range(i, i+64, 8) 1756*f4ee7fbaSAndroid Build Coastguard Worker )) 1757*f4ee7fbaSAndroid Build Coastguard Worker else: 1758*f4ee7fbaSAndroid Build Coastguard Worker print('Context map for distances:') 1759*f4ee7fbaSAndroid Build Coastguard Worker print(*( 1760*f4ee7fbaSAndroid Build Coastguard Worker ''.join(map('{:x}'.format, cmap[i:i+4])) 1761*f4ee7fbaSAndroid Build Coastguard Worker for i in range(0, len(cmap), 4) 1762*f4ee7fbaSAndroid Build Coastguard Worker )) 1763*f4ee7fbaSAndroid Build Coastguard Worker self.cmaps[kind] = cmap 1764*f4ee7fbaSAndroid Build Coastguard Worker return NTREES 1765*f4ee7fbaSAndroid Build Coastguard Worker 1766*f4ee7fbaSAndroid Build Coastguard Worker @staticmethod 1767*f4ee7fbaSAndroid Build Coastguard Worker def IMTF(v): 1768*f4ee7fbaSAndroid Build Coastguard Worker """In place inverse move to front transform. 1769*f4ee7fbaSAndroid Build Coastguard Worker """ 1770*f4ee7fbaSAndroid Build Coastguard Worker #mtf is initialized virtually with range(infinity) 1771*f4ee7fbaSAndroid Build Coastguard Worker mtf = [] 1772*f4ee7fbaSAndroid Build Coastguard Worker for i, vi in enumerate(v): 1773*f4ee7fbaSAndroid Build Coastguard Worker #get old value from mtf. If never seen, take virtual value 1774*f4ee7fbaSAndroid Build Coastguard Worker try: value = mtf.pop(vi) 1775*f4ee7fbaSAndroid Build Coastguard Worker except IndexError: value = vi 1776*f4ee7fbaSAndroid Build Coastguard Worker #put value at front 1777*f4ee7fbaSAndroid Build Coastguard Worker mtf.insert(0, value) 1778*f4ee7fbaSAndroid Build Coastguard Worker #replace transformed value 1779*f4ee7fbaSAndroid Build Coastguard Worker v[i] = value 1780*f4ee7fbaSAndroid Build Coastguard Worker 1781*f4ee7fbaSAndroid Build Coastguard Worker def readPrefixArray(self, kind, numberOfTrees): 1782*f4ee7fbaSAndroid Build Coastguard Worker """Read prefix code array""" 1783*f4ee7fbaSAndroid Build Coastguard Worker prefixes = [] 1784*f4ee7fbaSAndroid Build Coastguard Worker for i in range(numberOfTrees): 1785*f4ee7fbaSAndroid Build Coastguard Worker if kind==L: alphabet = LiteralAlphabet(i) 1786*f4ee7fbaSAndroid Build Coastguard Worker elif kind==I: alphabet = InsertAndCopyAlphabet(i) 1787*f4ee7fbaSAndroid Build Coastguard Worker elif kind==D: alphabet = DistanceAlphabet( 1788*f4ee7fbaSAndroid Build Coastguard Worker i, NPOSTFIX=self.NPOSTFIX, NDIRECT=self.NDIRECT) 1789*f4ee7fbaSAndroid Build Coastguard Worker self.readPrefixCode(alphabet) 1790*f4ee7fbaSAndroid Build Coastguard Worker prefixes.append(alphabet) 1791*f4ee7fbaSAndroid Build Coastguard Worker self.prefixCodes[kind] = prefixes 1792*f4ee7fbaSAndroid Build Coastguard Worker 1793*f4ee7fbaSAndroid Build Coastguard Worker #metablock data 1794*f4ee7fbaSAndroid Build Coastguard Worker def metablock(self): 1795*f4ee7fbaSAndroid Build Coastguard Worker """Process the data. 1796*f4ee7fbaSAndroid Build Coastguard Worker Relevant variables of self: 1797*f4ee7fbaSAndroid Build Coastguard Worker numberOfBlockTypes[kind]: number of block types 1798*f4ee7fbaSAndroid Build Coastguard Worker currentBlockTypes[kind]: current block types (=0) 1799*f4ee7fbaSAndroid Build Coastguard Worker literalContextModes: the context modes for the literal block types 1800*f4ee7fbaSAndroid Build Coastguard Worker currentBlockCounts[kind]: counters for block types 1801*f4ee7fbaSAndroid Build Coastguard Worker blockTypeCodes[kind]: code for block type 1802*f4ee7fbaSAndroid Build Coastguard Worker blockCountCodes[kind]: code for block count 1803*f4ee7fbaSAndroid Build Coastguard Worker cmaps[kind]: the context maps (not for I) 1804*f4ee7fbaSAndroid Build Coastguard Worker prefixCodes[kind][#]: the prefix codes 1805*f4ee7fbaSAndroid Build Coastguard Worker lastDistances: the last four distances 1806*f4ee7fbaSAndroid Build Coastguard Worker lastChars: the last two chars 1807*f4ee7fbaSAndroid Build Coastguard Worker output: the result 1808*f4ee7fbaSAndroid Build Coastguard Worker """ 1809*f4ee7fbaSAndroid Build Coastguard Worker print('Meta block contents'.center(60, '=')) 1810*f4ee7fbaSAndroid Build Coastguard Worker self.currentBlockTypes = {L:0, I:0, D:0, pL:1, pI:1, pD:1} 1811*f4ee7fbaSAndroid Build Coastguard Worker self.lastDistances = deque([17,16,11,4], maxlen=4) 1812*f4ee7fbaSAndroid Build Coastguard Worker #the current context mode is for block type 0 1813*f4ee7fbaSAndroid Build Coastguard Worker self.contextMode = ContextModeKeeper(self.literalContextModes[0]) 1814*f4ee7fbaSAndroid Build Coastguard Worker wordList = WordList() 1815*f4ee7fbaSAndroid Build Coastguard Worker 1816*f4ee7fbaSAndroid Build Coastguard Worker #setup distance callback function 1817*f4ee7fbaSAndroid Build Coastguard Worker def distanceCallback(symbol, extra): 1818*f4ee7fbaSAndroid Build Coastguard Worker "callback function for displaying decoded distance" 1819*f4ee7fbaSAndroid Build Coastguard Worker index, offset = symbol.value(extra) 1820*f4ee7fbaSAndroid Build Coastguard Worker if index: 1821*f4ee7fbaSAndroid Build Coastguard Worker #recent distance 1822*f4ee7fbaSAndroid Build Coastguard Worker distance = self.lastDistances[-index]+offset 1823*f4ee7fbaSAndroid Build Coastguard Worker return 'Distance: {}last{:+d}={}'.format(index, offset, distance) 1824*f4ee7fbaSAndroid Build Coastguard Worker #absolute value 1825*f4ee7fbaSAndroid Build Coastguard Worker if offset<=maxDistance: 1826*f4ee7fbaSAndroid Build Coastguard Worker return 'Absolute value: {} (pos {})'.format(offset, maxDistance-offset) 1827*f4ee7fbaSAndroid Build Coastguard Worker #word list value 1828*f4ee7fbaSAndroid Build Coastguard Worker action, word = divmod(offset-maxDistance, 1<<wordList.NDBITS[copyLen]) 1829*f4ee7fbaSAndroid Build Coastguard Worker return '{}-{} gives word {},{} action {}'.format( 1830*f4ee7fbaSAndroid Build Coastguard Worker offset, maxDistance, copyLen, word, action) 1831*f4ee7fbaSAndroid Build Coastguard Worker for dpc in self.prefixCodes[D]: dpc.callback = distanceCallback 1832*f4ee7fbaSAndroid Build Coastguard Worker 1833*f4ee7fbaSAndroid Build Coastguard Worker blockLen = 0 1834*f4ee7fbaSAndroid Build Coastguard Worker #there we go 1835*f4ee7fbaSAndroid Build Coastguard Worker while blockLen<self.MLEN: 1836*f4ee7fbaSAndroid Build Coastguard Worker #get insert© command 1837*f4ee7fbaSAndroid Build Coastguard Worker litLen, copyLen, dist0Flag = self.verboseRead( 1838*f4ee7fbaSAndroid Build Coastguard Worker self.prefixCodes[I][ 1839*f4ee7fbaSAndroid Build Coastguard Worker self.figureBlockType(I)]) 1840*f4ee7fbaSAndroid Build Coastguard Worker #literal data 1841*f4ee7fbaSAndroid Build Coastguard Worker for i in range(litLen): 1842*f4ee7fbaSAndroid Build Coastguard Worker bt = self.figureBlockType(L) 1843*f4ee7fbaSAndroid Build Coastguard Worker cm = self.contextMode.getIndex() 1844*f4ee7fbaSAndroid Build Coastguard Worker ct = self.cmaps[L][bt<<6|cm] 1845*f4ee7fbaSAndroid Build Coastguard Worker char = self.verboseRead( 1846*f4ee7fbaSAndroid Build Coastguard Worker self.prefixCodes[L][ct], 1847*f4ee7fbaSAndroid Build Coastguard Worker context='{},{}='.format(bt,cm)) 1848*f4ee7fbaSAndroid Build Coastguard Worker self.contextMode.add(char) 1849*f4ee7fbaSAndroid Build Coastguard Worker self.output.append(char) 1850*f4ee7fbaSAndroid Build Coastguard Worker blockLen += litLen 1851*f4ee7fbaSAndroid Build Coastguard Worker #check if we're done 1852*f4ee7fbaSAndroid Build Coastguard Worker if blockLen>=self.MLEN: return 1853*f4ee7fbaSAndroid Build Coastguard Worker #distance 1854*f4ee7fbaSAndroid Build Coastguard Worker #distances are computed relative to output length, at most window size 1855*f4ee7fbaSAndroid Build Coastguard Worker maxDistance = min(len(self.output), self.windowSize) 1856*f4ee7fbaSAndroid Build Coastguard Worker if dist0Flag: 1857*f4ee7fbaSAndroid Build Coastguard Worker distance = self.lastDistances[-1] 1858*f4ee7fbaSAndroid Build Coastguard Worker else: 1859*f4ee7fbaSAndroid Build Coastguard Worker bt = self.figureBlockType(D) 1860*f4ee7fbaSAndroid Build Coastguard Worker cm = {2:0, 3:1, 4:2}.get(copyLen, 3) 1861*f4ee7fbaSAndroid Build Coastguard Worker ct = self.cmaps[D][bt<<2|cm] 1862*f4ee7fbaSAndroid Build Coastguard Worker index, offset = self.verboseRead( 1863*f4ee7fbaSAndroid Build Coastguard Worker self.prefixCodes[D][ct], 1864*f4ee7fbaSAndroid Build Coastguard Worker context='{},{}='.format(bt,cm)) 1865*f4ee7fbaSAndroid Build Coastguard Worker distance = self.lastDistances[-index]+offset if index else offset 1866*f4ee7fbaSAndroid Build Coastguard Worker if index==1 and offset==0: 1867*f4ee7fbaSAndroid Build Coastguard Worker #to make sure distance is not put in last distance list 1868*f4ee7fbaSAndroid Build Coastguard Worker dist0Flag = True 1869*f4ee7fbaSAndroid Build Coastguard Worker if distance<=maxDistance: 1870*f4ee7fbaSAndroid Build Coastguard Worker #copy from output 1871*f4ee7fbaSAndroid Build Coastguard Worker for i in range( 1872*f4ee7fbaSAndroid Build Coastguard Worker maxDistance-distance, 1873*f4ee7fbaSAndroid Build Coastguard Worker maxDistance-distance+copyLen): 1874*f4ee7fbaSAndroid Build Coastguard Worker self.output.append(self.output[i]) 1875*f4ee7fbaSAndroid Build Coastguard Worker if not dist0Flag: self.lastDistances.append(distance) 1876*f4ee7fbaSAndroid Build Coastguard Worker comment = 'Seen before' 1877*f4ee7fbaSAndroid Build Coastguard Worker else: 1878*f4ee7fbaSAndroid Build Coastguard Worker #fetch from wordlist 1879*f4ee7fbaSAndroid Build Coastguard Worker newWord = wordList.word(copyLen, distance-maxDistance-1) 1880*f4ee7fbaSAndroid Build Coastguard Worker self.output.extend(newWord) 1881*f4ee7fbaSAndroid Build Coastguard Worker #adjust copyLen to reflect actual new data 1882*f4ee7fbaSAndroid Build Coastguard Worker copyLen = len(newWord) 1883*f4ee7fbaSAndroid Build Coastguard Worker comment = 'From wordlist' 1884*f4ee7fbaSAndroid Build Coastguard Worker blockLen += copyLen 1885*f4ee7fbaSAndroid Build Coastguard Worker print(' '*40, 1886*f4ee7fbaSAndroid Build Coastguard Worker comment, 1887*f4ee7fbaSAndroid Build Coastguard Worker ': "', 1888*f4ee7fbaSAndroid Build Coastguard Worker outputFormatter(self.output[-copyLen:]), 1889*f4ee7fbaSAndroid Build Coastguard Worker '"', 1890*f4ee7fbaSAndroid Build Coastguard Worker sep='') 1891*f4ee7fbaSAndroid Build Coastguard Worker self.contextMode.add(self.output[-2]) 1892*f4ee7fbaSAndroid Build Coastguard Worker self.contextMode.add(self.output[-1]) 1893*f4ee7fbaSAndroid Build Coastguard Worker 1894*f4ee7fbaSAndroid Build Coastguard Worker def figureBlockType(self, kind): 1895*f4ee7fbaSAndroid Build Coastguard Worker counts, types = self.currentBlockCounts, self.currentBlockTypes 1896*f4ee7fbaSAndroid Build Coastguard Worker if counts[kind]==0: 1897*f4ee7fbaSAndroid Build Coastguard Worker newType = self.verboseRead(self.blockTypeCodes[kind]) 1898*f4ee7fbaSAndroid Build Coastguard Worker if newType==-2: newType = types['P'+kind] 1899*f4ee7fbaSAndroid Build Coastguard Worker elif newType==-1: 1900*f4ee7fbaSAndroid Build Coastguard Worker newType = (types[kind]+1)%self.numberOfBlockTypes[kind] 1901*f4ee7fbaSAndroid Build Coastguard Worker types['P'+kind] = types[kind] 1902*f4ee7fbaSAndroid Build Coastguard Worker types[kind] = newType 1903*f4ee7fbaSAndroid Build Coastguard Worker counts[kind] = self.verboseRead(self.blockCountCodes[kind]) 1904*f4ee7fbaSAndroid Build Coastguard Worker counts[kind] -=1 1905*f4ee7fbaSAndroid Build Coastguard Worker return types[kind] 1906*f4ee7fbaSAndroid Build Coastguard Worker 1907*f4ee7fbaSAndroid Build Coastguard Worker__test__ = { 1908*f4ee7fbaSAndroid Build Coastguard Worker'BitStream': """ 1909*f4ee7fbaSAndroid Build Coastguard Worker >>> bs = BitStream(b'Jurjen') 1910*f4ee7fbaSAndroid Build Coastguard Worker >>> bs.readBytes(2) 1911*f4ee7fbaSAndroid Build Coastguard Worker b'Ju' 1912*f4ee7fbaSAndroid Build Coastguard Worker >>> bs.read(6) #r=01110010 1913*f4ee7fbaSAndroid Build Coastguard Worker 50 1914*f4ee7fbaSAndroid Build Coastguard Worker >>> bs 1915*f4ee7fbaSAndroid Build Coastguard Worker BitStream(pos=2:6) 1916*f4ee7fbaSAndroid Build Coastguard Worker >>> bs.peek(5) #j=01101010 1917*f4ee7fbaSAndroid Build Coastguard Worker 9 1918*f4ee7fbaSAndroid Build Coastguard Worker >>> bs.readBytes(2) 1919*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 1920*f4ee7fbaSAndroid Build Coastguard Worker ... 1921*f4ee7fbaSAndroid Build Coastguard Worker ValueError: readBytes: need byte boundary 1922*f4ee7fbaSAndroid Build Coastguard Worker """, 1923*f4ee7fbaSAndroid Build Coastguard Worker 1924*f4ee7fbaSAndroid Build Coastguard Worker'Symbol': """ 1925*f4ee7fbaSAndroid Build Coastguard Worker >>> a=Symbol(MetablockLengthAlphabet(),5) 1926*f4ee7fbaSAndroid Build Coastguard Worker >>> len(a) 1927*f4ee7fbaSAndroid Build Coastguard Worker 2 1928*f4ee7fbaSAndroid Build Coastguard Worker >>> int(a) 1929*f4ee7fbaSAndroid Build Coastguard Worker 5 1930*f4ee7fbaSAndroid Build Coastguard Worker >>> a.bitPattern() 1931*f4ee7fbaSAndroid Build Coastguard Worker '01' 1932*f4ee7fbaSAndroid Build Coastguard Worker >>> a.value(200000) 1933*f4ee7fbaSAndroid Build Coastguard Worker 200001 1934*f4ee7fbaSAndroid Build Coastguard Worker >>> a.explanation(300000) 1935*f4ee7fbaSAndroid Build Coastguard Worker 'data length: 493e0h+1=300001' 1936*f4ee7fbaSAndroid Build Coastguard Worker """, 1937*f4ee7fbaSAndroid Build Coastguard Worker 1938*f4ee7fbaSAndroid Build Coastguard Worker'RangeDecoder': """ 1939*f4ee7fbaSAndroid Build Coastguard Worker >>> a=RangeDecoder(bitLength=3) 1940*f4ee7fbaSAndroid Build Coastguard Worker >>> len(a) 1941*f4ee7fbaSAndroid Build Coastguard Worker 8 1942*f4ee7fbaSAndroid Build Coastguard Worker >>> a.name='t' 1943*f4ee7fbaSAndroid Build Coastguard Worker >>> list(a) 1944*f4ee7fbaSAndroid Build Coastguard Worker [Symbol(t, 0), Symbol(t, 1), Symbol(t, 2), Symbol(t, 3), Symbol(t, 4), Symbol(t, 5), Symbol(t, 6), Symbol(t, 7)] 1945*f4ee7fbaSAndroid Build Coastguard Worker >>> a[2] 1946*f4ee7fbaSAndroid Build Coastguard Worker Symbol(t, 2) 1947*f4ee7fbaSAndroid Build Coastguard Worker >>> a.bitPattern(4) 1948*f4ee7fbaSAndroid Build Coastguard Worker '100' 1949*f4ee7fbaSAndroid Build Coastguard Worker >>> a.length(2) 1950*f4ee7fbaSAndroid Build Coastguard Worker 3 1951*f4ee7fbaSAndroid Build Coastguard Worker >>> a.decodePeek(15) 1952*f4ee7fbaSAndroid Build Coastguard Worker (3, Symbol(t, 7)) 1953*f4ee7fbaSAndroid Build Coastguard Worker >>> 1954*f4ee7fbaSAndroid Build Coastguard Worker 1955*f4ee7fbaSAndroid Build Coastguard Worker """, 1956*f4ee7fbaSAndroid Build Coastguard Worker 1957*f4ee7fbaSAndroid Build Coastguard Worker'PrefixDecoder': """ 1958*f4ee7fbaSAndroid Build Coastguard Worker >>> a=PrefixDecoder(decodeTable={0:1,1:2,3:3,7:4}) 1959*f4ee7fbaSAndroid Build Coastguard Worker >>> len(a) 1960*f4ee7fbaSAndroid Build Coastguard Worker 4 1961*f4ee7fbaSAndroid Build Coastguard Worker >>> a.name='t' 1962*f4ee7fbaSAndroid Build Coastguard Worker >>> list(a) 1963*f4ee7fbaSAndroid Build Coastguard Worker [Symbol(t, 1), Symbol(t, 2), Symbol(t, 3), Symbol(t, 4)] 1964*f4ee7fbaSAndroid Build Coastguard Worker >>> a.decodePeek(22) 1965*f4ee7fbaSAndroid Build Coastguard Worker (1, Symbol(t, 1)) 1966*f4ee7fbaSAndroid Build Coastguard Worker >>> a.decodePeek(27) 1967*f4ee7fbaSAndroid Build Coastguard Worker (3, Symbol(t, 3)) 1968*f4ee7fbaSAndroid Build Coastguard Worker >>> a.length(1) 1969*f4ee7fbaSAndroid Build Coastguard Worker 1 1970*f4ee7fbaSAndroid Build Coastguard Worker >>> a.length(4) 1971*f4ee7fbaSAndroid Build Coastguard Worker 3 1972*f4ee7fbaSAndroid Build Coastguard Worker """, 1973*f4ee7fbaSAndroid Build Coastguard Worker 1974*f4ee7fbaSAndroid Build Coastguard Worker'Code': """ 1975*f4ee7fbaSAndroid Build Coastguard Worker >>> a=Code('t',alphabetSize=10) 1976*f4ee7fbaSAndroid Build Coastguard Worker >>> len(a) 1977*f4ee7fbaSAndroid Build Coastguard Worker 10 1978*f4ee7fbaSAndroid Build Coastguard Worker >>> a.showCode() 1979*f4ee7fbaSAndroid Build Coastguard Worker 0000:0 0001:1 0010:2 0011:3 0100:4 0101:5 0110:6 0111:7 1000:8 1001:9 1980*f4ee7fbaSAndroid Build Coastguard Worker >>> a.setLength({2:1,3:2,5:3,6:3}) 1981*f4ee7fbaSAndroid Build Coastguard Worker >>> a.showCode() 1982*f4ee7fbaSAndroid Build Coastguard Worker 0:2 01:3 011:5 111:6 1983*f4ee7fbaSAndroid Build Coastguard Worker >>> len(a) 1984*f4ee7fbaSAndroid Build Coastguard Worker 4 1985*f4ee7fbaSAndroid Build Coastguard Worker >>> def callback(i): return 'call{}back'.format(i) 1986*f4ee7fbaSAndroid Build Coastguard Worker >>> a=Code('t',callback=callback,bitLength=3) 1987*f4ee7fbaSAndroid Build Coastguard Worker >>> a[6].explanation() 1988*f4ee7fbaSAndroid Build Coastguard Worker 'call6back' 1989*f4ee7fbaSAndroid Build Coastguard Worker """, 1990*f4ee7fbaSAndroid Build Coastguard Worker 1991*f4ee7fbaSAndroid Build Coastguard Worker'WithExtra': """ 1992*f4ee7fbaSAndroid Build Coastguard Worker >>> class A(WithExtra): 1993*f4ee7fbaSAndroid Build Coastguard Worker ... extraTable = [0,1,1,2,2] 1994*f4ee7fbaSAndroid Build Coastguard Worker >>> a=A('t',alphabetSize=5) 1995*f4ee7fbaSAndroid Build Coastguard Worker >>> a[1] 1996*f4ee7fbaSAndroid Build Coastguard Worker Symbol(t, 1) 1997*f4ee7fbaSAndroid Build Coastguard Worker >>> a.extraBits(2) 1998*f4ee7fbaSAndroid Build Coastguard Worker 1 1999*f4ee7fbaSAndroid Build Coastguard Worker >>> a.mnemonic(4) 2000*f4ee7fbaSAndroid Build Coastguard Worker '4' 2001*f4ee7fbaSAndroid Build Coastguard Worker >>> a.readTupleAndExtra(BitStream(b'\x5b')) 2002*f4ee7fbaSAndroid Build Coastguard Worker (3, Symbol(t, 3), 2, 3) 2003*f4ee7fbaSAndroid Build Coastguard Worker """, 2004*f4ee7fbaSAndroid Build Coastguard Worker 2005*f4ee7fbaSAndroid Build Coastguard Worker'BoolCode': """ 2006*f4ee7fbaSAndroid Build Coastguard Worker >>> BoolCode('test')[0].explanation() 2007*f4ee7fbaSAndroid Build Coastguard Worker '0: False' 2008*f4ee7fbaSAndroid Build Coastguard Worker """, 2009*f4ee7fbaSAndroid Build Coastguard Worker 2010*f4ee7fbaSAndroid Build Coastguard Worker'Enumerator': """ 2011*f4ee7fbaSAndroid Build Coastguard Worker >>> class A(Enumerator): 2012*f4ee7fbaSAndroid Build Coastguard Worker ... extraTable = [0,1,1,2,2] 2013*f4ee7fbaSAndroid Build Coastguard Worker ... value0=3 2014*f4ee7fbaSAndroid Build Coastguard Worker >>> a=A(alphabetLength=5) 2015*f4ee7fbaSAndroid Build Coastguard Worker >>> a.value(3) 2016*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 2017*f4ee7fbaSAndroid Build Coastguard Worker ... 2018*f4ee7fbaSAndroid Build Coastguard Worker TypeError: value() missing 1 required positional argument: 'extra' 2019*f4ee7fbaSAndroid Build Coastguard Worker >>> a.explanation(3,4) 2020*f4ee7fbaSAndroid Build Coastguard Worker 'xx 011: 8-11; 8+4=12' 2021*f4ee7fbaSAndroid Build Coastguard Worker """, 2022*f4ee7fbaSAndroid Build Coastguard Worker 2023*f4ee7fbaSAndroid Build Coastguard Worker'WindowSizeAlphabet': """ 2024*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet = WindowSizeAlphabet() 2025*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[0] 2026*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 2027*f4ee7fbaSAndroid Build Coastguard Worker ... 2028*f4ee7fbaSAndroid Build Coastguard Worker ValueError: No symbol WindowSizeAlphabet[0] 2029*f4ee7fbaSAndroid Build Coastguard Worker >>> len(windowSizeAlphabet) 2030*f4ee7fbaSAndroid Build Coastguard Worker 16 2031*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[21] 2032*f4ee7fbaSAndroid Build Coastguard Worker Symbol(WSIZE, 21) 2033*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[21].bitPattern() 2034*f4ee7fbaSAndroid Build Coastguard Worker '1001' 2035*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[21].extraBits() 2036*f4ee7fbaSAndroid Build Coastguard Worker 0 2037*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[21].index 2038*f4ee7fbaSAndroid Build Coastguard Worker 21 2039*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[10].value() 2040*f4ee7fbaSAndroid Build Coastguard Worker 1008 2041*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet[10].explanation() 2042*f4ee7fbaSAndroid Build Coastguard Worker 'windowsize=(1<<10)-16=1008' 2043*f4ee7fbaSAndroid Build Coastguard Worker >>> windowSizeAlphabet.showCode() 2044*f4ee7fbaSAndroid Build Coastguard Worker 0:65520 1100001:16368 1110001:32752 0011:262128 2045*f4ee7fbaSAndroid Build Coastguard Worker 0000001:131056 0010001:None 1001:2097136 1011:4194288 2046*f4ee7fbaSAndroid Build Coastguard Worker 1000001:4080 1010001:8176 0101:524272 0111:1048560 2047*f4ee7fbaSAndroid Build Coastguard Worker 0100001:1008 0110001:2032 1101:8388592 1111:16777200 2048*f4ee7fbaSAndroid Build Coastguard Worker """, 2049*f4ee7fbaSAndroid Build Coastguard Worker 2050*f4ee7fbaSAndroid Build Coastguard Worker'TypeCountAlphabet': """ 2051*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet = TypeCountAlphabet(description='bananas') 2052*f4ee7fbaSAndroid Build Coastguard Worker >>> len(typeCountAlphabet) 2053*f4ee7fbaSAndroid Build Coastguard Worker 9 2054*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet[3] 2055*f4ee7fbaSAndroid Build Coastguard Worker Symbol(BT#, 3) 2056*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet[9] 2057*f4ee7fbaSAndroid Build Coastguard Worker Traceback (most recent call last): 2058*f4ee7fbaSAndroid Build Coastguard Worker ... 2059*f4ee7fbaSAndroid Build Coastguard Worker ValueError: No symbol TypeCountAlphabet[9] 2060*f4ee7fbaSAndroid Build Coastguard Worker >>> print(typeCountAlphabet[3]) 2061*f4ee7fbaSAndroid Build Coastguard Worker xx,0101 2062*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet[8].value(127) 2063*f4ee7fbaSAndroid Build Coastguard Worker 256 2064*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet[4].explanation(2) 2065*f4ee7fbaSAndroid Build Coastguard Worker 'xxx,0111: 11 bananas' 2066*f4ee7fbaSAndroid Build Coastguard Worker >>> typeCountAlphabet[0].explanation() 2067*f4ee7fbaSAndroid Build Coastguard Worker '0: 1 banana' 2068*f4ee7fbaSAndroid Build Coastguard Worker """, 2069*f4ee7fbaSAndroid Build Coastguard Worker 2070*f4ee7fbaSAndroid Build Coastguard Worker'DistanceParamAlphabet': """ 2071*f4ee7fbaSAndroid Build Coastguard Worker >>> dpa = DistanceParamAlphabet() 2072*f4ee7fbaSAndroid Build Coastguard Worker >>> dpa.showCode() 2073*f4ee7fbaSAndroid Build Coastguard Worker 00:PF0 01:PF1 10:PF2 11:PF3 2074*f4ee7fbaSAndroid Build Coastguard Worker >>> dpa.readTupleAndExtra(BitStream(b'\\x29')) 2075*f4ee7fbaSAndroid Build Coastguard Worker (2, Symbol(DIST, 1), 4, 10) 2076*f4ee7fbaSAndroid Build Coastguard Worker >>> dpa.explanation(2, 5) 2077*f4ee7fbaSAndroid Build Coastguard Worker '2 postfix bits and 0101<<2=20 direct codes' 2078*f4ee7fbaSAndroid Build Coastguard Worker """, 2079*f4ee7fbaSAndroid Build Coastguard Worker 2080*f4ee7fbaSAndroid Build Coastguard Worker'LiteralAlphabet': """ 2081*f4ee7fbaSAndroid Build Coastguard Worker >>> LiteralAlphabet(-1).showCode() #doctest: +ELLIPSIS 2082*f4ee7fbaSAndroid Build Coastguard Worker 00000000:\\x00 00110100:4 01101000:h 10011100:\\x9c 11010000:\\xd0 2083*f4ee7fbaSAndroid Build Coastguard Worker 00000001:\\x01 00110101:5 01101001:i 10011101:\\x9d 11010001:\\xd1 2084*f4ee7fbaSAndroid Build Coastguard Worker 00000010:\\x02 00110110:6 01101010:j 10011110:\\x9e 11010010:\\xd2 2085*f4ee7fbaSAndroid Build Coastguard Worker ... 2086*f4ee7fbaSAndroid Build Coastguard Worker 00101111:/ 01100011:c 10010111:\\x97 11001011:\\xcb 11111111:\\xff 2087*f4ee7fbaSAndroid Build Coastguard Worker 00110000:0 01100100:d 10011000:\\x98 11001100:\\xcc 2088*f4ee7fbaSAndroid Build Coastguard Worker 00110001:1 01100101:e 10011001:\\x99 11001101:\\xcd 2089*f4ee7fbaSAndroid Build Coastguard Worker 00110010:2 01100110:f 10011010:\\x9a 11001110:\\xce 2090*f4ee7fbaSAndroid Build Coastguard Worker 00110011:3 01100111:g 10011011:\\x9b 11001111:\\xcf 2091*f4ee7fbaSAndroid Build Coastguard Worker """, 2092*f4ee7fbaSAndroid Build Coastguard Worker 2093*f4ee7fbaSAndroid Build Coastguard Worker'BlockCountAlphabet': """ 2094*f4ee7fbaSAndroid Build Coastguard Worker >>> bc=BlockCountAlphabet('BCL') 2095*f4ee7fbaSAndroid Build Coastguard Worker >>> len(bc) 2096*f4ee7fbaSAndroid Build Coastguard Worker 26 2097*f4ee7fbaSAndroid Build Coastguard Worker >>> bs=BitStream(b'\\x40\\x83\\xc8\\x59\\12\\x02') 2098*f4ee7fbaSAndroid Build Coastguard Worker >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3]) 2099*f4ee7fbaSAndroid Build Coastguard Worker 'Block count: xx 00000: 1-4; 1+2=3' 2100*f4ee7fbaSAndroid Build Coastguard Worker >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3]) 2101*f4ee7fbaSAndroid Build Coastguard Worker 'Block count: xxx 00110: 33-40; 33+0=33' 2102*f4ee7fbaSAndroid Build Coastguard Worker >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3]) 2103*f4ee7fbaSAndroid Build Coastguard Worker 'Block count: xxxxxx 10001: 305-368; 305+28=333' 2104*f4ee7fbaSAndroid Build Coastguard Worker >>> x = bc.readTupleAndExtra(bs); x[1].explanation(x[3]) 2105*f4ee7fbaSAndroid Build Coastguard Worker 'Block count: xxxxxxxxxxx 10110: 2289-4336; 2289+1044=3333' 2106*f4ee7fbaSAndroid Build Coastguard Worker """, 2107*f4ee7fbaSAndroid Build Coastguard Worker 2108*f4ee7fbaSAndroid Build Coastguard Worker'Layout': """ 2109*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.pos = 0 2110*f4ee7fbaSAndroid Build Coastguard Worker >>> l = Layout(olleke) 2111*f4ee7fbaSAndroid Build Coastguard Worker >>> l.verboseRead(WindowSizeAlphabet()) 2112*f4ee7fbaSAndroid Build Coastguard Worker 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288 2113*f4ee7fbaSAndroid Build Coastguard Worker 4194288 2114*f4ee7fbaSAndroid Build Coastguard Worker >>> l.verboseRead(BoolCode('LAST', description="Last block")) 2115*f4ee7fbaSAndroid Build Coastguard Worker 1 LAST Last block: 1: True 2116*f4ee7fbaSAndroid Build Coastguard Worker True 2117*f4ee7fbaSAndroid Build Coastguard Worker >>> l.verboseRead(BoolCode('EMPTY', description="Empty block")) 2118*f4ee7fbaSAndroid Build Coastguard Worker 0 EMPTY Empty block: 0: False 2119*f4ee7fbaSAndroid Build Coastguard Worker False 2120*f4ee7fbaSAndroid Build Coastguard Worker >>> l.verboseRead(MetablockLengthAlphabet()) 2121*f4ee7fbaSAndroid Build Coastguard Worker 0001 2e 00 |00h|2Eh,|00 MLEN data length: 002eh+1=47 2122*f4ee7fbaSAndroid Build Coastguard Worker 47 2123*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.pos = 76 2124*f4ee7fbaSAndroid Build Coastguard Worker >>> l = Layout(olleke) 2125*f4ee7fbaSAndroid Build Coastguard Worker >>> x = l.verboseRead(DistanceAlphabet(0,NPOSTFIX=0,NDIRECT=0), skipExtra=True) 2126*f4ee7fbaSAndroid Build Coastguard Worker 000a 82 10|1100 D0 10[15*x]-3 2127*f4ee7fbaSAndroid Build Coastguard Worker >>> x.explanation(0x86a3) 2128*f4ee7fbaSAndroid Build Coastguard Worker '10[1000011010100011]-3: [0]+100000' 2129*f4ee7fbaSAndroid Build Coastguard Worker """, 2130*f4ee7fbaSAndroid Build Coastguard Worker 2131*f4ee7fbaSAndroid Build Coastguard Worker'olleke': """ 2132*f4ee7fbaSAndroid Build Coastguard Worker >>> olleke.pos = 0 2133*f4ee7fbaSAndroid Build Coastguard Worker >>> try: Layout(olleke).processStream() 2134*f4ee7fbaSAndroid Build Coastguard Worker ... except NotImplementedError: pass 2135*f4ee7fbaSAndroid Build Coastguard Worker ... #doctest: +REPORT_NDIFF 2136*f4ee7fbaSAndroid Build Coastguard Worker addr hex binary context explanation 2137*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Stream header------------------------ 2138*f4ee7fbaSAndroid Build Coastguard Worker 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288 2139*f4ee7fbaSAndroid Build Coastguard Worker ======================Metablock header====================== 2140*f4ee7fbaSAndroid Build Coastguard Worker 1 LAST Last block: 1: True 2141*f4ee7fbaSAndroid Build Coastguard Worker 0 EMPTY Empty block: 0: False 2142*f4ee7fbaSAndroid Build Coastguard Worker 0001 2e 00 |00h|2Eh,|00 MLEN data length: 002eh+1=47 2143*f4ee7fbaSAndroid Build Coastguard Worker -------------------Block type descriptors------------------- 2144*f4ee7fbaSAndroid Build Coastguard Worker 0003 00 0 BT#L 0: 1 literal block type 2145*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#I 0: 1 insert© block type 2146*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#D 0: 1 distance block type 2147*f4ee7fbaSAndroid Build Coastguard Worker ------------------Distance code parameters------------------ 2148*f4ee7fbaSAndroid Build Coastguard Worker 0004 44 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes 2149*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Context modes------------------------ 2150*f4ee7fbaSAndroid Build Coastguard Worker 10 LC0 Context mode for type 0: 2(UTF8) 2151*f4ee7fbaSAndroid Build Coastguard Worker ------------------------Context maps------------------------ 2152*f4ee7fbaSAndroid Build Coastguard Worker 0 LT# 0: 1 literal prefix tree 2153*f4ee7fbaSAndroid Build Coastguard Worker 0 DT# 0: 1 distance prefix tree 2154*f4ee7fbaSAndroid Build Coastguard Worker ---------------------Prefix code lists---------------------- 2155*f4ee7fbaSAndroid Build Coastguard Worker 10 PFX L0 is complex with lengths 3,4,0,5,17... 2156*f4ee7fbaSAndroid Build Coastguard Worker 0005 4f 1|0 ##L0 len 3: coded with 3 bits 2157*f4ee7fbaSAndroid Build Coastguard Worker 0111 ##L0 len 4: coded with 1 bits 2158*f4ee7fbaSAndroid Build Coastguard Worker 10 ##L0 unused: coded with 3 bits 2159*f4ee7fbaSAndroid Build Coastguard Worker 0006 d6 0|0 ##L0 len 5: skipped 2160*f4ee7fbaSAndroid Build Coastguard Worker 011 ##L0 zero xxx: coded with 2 bits 2161*f4ee7fbaSAndroid Build Coastguard Worker ***** Lengths for L0 will be coded as: 2162*f4ee7fbaSAndroid Build Coastguard Worker 0:len 4 01:zero xxx 011:unused 111:len 3 2163*f4ee7fbaSAndroid Build Coastguard Worker 0007 95 1|11,01 #L0 7+3 unused 2164*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for \\n is 4 bits 2165*f4ee7fbaSAndroid Build Coastguard Worker 001,01 #L0 1+3 unused 2166*f4ee7fbaSAndroid Build Coastguard Worker 0008 44 010,0|1 #L0 total 19+2 unused 2167*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for " " is 4 bits 2168*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for ! is 4 bits 2169*f4ee7fbaSAndroid Build Coastguard Worker 0009 cb 011,|01 #L0 3+3 unused 2170*f4ee7fbaSAndroid Build Coastguard Worker |110,01 #L0 total 35+6 unused 2171*f4ee7fbaSAndroid Build Coastguard Worker 000a 82 0 #L0 Length for K is 4 bits 2172*f4ee7fbaSAndroid Build Coastguard Worker 000,01 #L0 0+3 unused 2173*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for O is 4 bits 2174*f4ee7fbaSAndroid Build Coastguard Worker 000b 4d 01|1 #L0 symbol P unused 2175*f4ee7fbaSAndroid Build Coastguard Worker 011 #L0 symbol Q unused 2176*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for R is 4 bits 2177*f4ee7fbaSAndroid Build Coastguard Worker 000c 88 000,|01 #L0 0+3 unused 2178*f4ee7fbaSAndroid Build Coastguard Worker |100,01 #L0 total 11+4 unused 2179*f4ee7fbaSAndroid Build Coastguard Worker 000d b6 0 #L0 Length for b is 4 bits 2180*f4ee7fbaSAndroid Build Coastguard Worker 011 #L0 symbol c unused 2181*f4ee7fbaSAndroid Build Coastguard Worker 011 #L0 symbol d unused 2182*f4ee7fbaSAndroid Build Coastguard Worker 000e 27 11|1 #L0 Length for e is 3 bits 2183*f4ee7fbaSAndroid Build Coastguard Worker 010,01 #L0 2+3 unused 2184*f4ee7fbaSAndroid Build Coastguard Worker |0 #L0 Length for k is 4 bits 2185*f4ee7fbaSAndroid Build Coastguard Worker 000f 1f 111 #L0 Length for l is 3 bits 2186*f4ee7fbaSAndroid Build Coastguard Worker 011 #L0 symbol m unused 2187*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for n is 4 bits 2188*f4ee7fbaSAndroid Build Coastguard Worker |0 #L0 Length for o is 4 bits 2189*f4ee7fbaSAndroid Build Coastguard Worker 0010 c1 000,01 #L0 0+3 unused 2190*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for s is 4 bits 2191*f4ee7fbaSAndroid Build Coastguard Worker 0011 b4 0|11 #L0 symbol t unused 2192*f4ee7fbaSAndroid Build Coastguard Worker 0 #L0 Length for u is 4 bits 2193*f4ee7fbaSAndroid Build Coastguard Worker End of table. Prefix code L0: 2194*f4ee7fbaSAndroid Build Coastguard Worker 000:e 0010:\\n 0110:! 0001:O 0101:b 0011:n 0111:s 2195*f4ee7fbaSAndroid Build Coastguard Worker 100:l 1010:" " 1110:K 1001:R 1101:k 1011:o 1111:u 2196*f4ee7fbaSAndroid Build Coastguard Worker 11,01 PFX IC0 is simple with 4 code words 2197*f4ee7fbaSAndroid Build Coastguard Worker 0012 2a |2Ah|10 IC0 ? bits: I5C4 2198*f4ee7fbaSAndroid Build Coastguard Worker 0013 b5 ec 00|B5h IC0 ? bits: I6+xC7 2199*f4ee7fbaSAndroid Build Coastguard Worker 0015 22 0010|111011 IC0 ? bits: I8+xC5 2200*f4ee7fbaSAndroid Build Coastguard Worker 0016 8c 001100|0010 IC0 ? bits: I0C14+xx 2201*f4ee7fbaSAndroid Build Coastguard Worker 0 SHAPE False: lengths 2,2,2,2 2202*f4ee7fbaSAndroid Build Coastguard Worker 0017 74 10,0|1 PFX D0 is simple with 3 code words 2203*f4ee7fbaSAndroid Build Coastguard Worker 0018 a6 0|01110 D0 1 bit: 2last-3 2204*f4ee7fbaSAndroid Build Coastguard Worker 010011 D0 2 bits: 11xx-3 2205*f4ee7fbaSAndroid Build Coastguard Worker 0019 aa 01010|1 D0 2 bits: 11xxx-3 2206*f4ee7fbaSAndroid Build Coastguard Worker ====================Meta block contents===================== 2207*f4ee7fbaSAndroid Build Coastguard Worker |1,01 IC0 Literal: 9, copy: 5 2208*f4ee7fbaSAndroid Build Coastguard Worker 001a 41 0001 0,0=L0 O 2209*f4ee7fbaSAndroid Build Coastguard Worker 100 0,48=L0 l 2210*f4ee7fbaSAndroid Build Coastguard Worker 001b a2 10|0 0,62=L0 l 2211*f4ee7fbaSAndroid Build Coastguard Worker 000 0,63=L0 e 2212*f4ee7fbaSAndroid Build Coastguard Worker 001c a1 1|101 0,59=L0 k 2213*f4ee7fbaSAndroid Build Coastguard Worker 000 0,63=L0 e 2214*f4ee7fbaSAndroid Build Coastguard Worker |1010 0,59=L0 " " 2215*f4ee7fbaSAndroid Build Coastguard Worker 001d b5 0101 0,11=L0 b 2216*f4ee7fbaSAndroid Build Coastguard Worker |1011 0,60=L0 o 2217*f4ee7fbaSAndroid Build Coastguard Worker 001e 24 0 0,3=D0 Distance: 2last-3=8 2218*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "lleke" 2219*f4ee7fbaSAndroid Build Coastguard Worker 0,10 IC0 Literal: 6, copy: 7 2220*f4ee7fbaSAndroid Build Coastguard Worker |0010 0,59=L0 \\n 2221*f4ee7fbaSAndroid Build Coastguard Worker 001f 89 1001 0,7=L0 R 2222*f4ee7fbaSAndroid Build Coastguard Worker 000 0,52=L0 e 2223*f4ee7fbaSAndroid Build Coastguard Worker 0020 fa 010|1 0,58=L0 b 2224*f4ee7fbaSAndroid Build Coastguard Worker 1111 0,63=L0 u 2225*f4ee7fbaSAndroid Build Coastguard Worker 0021 eb 011|1 0,59=L0 s 2226*f4ee7fbaSAndroid Build Coastguard Worker 11,01 0,3=D0 Absolute value: 12 (pos 8) 2227*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "olleke\\n" 2228*f4ee7fbaSAndroid Build Coastguard Worker 0022 db 01,1|1 IC0 Literal: 0, copy: 15 2229*f4ee7fbaSAndroid Build Coastguard Worker |110,11 0,3=D0 Absolute value: 27 (pos 0) 2230*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "Olleke bolleke\\n" 2231*f4ee7fbaSAndroid Build Coastguard Worker 0023 f8 00 IC0 Literal: 5, copy: 4 2232*f4ee7fbaSAndroid Build Coastguard Worker 1110 0,7=L0 K 2233*f4ee7fbaSAndroid Build Coastguard Worker 0024 2c 00|11 0,52=L0 n 2234*f4ee7fbaSAndroid Build Coastguard Worker 1011 0,62=L0 o 2235*f4ee7fbaSAndroid Build Coastguard Worker 0025 0d 1|00 0,59=L0 l 2236*f4ee7fbaSAndroid Build Coastguard Worker 0110 0,63=L0 ! 2237*f4ee7fbaSAndroid Build Coastguard Worker """, 2238*f4ee7fbaSAndroid Build Coastguard Worker 2239*f4ee7fbaSAndroid Build Coastguard Worker'file': """ 2240*f4ee7fbaSAndroid Build Coastguard Worker >>> try: Layout(BitStream( 2241*f4ee7fbaSAndroid Build Coastguard Worker ... open("H:/Downloads/brotli-master/tests/testdata/10x10y.compressed",'rb') 2242*f4ee7fbaSAndroid Build Coastguard Worker ... .read())).processStream() 2243*f4ee7fbaSAndroid Build Coastguard Worker ... except NotImplementedError: pass 2244*f4ee7fbaSAndroid Build Coastguard Worker addr hex binary context explanation 2245*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Stream header------------------------ 2246*f4ee7fbaSAndroid Build Coastguard Worker 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288 2247*f4ee7fbaSAndroid Build Coastguard Worker ======================Metablock header====================== 2248*f4ee7fbaSAndroid Build Coastguard Worker 1 LAST Last block: 1: True 2249*f4ee7fbaSAndroid Build Coastguard Worker 0 EMPTY Empty block: 0: False 2250*f4ee7fbaSAndroid Build Coastguard Worker 0001 13 00 |00h|13h,|00 MLEN data length: 0013h+1=20 2251*f4ee7fbaSAndroid Build Coastguard Worker -------------------Block type descriptors------------------- 2252*f4ee7fbaSAndroid Build Coastguard Worker 0003 00 0 BT#L 0: 1 literal block type 2253*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#I 0: 1 insert© block type 2254*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#D 0: 1 distance block type 2255*f4ee7fbaSAndroid Build Coastguard Worker ------------------Distance code parameters------------------ 2256*f4ee7fbaSAndroid Build Coastguard Worker 0004 a4 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes 2257*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Context modes------------------------ 2258*f4ee7fbaSAndroid Build Coastguard Worker 10 LC0 Context mode for type 0: 2(UTF8) 2259*f4ee7fbaSAndroid Build Coastguard Worker ------------------------Context maps------------------------ 2260*f4ee7fbaSAndroid Build Coastguard Worker 0 LT# 0: 1 literal prefix tree 2261*f4ee7fbaSAndroid Build Coastguard Worker 0 DT# 0: 1 distance prefix tree 2262*f4ee7fbaSAndroid Build Coastguard Worker ---------------------Prefix code lists---------------------- 2263*f4ee7fbaSAndroid Build Coastguard Worker 0005 b0 0|1,01 PFX L0 is simple with 2 code words 2264*f4ee7fbaSAndroid Build Coastguard Worker 0006 b2 0|1011000 L0 1 bit: X 2265*f4ee7fbaSAndroid Build Coastguard Worker 0007 ea 0|1011001 L0 1 bit: Y 2266*f4ee7fbaSAndroid Build Coastguard Worker 01,01 PFX IC0 is simple with 2 code words 2267*f4ee7fbaSAndroid Build Coastguard Worker 0008 81 0000001|111 IC0 1 bit: I1C9&D=0 2268*f4ee7fbaSAndroid Build Coastguard Worker 0009 47 02 0|47h|1 IC0 1 bit: I1C9 2269*f4ee7fbaSAndroid Build Coastguard Worker 00,01 PFX D0 is simple with 1 code word 2270*f4ee7fbaSAndroid Build Coastguard Worker 000b 8a 010|000 D0 0 bits: 10x-3 2271*f4ee7fbaSAndroid Build Coastguard Worker ====================Meta block contents===================== 2272*f4ee7fbaSAndroid Build Coastguard Worker 1 IC0 Literal: 1, copy: 9 2273*f4ee7fbaSAndroid Build Coastguard Worker 0 0,0=L0 X 2274*f4ee7fbaSAndroid Build Coastguard Worker 0,() 0,3=D0 Absolute value: 1 (pos 0) 2275*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "XXXXXXXXX" 2276*f4ee7fbaSAndroid Build Coastguard Worker 0 IC0 Literal: 1, copy: 9, same distance 2277*f4ee7fbaSAndroid Build Coastguard Worker |1 0,54=L0 Y 2278*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "YYYYYYYYY" 2279*f4ee7fbaSAndroid Build Coastguard Worker """, 2280*f4ee7fbaSAndroid Build Coastguard Worker 2281*f4ee7fbaSAndroid Build Coastguard Worker'XY': """ 2282*f4ee7fbaSAndroid Build Coastguard Worker >>> try: Layout(BitStream(brotli.compress('X'*10+'Y'*10))).processStream() 2283*f4ee7fbaSAndroid Build Coastguard Worker ... except NotImplementedError: pass 2284*f4ee7fbaSAndroid Build Coastguard Worker addr hex binary context explanation 2285*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Stream header------------------------ 2286*f4ee7fbaSAndroid Build Coastguard Worker 0000 1b 1011 WSIZE windowsize=(1<<22)-16=4194288 2287*f4ee7fbaSAndroid Build Coastguard Worker ======================Metablock header====================== 2288*f4ee7fbaSAndroid Build Coastguard Worker 1 LAST Last block: 1: True 2289*f4ee7fbaSAndroid Build Coastguard Worker 0 EMPTY Empty block: 0: False 2290*f4ee7fbaSAndroid Build Coastguard Worker 0001 13 00 |00h|13h,|00 MLEN data length: 0013h+1=20 2291*f4ee7fbaSAndroid Build Coastguard Worker -------------------Block type descriptors------------------- 2292*f4ee7fbaSAndroid Build Coastguard Worker 0003 00 0 BT#L 0: 1 literal block type 2293*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#I 0: 1 insert© block type 2294*f4ee7fbaSAndroid Build Coastguard Worker 0 BT#D 0: 1 distance block type 2295*f4ee7fbaSAndroid Build Coastguard Worker ------------------Distance code parameters------------------ 2296*f4ee7fbaSAndroid Build Coastguard Worker 0004 a4 0|000,00 DIST 0 postfix bits and 0000<<0=0 direct codes 2297*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Context modes------------------------ 2298*f4ee7fbaSAndroid Build Coastguard Worker 10 LC0 Context mode for type 0: 2(UTF8) 2299*f4ee7fbaSAndroid Build Coastguard Worker ------------------------Context maps------------------------ 2300*f4ee7fbaSAndroid Build Coastguard Worker 0 LT# 0: 1 literal prefix tree 2301*f4ee7fbaSAndroid Build Coastguard Worker 0 DT# 0: 1 distance prefix tree 2302*f4ee7fbaSAndroid Build Coastguard Worker ---------------------Prefix code lists---------------------- 2303*f4ee7fbaSAndroid Build Coastguard Worker 0005 b0 0|1,01 PFX L0 is simple with 2 code words 2304*f4ee7fbaSAndroid Build Coastguard Worker 0006 b2 0|1011000 L0 1 bit: X 2305*f4ee7fbaSAndroid Build Coastguard Worker 0007 82 0|1011001 L0 1 bit: Y 2306*f4ee7fbaSAndroid Build Coastguard Worker 00,01 PFX IC0 is simple with 1 code word 2307*f4ee7fbaSAndroid Build Coastguard Worker 0008 84 0000100|100 IC0 0 bits: I4C6&D=0 2308*f4ee7fbaSAndroid Build Coastguard Worker 0009 00 00,0|1 PFX D0 is simple with 1 code word 2309*f4ee7fbaSAndroid Build Coastguard Worker 000a e0 0|00000 D0 0 bits: last 2310*f4ee7fbaSAndroid Build Coastguard Worker ====================Meta block contents===================== 2311*f4ee7fbaSAndroid Build Coastguard Worker () IC0 Literal: 4, copy: 6, same distance 2312*f4ee7fbaSAndroid Build Coastguard Worker 0 0,0=L0 X 2313*f4ee7fbaSAndroid Build Coastguard Worker 0 0,52=L0 X 2314*f4ee7fbaSAndroid Build Coastguard Worker 0 0,54=L0 X 2315*f4ee7fbaSAndroid Build Coastguard Worker 0 0,54=L0 X 2316*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "XXXXXX" 2317*f4ee7fbaSAndroid Build Coastguard Worker () IC0 Literal: 4, copy: 6, same distance 2318*f4ee7fbaSAndroid Build Coastguard Worker 1 0,54=L0 Y 2319*f4ee7fbaSAndroid Build Coastguard Worker 1 0,54=L0 Y 2320*f4ee7fbaSAndroid Build Coastguard Worker |1 0,54=L0 Y 2321*f4ee7fbaSAndroid Build Coastguard Worker 000b 01 1 0,54=L0 Y 2322*f4ee7fbaSAndroid Build Coastguard Worker Seen before: "YYYYYY" 2323*f4ee7fbaSAndroid Build Coastguard Worker """, 2324*f4ee7fbaSAndroid Build Coastguard Worker 2325*f4ee7fbaSAndroid Build Coastguard Worker'empty': """ 2326*f4ee7fbaSAndroid Build Coastguard Worker >>> try: Layout(BitStream(b'\\x81\\x16\\x00\\x58')).processStream() 2327*f4ee7fbaSAndroid Build Coastguard Worker ... except NotImplementedError: pass 2328*f4ee7fbaSAndroid Build Coastguard Worker addr hex binary context explanation 2329*f4ee7fbaSAndroid Build Coastguard Worker -----------------------Stream header------------------------ 2330*f4ee7fbaSAndroid Build Coastguard Worker 0000 81 0000001 WSIZE windowsize=(1<<17)-16=131056 2331*f4ee7fbaSAndroid Build Coastguard Worker ======================Metablock header====================== 2332*f4ee7fbaSAndroid Build Coastguard Worker |1 LAST Last block: 1: True 2333*f4ee7fbaSAndroid Build Coastguard Worker 0001 16 0 EMPTY Empty block: 0: False 2334*f4ee7fbaSAndroid Build Coastguard Worker 11 MLEN 11: empty block 2335*f4ee7fbaSAndroid Build Coastguard Worker 0 RSVD Reserved (must be zero) 2336*f4ee7fbaSAndroid Build Coastguard Worker 0002 00 000000|00,01 SKIP skip length: 0h+1=1 2337*f4ee7fbaSAndroid Build Coastguard Worker |00 SKIP 2 bits ignored 2338*f4ee7fbaSAndroid Build Coastguard Worker Skipping to 4 2339*f4ee7fbaSAndroid Build Coastguard Worker """, 2340*f4ee7fbaSAndroid Build Coastguard Worker 2341*f4ee7fbaSAndroid Build Coastguard Worker} 2342*f4ee7fbaSAndroid Build Coastguard Worker 2343*f4ee7fbaSAndroid Build Coastguard Workerif __name__=='__main__': 2344*f4ee7fbaSAndroid Build Coastguard Worker import sys 2345*f4ee7fbaSAndroid Build Coastguard Worker if len(sys.argv)>1: 2346*f4ee7fbaSAndroid Build Coastguard Worker l = Layout(BitStream(open(sys.argv[1],'rb').read())) 2347*f4ee7fbaSAndroid Build Coastguard Worker l.processStream() 2348*f4ee7fbaSAndroid Build Coastguard Worker else: 2349*f4ee7fbaSAndroid Build Coastguard Worker sys.path.append("h:/Persoonlijk/bin") 2350*f4ee7fbaSAndroid Build Coastguard Worker try: 2351*f4ee7fbaSAndroid Build Coastguard Worker import brotli 2352*f4ee7fbaSAndroid Build Coastguard Worker open('brotlidump.br', 'wb').write( 2353*f4ee7fbaSAndroid Build Coastguard Worker brotli.compress( 2354*f4ee7fbaSAndroid Build Coastguard Worker open('brotlidump.py', 'r').read() 2355*f4ee7fbaSAndroid Build Coastguard Worker )) 2356*f4ee7fbaSAndroid Build Coastguard Worker olleke = BitStream(brotli.compress( 2357*f4ee7fbaSAndroid Build Coastguard Worker 'Olleke bolleke\nRebusolleke\nOlleke bolleke\nKnol!')) 2358*f4ee7fbaSAndroid Build Coastguard Worker except ImportError: pass 2359*f4ee7fbaSAndroid Build Coastguard Worker import doctest 2360*f4ee7fbaSAndroid Build Coastguard Worker doctest.testmod(optionflags=doctest.REPORT_NDIFF 2361*f4ee7fbaSAndroid Build Coastguard Worker #|doctest.FAIL_FAST 2362*f4ee7fbaSAndroid Build Coastguard Worker ) 2363