Merge pull request #110 from dcoshea/sign_coding_and_mem_leak

Fixes for Anvil memory leak and UTF-8 coding in sign text
This commit is contained in:
Tyler Kennedy 2012-10-07 07:36:06 -07:00
commit a1830fee05
3 changed files with 35 additions and 6 deletions

View File

@ -720,6 +720,9 @@ class InfdevChunk(LightedChunk):
root_tag.save(buf=buf) root_tag.save(buf=buf)
return deflate(buf.getvalue()) return deflate(buf.getvalue())
def _discardUncompressed(self):
self.root_tag = None
def _compressChunk(self): def _compressChunk(self):
root_tag = self.root_tag root_tag = self.root_tag
if root_tag is None: if root_tag is None:
@ -730,7 +733,7 @@ class InfdevChunk(LightedChunk):
if self.compressMode == MCRegionFile.VERSION_DEFLATE: if self.compressMode == MCRegionFile.VERSION_DEFLATE:
self.compressedTag = self.compressTagDeflate(root_tag) self.compressedTag = self.compressTagDeflate(root_tag)
self.root_tag = None self._discardUncompressed()
def decompressTagGzip(self, data): def decompressTagGzip(self, data):
return nbt.load(buf=nbt.gunzip(data)) return nbt.load(buf=nbt.gunzip(data))
@ -774,7 +777,7 @@ class InfdevChunk(LightedChunk):
if not self.dirty: if not self.dirty:
# if we are not dirty, just throw the # if we are not dirty, just throw the
# uncompressed tag structure away. rely on the OS disk cache. # uncompressed tag structure away. rely on the OS disk cache.
self.root_tag = None self._discardUncompressed()
else: else:
if self.root_tag is not None: if self.root_tag is not None:
self.sanitizeBlocks() # xxx self.sanitizeBlocks() # xxx
@ -799,6 +802,8 @@ class InfdevChunk(LightedChunk):
try: try:
self._decompressChunk() self._decompressChunk()
except MemoryError:
raise
except Exception, e: except Exception, e:
error(u"Malformed NBT data in file: {0} ({1})".format(self.filename, e)) error(u"Malformed NBT data in file: {0} ({1})".format(self.filename, e))
if self.world: if self.world:
@ -884,6 +889,8 @@ class InfdevChunk(LightedChunk):
self.dataIsPacked = True self.dataIsPacked = True
self.decompress() self.decompress()
except MemoryError:
raise
except Exception, e: except Exception, e:
error(u"Incorrect chunk format in file: {0} ({1})".format(self.filename, e)) error(u"Incorrect chunk format in file: {0} ({1})".format(self.filename, e))
if self.world: if self.world:
@ -1109,6 +1116,14 @@ class AnvilChunk(InfdevChunk):
arr[..., y:y + 16] = secarray.swapaxes(0, 2) arr[..., y:y + 16] = secarray.swapaxes(0, 2)
def _discardUncompressed(self):
self._Blocks = None
self._Data = None
self._BlockLight = None
self._SkyLight = None
super(AnvilChunk, self)._discardUncompressed()
def _compressChunk(self): def _compressChunk(self):
sections = self.root_tag[Level][Sections] = nbt.TAG_List() sections = self.root_tag[Level][Sections] = nbt.TAG_List()
@ -2731,6 +2746,8 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
data = nbt.gunzip(cdata) data = nbt.gunzip(cdata)
chunk.root_tag = nbt.load(buf=data) chunk.root_tag = nbt.load(buf=data)
except MemoryError:
raise
except Exception, e: except Exception, e:
raise ChunkMalformed("Chunk {0} had an error: {1!r}".format(chunk.chunkPosition, e), sys.exc_info()[2]) raise ChunkMalformed("Chunk {0} had an error: {1!r}".format(chunk.chunkPosition, e), sys.exc_info()[2])

18
mce.py
View File

@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
import mclevelbase
import mclevel import mclevel
import infiniteworld import infiniteworld
import sys import sys
@ -604,7 +605,15 @@ class mce(object):
else: else:
filename = self.level.displayName + ".signs" filename = self.level.displayName + ".signs"
outFile = codecs.open(filename, "w", encoding='utf-8') # It appears that Minecraft interprets the sign text as UTF-8,
# so we should decode it as such too.
decodeSignText = codecs.getdecoder('utf-8')
# We happen to encode the output file in UTF-8 too, although
# we could use another UTF encoding. The '-sig' encoding puts
# a signature at the start of the output file that tools such
# as Microsoft Windows Notepad and Emacs understand to mean
# the file has UTF-8 encoding.
outFile = codecs.open(filename, "w", encoding='utf-8-sig')
print "Dumping signs..." print "Dumping signs..."
signCount = 0 signCount = 0
@ -612,7 +621,7 @@ class mce(object):
for i, cPos in enumerate(self.level.allChunks): for i, cPos in enumerate(self.level.allChunks):
try: try:
chunk = self.level.getChunk(*cPos) chunk = self.level.getChunk(*cPos)
except mclevel.ChunkMalformed: except mclevelbase.ChunkMalformed:
continue continue
for tileEntity in chunk.TileEntities: for tileEntity in chunk.TileEntities:
@ -621,7 +630,8 @@ class mce(object):
outFile.write(str(map(lambda x: tileEntity[x].value, "xyz")) + "\n") outFile.write(str(map(lambda x: tileEntity[x].value, "xyz")) + "\n")
for i in range(4): for i in range(4):
outFile.write(tileEntity["Text{0}".format(i + 1)].value + u"\n") signText = tileEntity["Text{0}".format(i + 1)].value
outFile.write(decodeSignText(signText)[0] + u"\n")
if i % 100 == 0: if i % 100 == 0:
print "Chunk {0}...".format(i) print "Chunk {0}...".format(i)
@ -770,7 +780,7 @@ class mce(object):
for i, cPos in enumerate(self.level.allChunks): for i, cPos in enumerate(self.level.allChunks):
try: try:
chunk = self.level.getChunk(*cPos) chunk = self.level.getChunk(*cPos)
except mclevel.ChunkMalformed: except mclevelbase.ChunkMalformed:
continue continue
for tileEntity in chunk.TileEntities: for tileEntity in chunk.TileEntities:

View File

@ -132,6 +132,8 @@ class MCSchematic (EntityLevel):
try: try:
self.root_tag = nbt.load(buf=data) self.root_tag = nbt.load(buf=data)
except MemoryError:
raise
except Exception, e: except Exception, e:
error(u"Malformed NBT data in schematic file: {0} ({1})".format(self.filename, e)) error(u"Malformed NBT data in schematic file: {0} ({1})".format(self.filename, e))
raise ChunkMalformed((e, self.filename), sys.exc_info()[2]) raise ChunkMalformed((e, self.filename), sys.exc_info()[2])