xref: /aosp_15_r20/external/brotli/research/brotlidump.py (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
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&copy", "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&copy 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&copy 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&copy 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&copy 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