def __init__(self, num_tiles, tile_width=8, tile_height=8): """Creates a new EbGraphicTileset. :param num_tiles: the number of tiles in this tileset :param tile_width: width in pixels of each of the tileset's individual tiles :param tile_height: height in pixels of each of the tileset's individual tiles""" if num_tiles <= 0: raise InvalidArgumentError( "Couldn't create EbGraphicTileset with invalid num_tiles[{}]". format(num_tiles)) self.num_tiles_maximum = num_tiles if tile_width <= 0: raise InvalidArgumentError( "Couldn't create EbGraphicTileset with invalid tile_width[{}]". format(tile_width)) elif (tile_width % 8) != 0: raise InvalidArgumentError(( "Couldn't create EbGraphicTileset with a tile_height[{}] that is not a " "multiple of 8").format(tile_height)) self.tile_width = tile_width if tile_height <= 0: raise InvalidArgumentError( "Couldn't create EbGraphicTileset with invalid tile height[{}]" .format(tile_height)) self.tile_height = tile_height self.tiles = [] self._num_tiles_used = 0 self._used_tiles = dict()
def __init__(self, width, height): """Creates a new EbTileArrangement. :param width: the width of the arrangement in tiles :param height: the height of the arrangement in tiles""" if width <= 0: raise InvalidArgumentError("Couldn't create EbTileArrangement with invalid width[{}]".format(width)) self.width = width if height <= 0: raise InvalidArgumentError("Couldn't create EbTileArrangement with invalid height[{}]".format(height)) self.height = height self.arrangement = [[EbTileArrangementItem() for x in range(self.width)] for y in range(self.height)]
def setup_eb_palette_from_image(palette, img, tile_width, tile_height): num_subpalettes = palette.num_subpalettes subpalette_length = palette.subpalette_length width, height = img.size rgb_image = img.convert("RGB") rgb_image_data = rgb_image.load() del rgb_image # First, get a list of all the unique sets of colors in each tile color_sets = [] for x in xrange(0, width, tile_width): for y in xrange(0, height, tile_height): new_color_set = set() for tile_x in xrange(x, x + tile_width): for tile_y in xrange(y, y + tile_height): r, g, b = rgb_image_data[tile_x, tile_y] r &= 0xf8 g &= 0xf8 b &= 0xf8 new_color_set.add((r, g, b)) if len(new_color_set) > subpalette_length: raise InvalidArgumentError( "Too many unique colors in the {}x{} box at ({},{}) in the image to fit into {} subpalettes," " each having {} colors".format(tile_width, tile_height, x, y, num_subpalettes, subpalette_length)) for i, color_set in enumerate(color_sets): if new_color_set.issubset(color_set): break elif new_color_set.issuperset(color_set): color_sets[i] = new_color_set break else: color_sets.append(new_color_set) # Next, find a way to fit all the sets of colors into a palette color_sets = join_sets(color_sets, num_subpalettes, subpalette_length) if color_sets is None: raise InvalidArgumentError( "Too many unique colors in the image to fit into {} subpalettes, each having {} colors" .format(num_subpalettes, subpalette_length)) for subpalette_id, color_set in enumerate(color_sets): for color_id, rgb in enumerate(color_set): palette[subpalette_id, color_id].from_tuple(rgb) return palette
def from_image_data(self, image_data, y): x1, x2, x3, x4 = None, None, None, None for x in range(256): if x1 is None: if image_data[x, y] == 1: x1 = x elif x2 is None: if image_data[x, y] == 0: x2 = x - 1 elif x3 is None: if image_data[x, y] == 1: x3 = x elif x4 is None: if image_data[x, y] == 0: x4 = x - 1 else: if image_data[x, y] == 1: raise InvalidArgumentError( "There are more than two lines on the same row at y={}" .format(y)) if x1 is None: self.x1 = 0xff self.x2 = 0 elif x2 is None: self.x1 = x1 self.x2 = 0xff else: if x1 == x2: raise InvalidArgumentError( "Line at ({},{}) must be at least 2 pixels wide".format( x1, y)) self.x1 = x1 self.x2 = x2 if x3 is None: self.x3 = 0xff self.x4 = 0 elif x4 is None: self.x3 = x3 self.x4 = 0xff else: if x3 == x4: raise InvalidArgumentError( "Line at ({},{}) must be at least 2 pixels wide".format( x1, y)) self.x3 = x3 self.x4 = x4
def __getitem__(self, key): subpalette_number, color_number = key if subpalette_number < 0 or color_number < 0 or subpalette_number >= self.num_subpalettes \ or color_number >= self.subpalette_length: raise InvalidArgumentError("Could not get color[{},{}] from palette of size[{},{}]".format( subpalette_number, color_number, self.num_subpalettes, self.subpalette_length)) return self.subpalettes[subpalette_number][color_number]
def __init__(self, address=None, size=3): if size is None or size <= 0: raise InvalidArgumentError( "Cannot create pointer with non-positive size[%d]" % size) self.size = 3 if address is not None: self.address = address
def eb_table_from_offset(offset, single_column=None, matrix_dimensions=None, hidden_columns=None, num_rows=None, name=None): if hidden_columns is None: hidden_columns = [] try: schema_specification = _EB_SCHEMA_MAP[offset] except KeyError: raise InvalidArgumentError( "Could not setup EbTable from unknown offset[{:#x}]".format( offset)) if single_column: schema = single_column else: schema = EbRowTableEntry.from_schema_specification( schema_specification=schema_specification["entries"], hidden_columns=hidden_columns) if matrix_dimensions: matrix_width, matrix_height = matrix_dimensions return MatrixTable(schema=schema, matrix_height=matrix_height, name=name or schema_specification["name"], size=schema_specification["size"]) else: return Table(schema=schema, name=name or schema_specification["name"], size=schema_specification["size"], num_rows=num_rows)
def __getitem__(self, key): x, y = key if x < 0 or y < 0 or x >= self.width or y >= self.height: raise InvalidArgumentError( "Couldn't get arrangement item[{},{}] from arrangement of size[{}x{}]" .format(x, y, self.width, self.height)) return self.arrangement[y][x]
def __init__(self, num_subpalettes, subpalette_length, rgb_list=None): """Creates a new EbPalette. :param num_subpalettes: the number of subpalettes within the palette. :param subpalette_length: the number of colors within each subpalette.""" if num_subpalettes <= 0: raise InvalidArgumentError("Couldn't create EbPalette with invalid num_subpalettes[{}]".format( num_subpalettes)) self.num_subpalettes = num_subpalettes if subpalette_length <= 0: raise InvalidArgumentError("Couldn't create EbPalette with invalid subpalette_length[{}]".format( subpalette_length)) self.subpalette_length = subpalette_length self.subpalettes = [[EbColor() for j in range(self.subpalette_length)] for i in range(self.num_subpalettes)] if rgb_list is not None: self.from_list(rgb_list)
def from_snes_address(address): if address < 0: raise InvalidArgumentError( "Invalid snes address[{:#x}]".format(address)) elif address >= 0xc00000: return address - 0xc00000 else: return address
def check_range_validity(range, size): begin, end = range if end < begin: raise InvalidArgumentError("Invalid range[(%#x,%#x)] provided" % (begin, end)) elif (begin < 0) or (end >= size): raise OutOfBoundsError("Invalid range[(%#x,%#x)] provided" % (begin, end))
def read_from_yml_data(self, yml_data): self.text = yml_data[self.key]['text'] self.mode = yml_data[self.key]['mode'] if self.mode not in DYNAMIC_CAST_NAME_MODES: raise InvalidArgumentError( 'Invalid dynamic cast name mode \'{}\' for entry with text \'{}\'. Valid modes are {}' .format(self.mode, self.name, DYNAMIC_CAST_NAME_MODES))
def fromstring(cls, s): value = getattr(cls, s.upper(), None) if value is None: from coilsnake.exceptions.common.exceptions import InvalidArgumentError raise InvalidArgumentError( "Could not convert string[%s] to class[%s] because the value was " "undefined" % (s, cls.__name__)) return value
def tostring(cls, val): for k, v in vars(cls).items(): if v == val: return k.lower() from coilsnake.exceptions.common.exceptions import InvalidArgumentError raise InvalidArgumentError( "Could not convert value[%s] to string because the value was undefined" % val)
def to_block(self, block, offset, is_mode_01): if is_mode_01 and self.x3 != 0xff and self.x4 != 0: raise InvalidArgumentError( "Cannot write row with two lines in only two bytes") block[offset] = self.x1 block[offset + 1] = self.x2 if not is_mode_01: block[offset + 2] = self.x3 block[offset + 3] = self.x4
def __setitem__(self, key, item): subpalette_number, color_number = key if subpalette_number < 0 or subpalette_number >= self.num_subpalettes \ or (isinstance(color_number, int) and (color_number < 0 or color_number >= self.subpalette_length)): raise InvalidArgumentError( "Could not set color[{},{}] of palette of size[{},{}]".format( subpalette_number, color_number, self.num_subpalettes, self.subpalette_length)) self.subpalettes[subpalette_number][color_number] = item
def __setitem__(self, key, item): if isinstance(key, int) and isinstance(item, (int, int)): if item < 0 or item > 0xff: raise InvalidArgumentError( "Could not write invalid value[%d] as a single byte" % item) if key >= self.size: raise OutOfBoundsError( "Attempted to write to offset[%#x] which is out of bounds" % key) else: self.data[key] = item elif isinstance(key, slice) and \ (isinstance(item, list) or isinstance(item, array.array) or isinstance(item, Block)): if key.start > key.stop: raise InvalidArgumentError( "Second argument of slice %s must be greater than the first" % key) elif (key.start < 0) or (key.stop - 1 >= self.size): raise OutOfBoundsError( "Attempted to write to range (%#x,%#x) which is out of bounds" % (key.start, key.stop - 1)) elif len(item) != (key.stop - key.start): raise InvalidArgumentError( "Attempted to write data of size %d to range of length %d" % (len(item), key.stop - key.start)) elif (key.stop - key.start) == 0: raise InvalidArgumentError("Attempted to write data of size 0") else: if isinstance(item, list): self.data[key] = array.array('B', item) elif isinstance(item, array.array): self.data[key] = item elif isinstance(item, Block): self.data[key] = item.data else: raise InvalidArgumentError( "Can not write value of type[{}]".format(type(item))) else: raise TypeError( "Arguments \"key\" and \"item\" had invalid types of %s and %s" % (type(key).__name__, type(item).__name__))
def recreate(self, num_rows=None, size=None): if num_rows is not None: self.num_rows = num_rows else: if size % self.schema.size != 0: raise InvalidArgumentError( "Cannot create table[{}] with rows of size[{}] and total size[{}]" .format(self.name, self.schema.size, size)) self.num_rows = size // self.schema.size self.size = self.schema.size * self.num_rows self.values = [None for i in range(self.num_rows)]
def allocate(self, data=None, size=None, can_write_to=None): if data is None and size is None: raise InvalidArgumentError("Insufficient parameters provided") if size is None: size = len(data) elif data is not None and size != len(data): raise InvalidArgumentError( "Parameter size[%d] and data's size[%d] differ" % (size, len(data))) if size <= 0: raise InvalidArgumentError("Cannot allocate a range of size[%d]" % size) # First find a free range allocated_range = None for i in range(0, len(self.unallocated_ranges)): begin, end = self.unallocated_ranges[i] if size <= end - begin + 1: if (can_write_to is not None) and (not can_write_to(begin)): continue if begin + size - 1 == end: # Used up the entire free range del (self.unallocated_ranges[i]) else: self.unallocated_ranges[i] = (begin + size, end) allocated_range = (begin, begin + size - 1) break if allocated_range is None: raise NotEnoughUnallocatedSpaceError("Not enough free space left") if data is not None: self[allocated_range[0]:allocated_range[1] + 1] = data return allocated_range[0]
def to_table_entry_class(cls, column_specification): class_name = "GeneratedTableEntry_{}".format( column_specification["name"]) column_specification["size"] = getitem_with_default( column_specification, "size", 1) column_specification["type"] = getitem_with_default( column_specification, "type", cls.DEFAULT_TABLE_ENTRY_TYPE) if (column_specification["type"] == "int") and ("values" in column_specification): return EnumeratedLittleEndianIntegerTableEntry.create( column_specification["name"], column_specification["size"], column_specification["values"]) elif (column_specification["type"] == "bitfield") and ("bitvalues" in column_specification): enumeration_class = GenericEnum.create( name=class_name, values=column_specification["bitvalues"]) return BitfieldTableEntry.create( name=column_specification["name"], size=column_specification["size"], enumeration_class=enumeration_class) else: try: entry_class, parameter_list = cls.TABLE_ENTRY_CLASS_MAP[ column_specification["type"]] except KeyError: raise InvalidArgumentError( "Unknown table column type[{}]".format( column_specification["type"])) try: parameters = dict( map(lambda x: (x, column_specification[x]), parameter_list)) except KeyError: raise InvalidArgumentError( "Column[{}] in table schema not provided with all required attributes[{}]" .format(column_specification["name"], parameter_list)) return type(class_name, (entry_class, ), parameters)
def write_multi(self, key, item, size): if size < 0: raise InvalidArgumentError( "Attempted to write data of negative length[%d]" % size) elif (key < 0) or (key >= self.size) or (key + size > self.size): raise OutOfBoundsError( "Attempted to write size[%d] bytes to offset[%#x], which is out of bounds in this " "block of size[%#x]" % (size, key, self.size)) elif size == 0: return else: for i in range(key, key + size): self.data[i] = item & 0xff item >>= 8
def __init__(self, schema, name="Anonymous Table", size=None, num_rows=None): self.name = name if size is None and num_rows is None: raise InvalidArgumentError( "Cannot create table[{}] with null size and null num_rows". format(self.name)) self.schema = schema self.recreate(num_rows=num_rows, size=size)
def read_from_project(self, resource_open): formatting_data = {} with resource_open(CAST_FORMATTING_FILE_NAME, 'yml', True) as f: formatting_data = yml_load(f) for fmt_entry in formatting_data: entry = EbCastEntry() entry.set_values(formatting_data[fmt_entry]['begin'], formatting_data[fmt_entry]['size'], formatting_data[fmt_entry]['misc']) self.entries.append(entry) if entry.size == 0: raise InvalidArgumentError( 'Cast graphics entry number {} has size 0 - would crash the cast screen.' .format(fmt_entry))
def read_multi(self, key, size): if size < 0: raise InvalidArgumentError( "Attempted to read data of negative length[%d]" % size) elif size == 0: return 0 elif (key < 0) or (key >= self.size) or (key + size > self.size): raise OutOfBoundsError( "Attempted to read size[%d] bytes from offset[%#x], which is out of bounds in this " "block of size[%#x]" % (size, key, self.size)) else: out = 0 bit_offset = 0 for byte in self.data[key:key + size]: out |= byte << bit_offset bit_offset += 8 return out
def __init__(self, schema, matrix_height, name="Anonymous Table", size=None, num_rows=None): super(MatrixTable, self).__init__(schema=schema, name=name, size=size, num_rows=num_rows) if self.num_rows % matrix_height != 0: raise InvalidArgumentError( "Could not create MatrixTable with num_rows[{}] not evenly divisible " "by matrix_height[{}]".format(self.num_rows, matrix_height)) self.matrix_height = matrix_height self.matrix_width = self.num_rows // matrix_height
def from_schema(cls, schema, name="CustomRowTableEntry", hidden_columns=set()): if type(hidden_columns) == list: hidden_columns = set(hidden_columns) elif type(hidden_columns) != set: raise InvalidArgumentError( "Could not create RowTableEntry with invalid hidden_columns[{}]" .format(hidden_columns)) return type( name, (cls, ), { "name": name, "size": sum([x.size for x in schema]), "schema": schema, "hidden_columns": hidden_columns })
def expand(self, desired_size): if self.type == 'Earthbound': if (desired_size != 0x400000) and (desired_size != 0x600000): raise InvalidArgumentError( "Cannot expand an %s ROM to size[%#x]" % (self.type, self.size)) else: if self.size == 0x300000: self.data.fromlist([0] * 0x100000) self.size += 0x100000 if desired_size == 0x600000 and self.size == 0x400000: self[0x00ffd5] = 0x25 self[0x00ffd7] = 0x0d self.data.fromlist([0] * 0x200000) self.size += 0x200000 # The data range written below is already marked as used in romtypes.yml for i in range(0x8000, 0x8000 + 0x8000): self[0x400000 + i] = self[i] else: raise NotImplementedError( "Don't know how to expand ROM of type[%s]" % self.type)
def __getitem__(self, key): if isinstance(key, slice): if key.start > key.stop: raise InvalidArgumentError( "Second argument of slice %s must be greater than the first" % key) elif (key.start < 0) or (key.stop - 1 >= self.size): raise OutOfBoundsError( "Attempted to read from range (%#x,%#x) which is out of bounds" % (key.start, key.stop - 1)) else: out = Block() out.from_array(self.data[key]) return out elif isinstance(key, int): if key >= self.size: raise OutOfBoundsError( "Attempted to read at offset[%#x] which is out of bounds" % key) else: return self.data[key] else: raise TypeError("Argument \"key\" had invalid type of %s" % type(key).__name__)
def open_image(f): try: image = Image.open(f) return image except IOError: raise InvalidArgumentError("Could not open file: {}".format(f.name))
def check_validity(self): if self.tile < 0 or self.tile > 0x3ff: raise InvalidArgumentError("Invalid tile[{}]".format(self.tile)) if self.subpalette < 0 or self.subpalette > 7: raise InvalidArgumentError("Invalid subpalette[{}]".format( self.subpalette))