@@ -75,7 +75,7 @@ def is_compressed(self):
75
75
""":return: True if reads of this stream yield zlib compressed data. Default False
76
76
:note: this does not imply anything about the actual internal storage.
77
77
Hence the data could be uncompressed, but read compressed, or vice versa"""
78
- raise False
78
+ return False
79
79
80
80
#} END interface
81
81
@@ -105,10 +105,12 @@ def __init__(self, type, size, stream, sha=None, compressed=None):
105
105
106
106
#{ Interface
107
107
108
+ @property
108
109
def hexsha (self ):
109
110
""":return: our sha, hex encoded, 40 bytes"""
110
111
return to_hex_sha (self [0 ])
111
-
112
+
113
+ @property
112
114
def binsha (self ):
113
115
""":return: our sha as binary, 20 bytes"""
114
116
return to_bin_sha (self [0 ])
@@ -229,10 +231,11 @@ class DecompressMemMapReader(object):
229
231
and decompress it into chunks, thats all ... """
230
232
__slots__ = ('_m' , '_zip' , '_buf' , '_buflen' , '_br' , '_cws' , '_cwe' , '_s' , '_close' )
231
233
232
- max_read_size = 512 * 1024
234
+ max_read_size = 512 * 1024 # currently unused
233
235
234
236
def __init__ (self , m , close_on_deletion , size ):
235
- """Initialize with mmap for stream reading"""
237
+ """Initialize with mmap for stream reading
238
+ :param m: must be content data - use new if you have object data and no size"""
236
239
self ._m = m
237
240
self ._zip = zlib .decompressobj ()
238
241
self ._buf = None # buffer of decompressed bytes
@@ -248,32 +251,38 @@ def __del__(self):
248
251
self ._m .close ()
249
252
# END handle resource freeing
250
253
251
- @classmethod
252
- def new (self , m , close_on_deletion = False ):
253
- """Create a new DecompressMemMapReader instance for acting as a read-only stream
254
- This method parses the object header from m and returns the parsed
255
- type and size, as well as the created stream instance.
256
- :param m: memory map on which to oparate
257
- :param close_on_deletion: if True, the memory map will be closed once we are
258
- being deleted"""
259
- inst = DecompressMemMapReader (m , close_on_deletion , 0 )
260
-
254
+ def _parse_header_info (self ):
255
+ """If this stream contains object data, parse the header info and skip the
256
+ stream to a point where each read will yield object content
257
+ :return: parsed type_string, size"""
261
258
# read header
262
259
maxb = 512 # should really be enough, cgit uses 8192 I believe
263
- inst ._s = maxb
264
- hdr = inst .read (maxb )
260
+ self ._s = maxb
261
+ hdr = self .read (maxb )
265
262
hdrend = hdr .find ("\0 " )
266
263
type , size = hdr [:hdrend ].split (" " )
267
264
size = int (size )
268
- inst ._s = size
265
+ self ._s = size
269
266
270
267
# adjust internal state to match actual header length that we ignore
271
268
# The buffer will be depleted first on future reads
272
- inst ._br = 0
269
+ self ._br = 0
273
270
hdrend += 1 # count terminating \0
274
- inst ._buf = StringIO (hdr [hdrend :])
275
- inst ._buflen = len (hdr ) - hdrend
271
+ self ._buf = StringIO (hdr [hdrend :])
272
+ self ._buflen = len (hdr ) - hdrend
273
+
274
+ return type , size
276
275
276
+ @classmethod
277
+ def new (self , m , close_on_deletion = False ):
278
+ """Create a new DecompressMemMapReader instance for acting as a read-only stream
279
+ This method parses the object header from m and returns the parsed
280
+ type and size, as well as the created stream instance.
281
+ :param m: memory map on which to oparate. It must be object data ( header + contents )
282
+ :param close_on_deletion: if True, the memory map will be closed once we are
283
+ being deleted"""
284
+ inst = DecompressMemMapReader (m , close_on_deletion , 0 )
285
+ type , size = inst ._parse_header_info ()
277
286
return type , size , inst
278
287
279
288
def read (self , size = - 1 ):
@@ -355,17 +364,22 @@ def read(self, size=-1):
355
364
# needs to be as large as the uncompressed bytes we want to read.
356
365
self ._cws = self ._cwe - len (tail )
357
366
self ._cwe = self ._cws + size
358
-
359
-
360
- indata = self ._m [self ._cws :self ._cwe ] # another copy ... :(
361
- # get the actual window end to be sure we don't use it for computations
362
- self ._cwe = self ._cws + len (indata )
363
367
else :
364
368
cws = self ._cws
365
369
self ._cws = self ._cwe
366
370
self ._cwe = cws + size
367
- indata = self ._m [self ._cws :self ._cwe ] # ... copy it again :(
368
371
# END handle tail
372
+
373
+
374
+ # if window is too small, make it larger so zip can decompress something
375
+ win_size = self ._cwe - self ._cws
376
+ if win_size < 8 :
377
+ self ._cwe = self ._cws + 8
378
+ # END adjust winsize
379
+ indata = self ._m [self ._cws :self ._cwe ] # another copy ... :(
380
+
381
+ # get the actual window end to be sure we don't use it for computations
382
+ self ._cwe = self ._cws + len (indata )
369
383
370
384
dcompdat = self ._zip .decompress (indata , size )
371
385
0 commit comments