0

nbt: code style fixes

We're ignoring E221 and E741 since I disagree with them; I think extra
whitespace around operators to align repeated operations can aid
readability and help spot bugs.

This was mostly whitespace issues, e.g. trailing whitespace and
a single space on blank lines.
This commit is contained in:
Nicolas F
2019-03-02 15:44:58 +01:00
parent 336850ea04
commit 846b7ab8f8

View File

@@ -13,10 +13,12 @@
# You should have received a copy of the GNU General Public License along
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
import gzip, zlib
import struct
import StringIO
import functools
import gzip
import StringIO
import struct
import zlib
# decorator that turns the first argument from a string into an open file
# handle
@@ -29,13 +31,15 @@ def _file_loader(func):
return func(fileobj, *args)
return wrapper
@_file_loader
def load(fileobj):
"""Reads in the given file as NBT format, parses it, and returns the
result as a (name, data) tuple.
result as a (name, data) tuple.
"""
return NBTFileReader(fileobj).read_all()
@_file_loader
def load_region(fileobj):
"""Reads in the given file as a MCR region, and returns an object
@@ -45,23 +49,29 @@ def load_region(fileobj):
class CorruptionError(Exception):
pass
class CorruptRegionError(CorruptionError):
"""An exception raised when the MCRFileReader class encounters an
error during region file parsing.
"""
pass
class CorruptChunkError(CorruptionError):
pass
class CorruptNBTError(CorruptionError):
"""An exception raised when the NBTFileReader class encounters
something unexpected in an NBT file."""
pass
class NBTFileReader(object):
"""Low level class that reads the Named Binary Tag format used by Minecraft
"""
# compile the unpacker's into a classes
_byte = struct.Struct("b")
_short = struct.Struct(">h")
@@ -70,8 +80,8 @@ class NBTFileReader(object):
_uint = struct.Struct(">I")
_long = struct.Struct(">q")
_float = struct.Struct(">f")
_double = struct.Struct(">d")
_double = struct.Struct(">d")
def __init__(self, fileobj, is_gzip=True):
"""Create a NBT parsing object with the given file-like
object. Setting is_gzip to False parses the file as a zlib
@@ -96,9 +106,9 @@ class NBTFileReader(object):
7: self._read_tag_byte_array,
8: self._read_tag_string,
9: self._read_tag_list,
10:self._read_tag_compound,
11:self._read_tag_int_array,
12:self._read_tag_long_array,
10: self._read_tag_compound,
11: self._read_tag_int_array,
12: self._read_tag_long_array,
}
# These private methods read the payload only of the following types
@@ -109,7 +119,7 @@ class NBTFileReader(object):
def _read_tag_byte(self):
byte = self._file.read(1)
return self._byte.unpack(byte)[0]
def _read_tag_short(self):
bytes = self._file.read(2)
return self._short.unpack(bytes)[0]
@@ -137,12 +147,12 @@ class NBTFileReader(object):
def _read_tag_int_array(self):
length = self._uint.unpack(self._file.read(4))[0]
int_bytes = self._file.read(length*4)
int_bytes = self._file.read(length * 4)
return struct.unpack(">%ii" % length, int_bytes)
def _read_tag_long_array(self):
length = self._uint.unpack(self._file.read(4))[0]
long_bytes = self._file.read(length*8)
long_bytes = self._file.read(length * 8)
return struct.unpack(">%iq" % length, long_bytes)
def _read_tag_string(self):
@@ -177,7 +187,7 @@ class NBTFileReader(object):
tags[name] = payload
return tags
def read_all(self):
"""Reads the entire file and returns (name, payload)
name is the name of the root tag, and payload is a dictionary mapping
@@ -189,15 +199,14 @@ class NBTFileReader(object):
tagtype = ord(self._file.read(1))
if tagtype != 10:
raise Exception("Expected a tag compound")
# Read the tag name
name = self._read_tag_string()
payload = self._read_tag_compound()
return (name, payload)
except (struct.error, ValueError, TypeError), e:
raise CorruptNBTError("could not parse nbt: %s" % (str(e),))
# For reference, the MCR format is outlined at
# <http://www.minecraftwiki.net/wiki/Beta_Level_Format>
class MCRFileReader(object):
@@ -206,16 +215,16 @@ class MCRFileReader(object):
chunks (as (name, data) tuples), getting chunk timestamps, and for
listing chunks contained in the file.
"""
_location_table_format = struct.Struct(">1024I")
_timestamp_table_format = struct.Struct(">1024i")
_chunk_header_format = struct.Struct(">I B")
def __init__(self, fileobj):
"""This creates a region object from the given file-like
object. Chances are you want to use load_region instead."""
self._file = fileobj
# read in the location table
location_data = self._file.read(4096)
if not len(location_data) == 4096:
@@ -234,29 +243,29 @@ class MCRFileReader(object):
with keeping it open. Using this object after closing it
results in undefined behaviour.
"""
self._file.close()
self._file = None
def get_chunks(self):
def get_chunks(self):
"""Return an iterator of all chunks contained in this region
file, as (x, z) coordinate tuples. To load these chunks,
provide these coordinates to load_chunk()."""
for x in xrange(32):
for z in xrange(32):
for x in xrange(32):
for z in xrange(32):
if self._locations[x + z * 32] >> 8 != 0:
yield (x,z)
yield (x, z)
def get_chunk_timestamp(self, x, z):
"""Return the given chunk's modification time. If the given
chunk doesn't exist, this number may be nonsense. Like
load_chunk(), this will wrap x and z into the range [0, 31].
"""
x = x % 32
z = z % 32
return self._timestamps[x + z * 32]
z = z % 32
return self._timestamps[x + z * 32]
def chunk_exists(self, x, z):
"""Determines if a chunk exists."""
x = x % 32
@@ -273,40 +282,42 @@ class MCRFileReader(object):
x = x % 32
z = z % 32
location = self._locations[x + z * 32]
offset = (location >> 8) * 4096;
sectors = location & 0xff;
offset = (location >> 8) * 4096
sectors = location & 0xff
if offset == 0:
return None
# seek to the data
self._file.seek(offset)
# read in the chunk data header
header = self._file.read(5)
if len(header) != 5:
raise CorruptChunkError("chunk header is invalid")
data_length, compression = self._chunk_header_format.unpack(header)
data_length, compression = self._chunk_header_format.unpack(header)
# figure out the compression
is_gzip = True
if compression == 1:
# gzip -- not used by the official client, but trivial to support here so...
# gzip -- not used by the official client, but trivial to
# support here so...
is_gzip = True
elif compression == 2:
# deflate -- pure zlib stream
is_gzip = False
else:
# unsupported!
raise CorruptRegionError("unsupported chunk compression type: %i (should be 1 or 2)" % (compression,))
raise CorruptRegionError("unsupported chunk compression type: %i "
"(should be 1 or 2)" % (compression,))
# turn the rest of the data into a StringIO object
# (using data_length - 1, as we already read 1 byte for compression)
data = self._file.read(data_length - 1)
if len(data) != data_length - 1:
raise CorruptRegionError("chunk length is invalid")
data = StringIO.StringIO(data)
try:
return NBTFileReader(data, is_gzip=is_gzip).read_all()
except CorruptionError: