48
48
This returns the final compressed chunk, and either None, or the
49
49
bytes that did not fit in the chunk.
51
self.bytes_in = None # Free the data cached so far, we don't need it
51
52
self.bytes_list.append(self.compressor.flush(Z_FINISH))
52
self.position += len(self.bytes_list[-1])
53
nulls_needed = self.chunk_size - self.position % self.chunk_size
53
total_len = sum(len(b) for b in self.bytes_list)
54
nulls_needed = self.chunk_size - total_len % self.chunk_size
55
56
self.bytes_list.append("\x00" * nulls_needed)
56
57
return self.bytes_list, self.unused_bytes
59
def _recompress_all_bytes_in(self, extra_bytes=None):
60
compressor = zlib.compressobj()
62
for accepted_bytes in self.bytes_in:
63
out = compressor.compress(accepted_bytes)
67
out = compressor.compress(extra_bytes)
70
out = compressor.flush(Z_SYNC_FLUSH)
73
return bytes_out, compressor
58
75
def write(self, bytes):
59
76
"""Write some bytes to the chunk.
61
78
If the bytes fit, False is returned. Otherwise True is returned
62
79
and the bytes have not been added to the chunk.
64
# Reject content if its likely to fail to fit. The 10 constant is to
65
# allow room for the zlib END_STREAM record in the Z_FINISH flush call.
66
if (self.seen_bytes > self.chunk_size and
67
self.position + 10 + len(bytes) > self.chunk_size):
68
self.unused_bytes = bytes
70
self.bytes_list.append(self.compressor.compress(bytes))
71
self.position += len(self.bytes_list[-1])
72
self.seen_bytes += len(bytes)
73
# If we are at the end of what we know will fit, flush.
74
if self.seen_bytes > self.chunk_size:
75
# Note: we could strip the \x00\x00\xff\xff and reinsert it in the
76
# reader - see rfc1979. syncing on every call imposes a increase in
77
# compressed size. e.g. 3661 vs 4050 bytes for 40 200 byte rows.
78
self.bytes_list.append(self.compressor.flush(Z_SYNC_FLUSH))
79
self.position += len(self.bytes_list[-1])
81
# Add these bytes using Z_SYNC_FLUSH, if it puts us over budget, we
82
# will try packing everything tighter, if that still fails, then we
83
# will reject this request.
84
out = self.compressor.compress(bytes)
86
self.bytes_list.append(out)
87
out = self.compressor.flush(Z_SYNC_FLUSH)
89
self.bytes_list.append(out)
90
total_len = sum(len(b) for b in self.bytes_list)
91
# Give us some extra room for a final Z_FINISH call.
92
if total_len + 10 > self.chunk_size:
93
# We are over budget, try to squeeze this in without any
95
bytes_out, compressor = self._recompress_all_bytes_in(bytes)
96
this_len = sum(len(b) for b in bytes_out)
97
if this_len + 10 > self.chunk_size:
98
# No way we can add anymore, we need to re-pack because our
99
# compressor is now out of sync
100
bytes_out, compressor = self._recompress_all_bytes_in()
101
self.compressor = compressor
102
self.bytes_list = bytes_out
103
self.unused_bytes = bytes
106
# This fits when we pack it tighter, so use the new packing
107
self.compressor = compressor
108
self.bytes_in.append(bytes)
109
self.bytes_list = bytes_out
111
# It fit, so mark it added
112
self.bytes_in.append(bytes)