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