workarounds for a bug in python's gzip module - it will raise an error when trying to decompress any extra bytes that follow the first gzip packet
changed (de)compressTag to (de)compressChunk - the chunk is now in charge of setting chunk.root_tag and chunk.compressedTag the region file sets chunk.compressMode on new chunks, which is VERSION_GZIP by default
This commit is contained in:
parent
6d4f29726b
commit
53be8e48bf
120
mclevel.py
120
mclevel.py
@ -957,8 +957,7 @@ class MCLevel(object):
|
||||
compressed = True
|
||||
unzippedData = None;
|
||||
try:
|
||||
with closing(gzip.GzipFile(fileobj=StringIO.StringIO(rawdata))) as gz:
|
||||
unzippedData = gz.read();
|
||||
unzippedData = gunzip(rawdata)
|
||||
except Exception,e:
|
||||
info( u"Exception during Gzip operation, assuming {0} uncompressed: {1!r}".format(filename, e) )
|
||||
if unzippedData is None:
|
||||
@ -1806,6 +1805,7 @@ class InfdevChunk(MCLevel):
|
||||
self.root_tag = None
|
||||
self.dirty = False;
|
||||
self.needsLighting = False
|
||||
self.compressMode = MCRegionFile.VERSION_GZIP
|
||||
|
||||
if create:
|
||||
self.create();
|
||||
@ -1813,6 +1813,45 @@ class InfdevChunk(MCLevel):
|
||||
if not world.containsChunk(*chunkPosition):
|
||||
raise ChunkNotPresent("Chunk {0} not found", self.chunkPosition)
|
||||
|
||||
|
||||
def compressTagGzip(self, root_tag):
|
||||
buf = StringIO.StringIO()
|
||||
with closing(gzip.GzipFile(fileobj=buf, mode='wb', compresslevel=2)) as gzipper:
|
||||
root_tag.save(buf=gzipper)
|
||||
|
||||
return buf.getvalue()
|
||||
|
||||
def compressTagDeflate(self, root_tag):
|
||||
buf = StringIO.StringIO()
|
||||
root_tag.save(buf=buf)
|
||||
return deflate(buf.getvalue())
|
||||
|
||||
def _compressChunk(self):
|
||||
root_tag = self.root_tag
|
||||
if root_tag is None: return
|
||||
|
||||
if self.compressMode == MCRegionFile.VERSION_GZIP:
|
||||
self.compressedTag = self.compressTagGzip(root_tag)
|
||||
if self.compressMode == MCRegionFile.VERSION_DEFLATE:
|
||||
self.compressedTag = self.compressTagDeflate(root_tag)
|
||||
|
||||
self.root_tag = None
|
||||
|
||||
def decompressTagGzip(self, data):
|
||||
return nbt.load(buf=gunzip(data))
|
||||
|
||||
def decompressTagDeflate(self, data):
|
||||
return nbt.load(buf=inflate(data))
|
||||
|
||||
def _decompressChunk(self):
|
||||
data = self.compressedTag
|
||||
|
||||
if self.compressMode == MCRegionFile.VERSION_GZIP:
|
||||
self.root_tag = self.decompressTagGzip(data)
|
||||
if self.compressMode == MCRegionFile.VERSION_DEFLATE:
|
||||
self.root_tag = self.decompressTagDeflate(data)
|
||||
|
||||
|
||||
def compressedSize(self):
|
||||
"return the size of the compressed data for this level, in bytes."
|
||||
self.compress();
|
||||
@ -1829,7 +1868,7 @@ class InfdevChunk(MCLevel):
|
||||
self.root_tag = None
|
||||
else:
|
||||
self.packChunkData()
|
||||
self.compressedTag = self.world.compressTag(self.root_tag)
|
||||
self._compressChunk(self)
|
||||
|
||||
self.world.chunkDidCompress(self);
|
||||
|
||||
@ -1846,7 +1885,7 @@ class InfdevChunk(MCLevel):
|
||||
|
||||
|
||||
try:
|
||||
self.root_tag = self.world.decompressTag(self.compressedTag)
|
||||
self._decompressChunk()
|
||||
|
||||
except Exception, e:
|
||||
error( u"Malformed NBT data in file: {0} ({1})".format(self.filename, e) )
|
||||
@ -2319,14 +2358,15 @@ class MCRegionFile(object):
|
||||
chunk.compressedTag = data[5:]
|
||||
|
||||
chunk.root_tag = nbt.load(buf=self.decompressSectors(data))
|
||||
|
||||
chunk.compressMode = struct.unpack_from("B", data, 4)[0]
|
||||
|
||||
|
||||
def decompressSectors(self, data):
|
||||
length = struct.unpack_from(">I", data)[0]
|
||||
format = struct.unpack_from("B", data, 4)[0]
|
||||
data = data[5:length+5]
|
||||
if format == self.VERSION_GZIP:
|
||||
with closing(gzip.GzipFile(fileobj=StringIO.StringIO(data))) as gz:
|
||||
return gz.read()
|
||||
return gunzip(data)
|
||||
if format == self.VERSION_DEFLATE:
|
||||
return inflate(data)
|
||||
|
||||
@ -2452,55 +2492,15 @@ def deflate(data):
|
||||
return zlib.compress(data)
|
||||
def inflate(data):
|
||||
return zlib.decompress(data)
|
||||
|
||||
|
||||
from nbt import gunzip
|
||||
|
||||
class MCInfdevOldLevel(MCLevel):
|
||||
materials = alphaMaterials;
|
||||
hasEntities = True;
|
||||
parentWorld = None;
|
||||
dimNo = 0;
|
||||
ChunkHeight = 128
|
||||
|
||||
compressMode = MCRegionFile.VERSION_DEFLATE
|
||||
|
||||
@property
|
||||
def compressMode(self):
|
||||
if self.version:
|
||||
return MCRegionFile.VERSION_DEFLATE
|
||||
else:
|
||||
return MCRegionFile.VERSION_GZIP
|
||||
|
||||
def compressTagGzip(self, root_tag):
|
||||
buf = StringIO.StringIO()
|
||||
with closing(gzip.GzipFile(fileobj=buf, mode='wb', compresslevel=2)) as gzipper:
|
||||
root_tag.save(buf=gzipper)
|
||||
|
||||
return buf.getvalue()
|
||||
|
||||
def compressTagDeflate(self, root_tag):
|
||||
buf = StringIO.StringIO()
|
||||
root_tag.save(buf=buf)
|
||||
return deflate(buf.getvalue())
|
||||
|
||||
def compressTag(self, root_tag):
|
||||
if self.compressMode == MCRegionFile.VERSION_GZIP:
|
||||
return self.compressTagGzip(root_tag)
|
||||
if self.compressMode == MCRegionFile.VERSION_DEFLATE:
|
||||
return self.compressTagDeflate(root_tag)
|
||||
|
||||
def decompressTagGzip(self, data):
|
||||
with closing(gzip.GzipFile(fileobj=StringIO.StringIO(data))) as gz:
|
||||
return nbt.load(buf=gz.read())
|
||||
|
||||
def decompressTagDeflate(self, data):
|
||||
return nbt.load(buf=inflate(data))
|
||||
|
||||
def decompressTag(self, data):
|
||||
if self.compressMode == MCRegionFile.VERSION_GZIP:
|
||||
return self.decompressTagGzip(data)
|
||||
if self.compressMode == MCRegionFile.VERSION_DEFLATE:
|
||||
return self.decompressTagDeflate(data)
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def displayName(self):
|
||||
@ -2907,10 +2907,9 @@ class MCInfdevOldLevel(MCLevel):
|
||||
with file(chunk.filename, 'rb') as f:
|
||||
cdata = f.read()
|
||||
chunk.compressedTag = cdata
|
||||
with closing(gzip.GzipFile(fileobj=StringIO.StringIO(cdata))) as gz:
|
||||
data = gz.read()
|
||||
chunk.root_tag = nbt.load(buf=data)
|
||||
|
||||
data = gunzip(cdata)
|
||||
chunk.root_tag = nbt.load(buf=data)
|
||||
|
||||
except Exception, e:
|
||||
raise ChunkMalformed, "Chunk {0} had an error: {1!r}".format(chunk.chunkPosition, e)
|
||||
|
||||
@ -3000,9 +2999,13 @@ class MCInfdevOldLevel(MCLevel):
|
||||
outputFile = os.path.join(parentFolder, os.path.basename(chunkFilename))
|
||||
|
||||
chunk = self.getChunk(cx,cz)
|
||||
chunk.decompress()
|
||||
data = self.compressTagGzip(chunk.root_tag)
|
||||
|
||||
if chunk.compressMode == MCRegionFile.VERSION_GZIP:
|
||||
chunk.compress()
|
||||
data = chunk.compressedTag;
|
||||
else:
|
||||
chunk.decompress()
|
||||
data = chunk.compressTagGzip(chunk.root_tag)
|
||||
|
||||
with file(outputFile, "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
@ -4106,8 +4109,7 @@ class ZipSchematic (MCInfdevOldLevel):
|
||||
try:
|
||||
schematicDat = os.path.join(tempdir, "schematic.dat")
|
||||
with closing(self.zipfile.open("schematic.dat")) as f:
|
||||
with closing(gzip.GzipFile(fileobj=StringIO.StringIO(f.read()))) as g:
|
||||
schematicDat = nbt.load(buf=g.read())
|
||||
schematicDat = nbt.load(buf=gunzip(f.read()))
|
||||
|
||||
self.Width = schematicDat['Width'].value;
|
||||
self.Height = schematicDat['Height'].value;
|
||||
|
11
nbt.py
11
nbt.py
@ -407,11 +407,18 @@ tag_handlers = {
|
||||
def assert_type(t, offset) :
|
||||
if not t in tag_handlers: raise TypeError("Unexpected type %d at %d" % (t, offset));
|
||||
|
||||
import zlib
|
||||
def gunzip(data):
|
||||
#strip off the header and use negative WBITS to tell zlib there's no header
|
||||
return zlib.decompress(data[10:], -zlib.MAX_WBITS)
|
||||
|
||||
def loadFile(filename):
|
||||
#sio = StringIO.StringIO();
|
||||
inputGz = gzip.GzipFile(filename, mode="rb")
|
||||
with file(filename, "rb") as f:
|
||||
inputdata = f.read()
|
||||
#inputGz = gzip.GzipFile(filename, mode="rb")
|
||||
try:
|
||||
data = inputGz.read();
|
||||
data = gunzip(inputdata)
|
||||
except IOError:
|
||||
print "File %s not zipped" % filename
|
||||
data = file(filename, "rb").read();
|
||||
|
Reference in New Issue
Block a user