~jconti/ubuntu/precise/emesene/fix-956422

« back to all changes in this revision

Viewing changes to pyisf/pyisf.py

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2010-04-14 01:33:51 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20100414013351-r2icbt5gs4ai71j8
Tags: 1.6.1-0ubuntu1
* New upstream release (LP: #562646).
* Fix missing-debian-source-format lintian warning.
* Refresh 20_dont_build_own_libmimic.patch patch.
* Bump Standards-Version to 3.8.4.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
#   This file is part of emesene.
 
4
#
 
5
#    Emesene is free software; you can redistribute it and/or modify
 
6
#    it under the terms of the GNU General Public License as published by
 
7
#    the Free Software Foundation; either version 2 of the License, or
 
8
#    (at your option) any later version.
 
9
#
 
10
#    Emesene is distributed in the hope that it will be useful,
 
11
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#    GNU General Public License for more details.
 
14
#
 
15
#    You should have received a copy of the GNU General Public License
 
16
#    along with emesene; if not, write to the Free Software
 
17
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
#
 
19
 
 
20
import struct
 
21
import drawing
 
22
import gtk.gdk
 
23
 
 
24
 
 
25
class IsfBin( object ):
 
26
    '''Base class to encoder and decoder, represents
 
27
        the information read from or to be stored in
 
28
        a binary Isf file, as well as the functions
 
29
        necessary to do so '''
 
30
 
 
31
    def __init__( self, data = '' ):
 
32
        self.data = data
 
33
        self.pointer = 0
 
34
        self.bit = 0
 
35
        
 
36
    def pop( self, length = 1 ):
 
37
        '''gets the next $len chars from the data stack,
 
38
        and increment the pointer'''
 
39
        
 
40
        start = self.pointer
 
41
        end = self.pointer + length
 
42
        self.pointer += length
 
43
 
 
44
        return self.data[start:end]
 
45
        
 
46
    def pops( self, format ):
 
47
        '''Reads formatted data from the struct.  Supports, in
 
48
            in addition to anthing supported by struct, mbuint32/64,
 
49
            and mbsint32'''
 
50
        if format.startswith('mbuint32'):
 
51
            next = True
 
52
            temp = 0
 
53
            bitcount = 0
 
54
            while next:
 
55
                byte = struct.unpack( '<B', self.pop(1) )[0]
 
56
                num = byte & 0x7f
 
57
                temp *= pow(2, 7)
 
58
                temp = temp | num
 
59
                bitcount += 7
 
60
                if byte > 0x7f and bitcount < 29:
 
61
                    next = True
 
62
                else:
 
63
                    next = False
 
64
            return temp
 
65
 
 
66
        elif format.startswith('mbuint64'):
 
67
            next = True
 
68
            temp = 0
 
69
            bitcount = 0
 
70
            while next:
 
71
                byte = struct.unpack( '<B', self.pop(1) )[0]
 
72
                num = byte & 0x7f
 
73
                temp *= pow(2, 7)
 
74
                temp = temp | num
 
75
                bitcount += 7
 
76
                if byte > 0x7f and bitcount < 57:
 
77
                    next = True
 
78
                else:
 
79
                    next = False
 
80
            return temp
 
81
 
 
82
        # The number of points in a stroke seems to use this strange
 
83
        # format of integer.  It is essentially a multi-byte integer
 
84
        # where the least significant bits come first in the stream.
 
85
        elif format.startswith('weirdoint'):
 
86
            next = True
 
87
            temp = 0
 
88
            bitcount = 0
 
89
            while next:
 
90
                byte = struct.unpack( '<B', self.pop(1) )[0]
 
91
                num = byte & 0x7f
 
92
                temp = temp + num * pow(2, bitcount)
 
93
                bitcount += 7
 
94
                if byte > 0x7f:
 
95
                    next = True
 
96
                else:
 
97
                    next = False
 
98
            return temp
 
99
 
 
100
        elif format.startswith('mbsint32'):
 
101
            temp = self.pops('mbuint64')
 
102
            if temp & 1:
 
103
                temp *= -1
 
104
            return int(temp / 2)
 
105
 
 
106
        else:
 
107
            # pop struct: get size, pop(), unpack()
 
108
            size = struct.calcsize(format) 
 
109
            return struct.unpack( format, self.pop(size) )
 
110
 
 
111
    def push( self, newdata, insert = False ):
 
112
        '''adds $newdata to the data stack, if insert is True then
 
113
            it adds it to the beginning of the stack'''
 
114
        if insert:
 
115
            self.data = newdata + self.data
 
116
        else:
 
117
            self.data += newdata
 
118
    
 
119
    def pushs( self, format, *vars ):
 
120
        '''Pushes formatted data onto the struct.  Supports, in
 
121
            in addition to anthing supported by struct, mbuint32/64,
 
122
            and mbsint32'''
 
123
        # TODO: I need a way to insert things at the beginning
 
124
        # for now insert is always False
 
125
        insert = False
 
126
 
 
127
        if format.startswith('mbuint32'):
 
128
            if len(vars) > 1:
 
129
                print 'Only one value per', format
 
130
            value = vars[0]
 
131
            if value > 0xfffffff or value < 0:
 
132
                print 'Value not within', format, 'range'
 
133
            new = True
 
134
            cont = False
 
135
            num = 0
 
136
            values = []
 
137
            while new or cont:
 
138
                for i in range(7):
 
139
                    bit = value % 2
 
140
                    value = int(value / 2)
 
141
                    if bit:
 
142
                        num += pow(2, i)
 
143
                    if value > 0:
 
144
                        cont = True
 
145
                    else:
 
146
                        cont = False
 
147
                if new:
 
148
                    new = False
 
149
                elif cont:
 
150
                    num += pow(2, 7)
 
151
                values.insert(0, num)
 
152
                num = 0
 
153
            if insert:
 
154
                for val in values.reverse():
 
155
                    self.push( struct.pack( '<B', val, insert = True ) )
 
156
            else:
 
157
                for val in values:
 
158
                    self.push( struct.pack( '<B', val ) )
 
159
 
 
160
        elif format.startswith('mbuint64'):
 
161
            if len(vars) > 1:
 
162
                print 'Only one value per', format
 
163
            value = vars[0]
 
164
            if value > 0xfffffffffffffff or value < 0:
 
165
                print 'Value not within', format, 'range'
 
166
            new = True
 
167
            cont = False
 
168
            num = 0
 
169
            values = []
 
170
            while new or cont:
 
171
                for i in range(7):
 
172
                    bit = value % 2
 
173
                    value = int(value / 2)
 
174
                    if bit and i < 7:
 
175
                        num += pow(2, i)
 
176
                    if value > 0:
 
177
                        cont = True
 
178
                    else:
 
179
                        cont = False
 
180
                if new:
 
181
                    new = False
 
182
                else:
 
183
                    num += pow(2, 7)
 
184
                values.insert(0, num)
 
185
                num = 0
 
186
            if insert:
 
187
                for val in values.reverse():
 
188
                    self.push( struct.pack( '<B', val, insert = True ) )
 
189
            else:
 
190
                for val in values:
 
191
                    self.push( struct.pack( '<B', val ) )
 
192
 
 
193
        elif format.startswith('mbsint32'):
 
194
            if len(vars) > 1:
 
195
                print 'Only one value per', format
 
196
            value = vars[0]
 
197
            if abs(value) > 0xfffffff:
 
198
                print 'Value not within', format, 'range'
 
199
            if value < 0:
 
200
                sign = 1
 
201
                value = abs(value)
 
202
            else:
 
203
                sign = 0
 
204
            value = value * 2 + sign
 
205
            self.pushs('mbuint64', value)
 
206
 
 
207
        elif format.startswith('weirdoint'):
 
208
            if len(vars) > 1:
 
209
                print 'Only one value per', format
 
210
            value = vars[0]
 
211
            new = True
 
212
            cont = False
 
213
            num = 0
 
214
            values = []
 
215
            while new or cont:
 
216
                for i in range(7):
 
217
                    bit = value % 2
 
218
                    value = int(value / 2)
 
219
                    if bit and i < 7:
 
220
                        num += pow(2, i)
 
221
                    if value > 0:
 
222
                        cont = True
 
223
                    else:
 
224
                        cont = False
 
225
                if new:
 
226
                    new = False
 
227
                else:
 
228
                    num += pow(2, 7)
 
229
                values.append(num)
 
230
                num = 0
 
231
 
 
232
            if insert:
 
233
                for val in values.reverse():
 
234
                    self.push( struct.pack( '<B', val, insert = True ) )
 
235
            else:
 
236
                for val in values:
 
237
                    self.push( struct.pack( '<B', val ) )
 
238
 
 
239
        else:
 
240
            # push struct: adds a packed struct to the data stack
 
241
            self.push(struct.pack(format, *vars))
 
242
 
 
243
class ImageDescriptor( object ):
 
244
    '''A class that represents a single image'''
 
245
    # The following two arrays, taglist and tagformat are organized
 
246
    # so the index is the tag's index, and the format strings are
 
247
    # the type of payload following the tag
 
248
 
 
249
    # Array of tag strings
 
250
    taglist = [
 
251
    'INK_SPACE_RECT', 'GUID_TABLE', 'DRAW_ATTRS_TABLE',
 
252
    'DRAW_ATTRS_BLOCK', 'STROKE_DESC_TABLE', 'STROKE_DESC_BLOCK',
 
253
    'BUTTONS', 'NO_X', 'NO_Y', 'DIDX', 'STROKE', 'STROKE_PROPERTY_LIST',
 
254
    'POINT_PROPERTY', 'SIDX', 'COMPRESSION_HEADER', 'TRANSFORM_TABLE',
 
255
    'TRANSFORM', 'TRANSFORM_ISOTROPIC_SCALE', 'TRANSFORM_ANISOTROPIC_SCALE',
 
256
    'TRANSFORM_ROTATE', 'TRANSFORM_TRANSLATE', 'TRANSFORM_SCALE_AND_TRANSLATE',
 
257
    'TRANSFORM_QUAD', 'TIDX', 'METRIC_TABLE', 'METRIC_BLOCK', 'MIDX',
 
258
    'MANTISSA', 'PERSISTENT_FORMAT', 'HIMETRIC_SIZE', 'STROKE_IDS']
 
259
 
 
260
    # Array of format stings; a V means an mbuint64 containing
 
261
    # the payload size follows
 
262
    tagformat = [
 
263
    'pass', 'V', 'V', 'V', 'V', 'V', 'pass', 'pass', 'pass', 'mbuint32', 'V',
 
264
    'pass', 'pass', 'mbuint32', 'pass', 'V', '<ffffff', '<f', '<ff', 'mbuint32',
 
265
    '<ff', '<ffff', '<IIIIII', 'mbuint32', 'V', 'V', 'pass', 'mbuint64', 'V', 
 
266
        'V', 'V']
 
267
        
 
268
        # Array of bitamounts used in huffman decompression
 
269
    bitamounts = [
 
270
                [0, 1, 2, 4, 6, 8, 12, 16, 24, 32], [0, 1, 1, 2, 4, 8, 12, 16, 24, 32],
 
271
        [0, 1, 1, 1, 2, 4, 8, 14, 22, 32], [0, 2, 2, 3, 5, 8, 12, 16, 24, 32],
 
272
        [0, 3, 4, 5, 8, 12, 16, 24, 32], [0, 4, 6, 8, 12, 16, 24, 32],
 
273
        [0, 6, 8, 12, 16, 24, 32], [0, 7, 8, 12, 16, 24, 32]]
 
274
    
 
275
    def __init__( self ):
 
276
        self.paths = []
 
277
        self.isf_tag = 0
 
278
        self.isf_size = 0
 
279
        self.himetric_size = [0, 0]
 
280
        self.indices = {
 
281
            'DIDX':0,
 
282
            'TIDX':0,
 
283
            'MIDX':0,
 
284
            'SIDX':0 }
 
285
        self.transforms = []
 
286
        self.draw_attrs_table = []
 
287
        self.size = 8
 
288
 
 
289
    def print_info( self ):
 
290
        '''Prints some information about the isf file'''
 
291
        print 'ISFTag:', self.isf_tag
 
292
        print 'ISFSize:', self.isf_size
 
293
        print 'Image Size:', self.himetric_size[0], 'x', self.himetric_size[1]
 
294
        print 'Transforms:'
 
295
        for trans in self.transforms:
 
296
            print trans
 
297
        print 'Paths:'
 
298
        for path in self.paths:
 
299
            path.print_info()
 
300
        print 'Indices:', self.indices
 
301
 
 
302
        
 
303
class IsfEncoder( ImageDescriptor ):
 
304
    '''encodes an isf file'''
 
305
    def __init__( self, paths, debug=False):
 
306
        self.paths = paths
 
307
        self.enc = IsfBin()
 
308
        self.fill()
 
309
        
 
310
    def fill( self ):
 
311
        '''Fills the data array'''
 
312
        for path in self.paths:
 
313
            stroke = self.enc_stroke(path)
 
314
            self.enc.pushs('mbuint32', taglist.index('STROKE'))
 
315
            self.enc.pushs('mbuint64', len(stroke))
 
316
            self.enc.data += stroke
 
317
            self.enc.pointer += len(stroke)
 
318
        self.add_headers()
 
319
    
 
320
    def add_headers( self ):
 
321
        '''Adds basic information to the top of the file'''
 
322
        head = IsfBin()
 
323
        head.pushs('mbuint32', 0)
 
324
        head.pushs('mbuint64', len(self.enc.data))
 
325
        self.enc.data = head.data + self.enc.data
 
326
        self.enc.pointer += len(head.data)
 
327
        
 
328
    def enc_stroke(self, path, enc):
 
329
        num_pts = len(path._points)
 
330
        stroke = IsfBin()
 
331
        stroke.pushs('weirdoint', num_pts)
 
332
        guid_x, guid_y = [], []
 
333
        for point in path._points:
 
334
            guid_x.append(point.x)
 
335
            guid_y.append(point.y)
 
336
        if num_pts > 1:
 
337
            packet_x = enc_huffman(guid_x)
 
338
            packet_y = enc_huffman(guid_y)
 
339
            tag = '\x82'
 
340
        else:
 
341
            packet_x = enc_gorilla(guid_x)
 
342
            packet_y = enc_gorilla(guid_y)
 
343
        
 
344
        stroke.data += tag + packet_x + tag + packet_y
 
345
        stroke.data = struct.pack('<B', len(stroke.data)) + stroke.data
 
346
        return stroke.data
 
347
 
 
348
    def enc_huffman(self, guid):
 
349
        stream = Bitstream()
 
350
        # Initial point to the stream
 
351
        enc_huffvalue(guid[0], stream)
 
352
        prevdelta = 0
 
353
        curdelta = 0
 
354
        i = 1
 
355
        while i < len(guid):
 
356
            curdelta = guid[i] - guid[i-1]
 
357
            diff = curdelta - prevdelta
 
358
            prevdelta = curdelta
 
359
            enc_huffvalue(diff, stream)
 
360
        
 
361
    def enc_huffvalue(self, val, stream):
 
362
        temp = val
 
363
        length = 0
 
364
        while temp:
 
365
            # Get the number of bits needed to represent
 
366
            length += 1
 
367
            temp /=2
 
368
        # Find the next smallest length in bitamounts
 
369
        while not bitamounts[2].count(length):
 
370
            length += 1
 
371
        # Get the index of that length
 
372
        index = bitamounts[2].index(length)
 
373
        # Push that index to the stream
 
374
        stream.push_count(index)
 
375
        # Push the actual value of length length
 
376
        stream.push_int(val, length)
 
377
 
 
378
class transform( object ):
 
379
    def __init__( self):
 
380
        self.a = 1
 
381
        
 
382
class IsfDecoder( ImageDescriptor ):
 
383
    '''decodes an isf file'''
 
384
    
 
385
    def __init__( self, data, debug=False):
 
386
        ImageDescriptor.__init__( self )
 
387
        
 
388
        # Dictionary of functions associated with tags
 
389
        self.tagdict = {
 
390
        'STROKE':self.dec_stroke,
 
391
        'DIDX':self.dec_index,
 
392
        'SIDX':self.dec_index,
 
393
        'TIDX':self.dec_index,
 
394
        'MIDX':self.dec_index,
 
395
        'DRAW_ATTRS_BLOCK':self.dec_dablock,
 
396
        'DRAW_ATTRS_TABLE':self.dec_datable
 
397
        }
 
398
    
 
399
        dec = IsfBin(data)
 
400
        self.debug = debug
 
401
        self.fill( dec )
 
402
        
 
403
    def fill( self, dec ):
 
404
        '''reads the data and fills each field of the file'''
 
405
        dec.pointer = 0
 
406
        self.isf_tag = dec.pops('mbuint32')
 
407
        if self.debug:
 
408
            print 'ISFTag', self.isf_tag
 
409
        self.isf_size = dec.pops('mbuint64')
 
410
        if self.debug:
 
411
            print 'ISFSize', self.isf_size
 
412
        # read tags
 
413
        while True:
 
414
            try:
 
415
                tagnum = dec.pops('mbuint32')
 
416
                tag = self.taglist[tagnum]
 
417
                if self.debug:
 
418
                    print 'Tag', tag
 
419
                format = self.tagformat[tagnum]
 
420
            except IndexError:
 
421
                if self.debug:
 
422
                    print 'Uknown Tag Value'
 
423
            except struct.error:
 
424
                if self.debug:
 
425
                    print 'End of file'
 
426
                return
 
427
            except:
 
428
                raise
 
429
            else:
 
430
                prnt = 1
 
431
                if format == 'pass':
 
432
                    pass
 
433
                elif format == 'V':
 
434
                    payload_size = dec.pops('mbuint64')
 
435
                    if self.debug:
 
436
                        print '\tPayload Size', payload_size
 
437
                    payload = dec.data[dec.pointer:dec.pointer+payload_size]
 
438
                    if self.tagdict.has_key(tag):
 
439
                        prnt = 0
 
440
                        self.tagdict[tag](tag, payload)
 
441
                    if self.debug and prnt:
 
442
                        for char in payload:
 
443
                            print '\t', hex(struct.unpack('<B', char)[0])
 
444
                    dec.pointer += payload_size
 
445
                else:
 
446
                    payload = dec.pops(format)
 
447
                    if self.tagdict.has_key(tag):
 
448
                        prnt = 0
 
449
                        self.tagdict[tag](tag, payload)
 
450
                    if self.debug and prnt:
 
451
                        print '\tPayload', payload
 
452
 
 
453
    def process_tag(self, tag, payload):
 
454
        '''Performs specific operations with supported tags'''
 
455
        if tag == 'STROKE_IDS':
 
456
            dat = IsfBin(payload)
 
457
            num_pts = dat.pops('mbuint32')
 
458
            stream = Bitstream(payload[dat.pointer:])
 
459
            ids = self.dec_packet(stream, num_pts)
 
460
            if self.debug:
 
461
                print '\t', ids
 
462
        elif tag == 'HIMETRIC_SIZE':
 
463
            dat = IsfBin(payload)
 
464
            width = dat.pops('mbsint32')
 
465
            height = dat.pops('mbsint32')
 
466
            self.himetric_size = [width, height]
 
467
        else: return 1
 
468
        
 
469
    def dec_datable( self, tag, payload ):
 
470
        dat = IsfBin(payload)
 
471
        index = 0
 
472
        while True:
 
473
            try:
 
474
                block_size = dat.pops('mbuint32')
 
475
                self.dec_dablock(tag, dat.data[dat.pointer:dat.pointer + block_size], index)
 
476
                dat.pointer += block_size
 
477
            except struct.error:
 
478
                if self.debug:
 
479
                    print 'End of DRAW_ATTR_TABLE'
 
480
                    for table in self.draw_attrs_table:
 
481
                        print table.color.to_string()
 
482
                return
 
483
            except:
 
484
                raise
 
485
            index += 1
 
486
        
 
487
    def dec_dablock( self, tag, payload, index = 0 ):
 
488
        dat = IsfBin(payload)
 
489
        if index >= len(self.draw_attrs_table):
 
490
            self.draw_attrs_table.append(drawing.DrawAttributes())
 
491
            print 'Appended'
 
492
        color = gtk.gdk.Color(0, 0, 0)
 
493
        while True:
 
494
            try:
 
495
                guid = dat.pops('mbuint32')
 
496
            except struct.error:
 
497
                if self.debug:
 
498
                    print 'End of DRAW_ATTR_BLOCK'
 
499
                self.draw_attrs_table[index].color = color
 
500
                return
 
501
            except:
 
502
                raise
 
503
            else:
 
504
                print '\tGUID', hex(guid)
 
505
                if guid != 0x57:
 
506
                    data = dat.pops('mbuint32')
 
507
                    print '\t\tData', hex(data)
 
508
                else:
 
509
                    data = dat.pops('<BBBB')
 
510
                if guid == 0x44:
 
511
                    print hex(data)
 
512
                    red = data & 0x7f
 
513
                    #red = 0xff - red
 
514
                    red = (red * 65535) / 127
 
515
                    green = (data & 0x3f80) / 0x80
 
516
                    #green = 0xff - green
 
517
                    green = (green * 65535) / 127
 
518
                    blue = (data & 0x1f6000) / 0x4000
 
519
                    #blue = 0xff - blue
 
520
                    blue = (blue * 65535) / 127
 
521
                    color = gtk.gdk.Color(green, red, blue)
 
522
 
 
523
    def dec_index( self, tag, payload ):
 
524
        self.indices[tag] = payload
 
525
        print '\tIndices:', self.indices
 
526
        
 
527
    def dec_stroke( self, tag, payload ):
 
528
        '''Decodes stroke data from the payload, including
 
529
            the number of data points, the x values, and the
 
530
            y values'''
 
531
        # Get number of points
 
532
        dat = IsfBin(payload)
 
533
        num_pts = dat.pops('weirdoint')
 
534
        num_bytes = dat.pointer
 
535
        dat = None
 
536
        if self.debug:
 
537
            print '\tNumPoints:', num_pts
 
538
        # Create the bit stream
 
539
        stream = Bitstream( payload[num_bytes:] )
 
540
 
 
541
        # Decode the two packets
 
542
        guid_x = self.dec_packet(stream, num_pts)
 
543
        guid_y = self.dec_packet(stream, num_pts)
 
544
        if guid_x == -1 or guid_y == -1:
 
545
            guid_x = [0]
 
546
            guid_y = [0]
 
547
        path = drawing.BrushPath(drawing.Point(guid_x[0], guid_y[0]), 
 
548
            self.draw_attrs_table[self.indices['DIDX']])
 
549
        for i in range(1, len(guid_x)):
 
550
            path.add(drawing.Point(guid_x[i], guid_y[i]))
 
551
        self.paths.append(path)
 
552
 
 
553
    def dec_packet(self, stream, num_pts):
 
554
        '''Function that decodes *ISF/PACKET* formatted data from
 
555
            a Bitstream class object, and the number of points
 
556
            to be decoded'''
 
557
        # Get the tag byte
 
558
        tag = stream.pop_byte()
 
559
        if tag & 0xc0 == 0x80:
 
560
            # Adaptive-Huffman Compression
 
561
            if self.debug:
 
562
                print '\tAdaptive-Huffman Compression'
 
563
            index = tag & 0x1f
 
564
            try:
 
565
                pts = self.dec_huffman(stream, index, num_pts)
 
566
            except:
 
567
                if self.debug == 0:
 
568
                    pts = -1
 
569
                else:
 
570
                    raise
 
571
        else:
 
572
            # Gorilla Compression
 
573
            if self.debug:
 
574
                print '\tGorilla Compression'
 
575
            # TODO: Figure out what the gorilla transformation is
 
576
            transformation = tag & 0x20
 
577
            if transformation == 0x20:
 
578
                print "\tError: Gorilla transformation unimplemented", hex(tag)
 
579
            width = tag & 0x1f
 
580
            if not width:
 
581
                width = 32
 
582
            try:
 
583
                pts = self.dec_gorilla(stream, width, num_pts)
 
584
            except:
 
585
                if self.debug == 0:
 
586
                    pts = -1
 
587
                else:
 
588
                    raise
 
589
        return pts
 
590
 
 
591
    def dec_huffman( self, stream, index, num_pts ):
 
592
        '''Decodes num_pts values from a Bistream object, using
 
593
            bitamounts[index] to decode it using an Adaptive-Huffman
 
594
            coding scheme'''
 
595
        huffbase = []
 
596
 
 
597
        bitamount = self.bitamounts[index]
 
598
 
 
599
        # Create huffbase array
 
600
        huffbase = [0]
 
601
        base = 1
 
602
        for value in bitamount:
 
603
            if value != 0:
 
604
                huffbase.append(base)
 
605
                base += pow(2, value-1)
 
606
 
 
607
        # Decompress data
 
608
        n_count = 0
 
609
        value = []
 
610
        val = 0
 
611
        while len(value) < num_pts:
 
612
            bit = stream.pop_bit()
 
613
            if bit:
 
614
                n_count += 1
 
615
            else:
 
616
                if n_count == 0:
 
617
                    val = 0
 
618
                elif n_count < len(bitamount):
 
619
                    offset = stream.pop_bits_to_int(bitamount[n_count])
 
620
                    sign = offset & 0x1
 
621
                    offset /= 2
 
622
                    val = huffbase[n_count] + offset
 
623
                    if sign:
 
624
                        val = val * -1
 
625
                elif n_count == len(bitamount):
 
626
                    #TODO: Implement 64-bit value decompression
 
627
                    print '64-bit'
 
628
                    val = 0
 
629
                else:
 
630
                    print 'error'
 
631
                    val = 0
 
632
                n_count = 0
 
633
                value.append(val)
 
634
        # Done reading stream, go to the next byte, unless already
 
635
        # at start of new byte
 
636
        if stream.bit != 0:
 
637
            stream.next_byte()
 
638
 
 
639
        # Delta-delta inverse transform
 
640
        curdelta = 0
 
641
        prevdelta = 0
 
642
        results = []
 
643
        for val in value:
 
644
            newdelta = curdelta*2 - prevdelta + val
 
645
            prevdelta = curdelta
 
646
            curdelta = newdelta
 
647
            results.append(newdelta)
 
648
        return results
 
649
 
 
650
    def dec_gorilla( self, stream, width, num_pts ):
 
651
        '''Decides num_pts values from the Bistream object 'stream',
 
652
            using a fixed width of width'''
 
653
        mask = ( 0xffffffff * pow(2, width-1) ) & 0xffffffff
 
654
        values = []
 
655
        while len(values) < num_pts:
 
656
            value = stream.pop_bits_to_int(width)
 
657
            if value & mask:
 
658
                value = value | mask
 
659
            string = struct.pack('q', value)
 
660
            values.append(struct.unpack('q', string)[0])
 
661
        stream.next_byte()
 
662
        return values
 
663
 
 
664
class Bitstream( object ):
 
665
    '''Takes a character string and turns it into a bitstream'''
 
666
 
 
667
    def __init__( self, data = '\x00'):
 
668
        self.data = data
 
669
        self.bit = 0
 
670
        self.index = 0
 
671
 
 
672
    def pop_byte( self ):
 
673
        '''Removes a byte from the stream, and increments the index'''
 
674
        byte = struct.unpack('<B', self.data[self.index])
 
675
        self.next_byte()
 
676
        return byte[0]
 
677
 
 
678
    def pop_bit( self ):
 
679
        '''Returns a bit from the stream, incrementing the counters'''
 
680
        mask = pow(2, 7-self.bit)
 
681
        bit = struct.unpack('<B', self.data[self.index])[0] & mask
 
682
        self.__increment()
 
683
        ret = False
 
684
        if bit:
 
685
            ret = True
 
686
        return ret
 
687
    
 
688
    def push_bit( self, bit ):
 
689
        '''Pushes the value of the bit passed to the stream'''
 
690
        if bit:
 
691
            val = ((0xff - (pow(2, 8 - self.bit) - 1)) & \
 
692
                struct.unpack('<B', self.data[self.index])[0]) + pow(2, 7 - self.bit)
 
693
            self.data = self.data[0:self.index] + struct.pack('<B', val)
 
694
        self.__increment()        
 
695
 
 
696
    def __increment( self ):
 
697
        '''Increments the bit counter, or the index if at last bit of byte'''
 
698
        if self.bit < 7:
 
699
            self.bit += 1
 
700
        else:
 
701
            self.bit = 0
 
702
            self.index += 1
 
703
            if self.index == len(self.data):
 
704
                self.data += '\x00'
 
705
        return
 
706
 
 
707
    def next_byte( self ):
 
708
        '''Resets the bit counter to 0, and increments the index'''
 
709
        self.index += 1
 
710
        self.bit = 0
 
711
        if self.index == len(self.data):
 
712
            self.data += '\x00'
 
713
 
 
714
    def pop_bits_to_int( self, length ):
 
715
        '''Pops length bits from the stream, and returns a little-
 
716
            endian decoded integer value'''
 
717
        bitcount = 0
 
718
        value = 0
 
719
        while bitcount < length:
 
720
            if self.pop_bit():
 
721
                value += pow(2, length-bitcount-1)
 
722
            bitcount += 1
 
723
        return value
 
724
    
 
725
    def push_int( self, value, length=0 ):
 
726
        '''Pushes the minimum number of bits possible to represent
 
727
            value to the stream, or a specific length if length set'''
 
728
        bitlist = []
 
729
        while value:
 
730
            bitlist.insert(0, value % 2)
 
731
            value /= 2
 
732
        if length >= len(bitlist):
 
733
            num = length - len(bitlist)
 
734
            for i in range(num):
 
735
                self.push_bit(0)
 
736
        else:
 
737
            raise ValueError
 
738
        for bit in bitlist:
 
739
            self.push_bit(bit)
 
740
    
 
741
    def push_count( self, count ):
 
742
        '''Pushes count # 1's to the bitstream, followed by a 0'''
 
743
        for count in range(count):
 
744
            self.push_bit(1)
 
745
        self.push_bit(0)
 
746
        
 
747