All pastes #795807 Raw Edit

convert.py

public python v1 · immutable
#795807 ·published 2007-11-24 14:20 UTC
rendered paste body
import structimport StringIOimport sysimport getoptimport os.path as pathimport globBLOCK_MAP_END_OF_BLOCK      = 0x00BLOCK_MAP_CHIPSET           = 0x01BLOCK_MAP_WIDTH             = 0x02BLOCK_MAP_HEIGHT            = 0x03BLOCK_MAP_TYPE_OF_LOOP      = 0x0BBLOCK_MAP_PARALLAX_BACK     = 0x1FBLOCK_MAP_BACKGROUND        = 0x20BLOCK_MAP_HORIZONTAL_PAN    = 0x21BLOCK_MAP_VERTICAL_PAN      = 0x22BLOCK_MAP_HORIZONTAL_PAN_A  = 0x23BLOCK_MAP_HORIZONTAL_PAN_SP = 0x24BLOCK_MAP_VERTICAL_PAN_A    = 0x25BLOCK_MAP_VERTICAL_PAN_SP   = 0x26BLOCK_MAP_LOWER_LAYER       = 0x47BLOCK_MAP_UPPER_LAYER       = 0x48BLOCK_MAP_EVENTS_LAYER      = 0x51BLOCK_MAP_TIMES_SAVED       = 0x5Bclass DataBlock:	def __init__(self, type, data, length):		self.type = type		self.data = StringIO.StringIO(data)		self.length = length		def read_byte(stream):	return struct.unpack("B", stream.read(1))[0]		def read_integer(stream):	value = 0	temp = 0x80		while temp & 0x80:		value <<= 7		temp = read_byte(stream)		value |= temp & 0x7F			return value	def read_string(stream, length):	return stream.read(length)	def read_array2(stream, length):	max = read_integer(stream)		array = {}		while stream.tell() < length:		row = read_integer(stream)		while True:			col = read_integer(stream)			if col == 0:				break							datalen = read_integer(stream)			if not array.has_key(row):				array[row] = {}							array[row][col] = DataBlock(col, stream.read(datalen), datalen)				return array	def loop_type_string(type):	if type == 0x00:		return "None"	elif type == 0x01:		return "Horizontal"	elif type == 0x02:		return "Vertical"	elif type == 0x03:		return "Both"	else:		return "Unknown"	class LcfDataBase:	def __init__(self, path):		self.path = path		self.file = open(path, "rb")				self.chipsets = {}				self.check_header()		for block in self.read_blocks():			if block.type == 0x14:				array = read_array2(block.data, block.length)								for row in array:					chip_name = read_string(array[row][0x01].data, array[row][0x01].length)					chip_filename = read_string(array[row][0x02].data, array[row][0x02].length)										self.chipsets[row] = {						'name': chip_name,						'filename': chip_filename					}	def check_header(self):		header = self.file.read(12)		if header != "\x0bLcfDataBase":			raise "Invalid header. Doesn't appear to be an RM2K database file."				def read_blocks(self):		try:			while True:				type = read_integer(self.file)				length = read_integer(self.file)				data = self.file.read(length)				yield DataBlock(type, data, length)		except Exception, e:			returnclass LcfMapUnit:	def __init__(self, path):		self.path = path		self.file = open(path, "rb")		self.check_header()						# set up default map data				self.chipset_id = 1		self.width = 20		self.height = 15		self.loop_type = 0           		self.parallax = False		self.background = None		self.pan_horizontal = False		self.pan_horizontal_auto = False		self.pan_horizontal_speed = 0		self.pan_vertical = False		self.pan_vertical_auto = False		self.pan_vertical_speed = 0   		self.layers = {}		self.event_count = 0		self.save_count = 0				for block in self.read_blocks():						if block.type == BLOCK_MAP_CHIPSET:				self.chipset_id = read_integer(block.data)			elif block.type == BLOCK_MAP_WIDTH:				self.width = read_integer(block.data)			elif block.type == BLOCK_MAP_HEIGHT:				self.height = read_integer(block.data)			elif block.type == BLOCK_MAP_TYPE_OF_LOOP:				self.loop_type = read_integer(block.data)			elif block.type == BLOCK_MAP_PARALLAX_BACK:				self.parallax = read_integer(block.data) == 1			elif block.type == BLOCK_MAP_BACKGROUND:				self.background = read_string(block.data, block.length)			elif block.type == BLOCK_MAP_HORIZONTAL_PAN:				self.pan_horizontal = read_integer(block.data) == 1			elif block.type == BLOCK_MAP_VERTICAL_PAN:				self.pan_vertical = read_integer(block.data) == 1			elif block.type == BLOCK_MAP_HORIZONTAL_PAN_A:				self.pan_horizontal_auto = read_integer(block.data) == 1			elif block.type == BLOCK_MAP_VERTICAL_PAN_A:				self.pan_vertical_auto = read_integer(block.data) == 1			elif block.type == BLOCK_MAP_HORIZONTAL_PAN_SP:				self.pan_horizontal_speed = read_integer(block.data)			elif block.type == BLOCK_MAP_VERTICAL_PAN_SP:				self.pan_vertical_speed = read_integer(block.data)			elif block.type == BLOCK_MAP_LOWER_LAYER:				self.layers['lower'] = block.data.read()			elif block.type == BLOCK_MAP_UPPER_LAYER:				self.layers['upper'] = block.data.read()			elif block.type == BLOCK_MAP_TIMES_SAVED:				self.save_count = read_integer(block.data)			elif block.type == BLOCK_MAP_END_OF_BLOCK:				break					def check_header(self):		header = self.file.read(11)		if header != "\nLcfMapUnit":			raise "Invalid header. Doesn't appear to be an RM2K map file."			def read_blocks(self):		try:			while True:				type = read_integer(self.file)				length = read_integer(self.file)				data = self.file.read(length)				yield DataBlock(type, data, length)		except Exception, e:			return		def print_help():	print "usage: convert.py [action] [args]"	print "Actions:"	print "  info [map]                   Shows information on an RM2k map."	print "  convert [map] [output_map]   Converts an RM2k map to a Sphere map."	print	print "Switches:"	print "  -c [file], --chipset=[file]  Override the map's chipset."	print "  -h, --help                   Prints this help."	print	print "map-converter v0.1 by engine #100. Licensed under the GPL."	print "http://projects.casiotone.org/map-converter/"def run_convert():		opts, leftover = getopt.gnu_getopt(sys.argv[1:], 'hc:', ['help', 'chipset='])		use_chipset = None	rtp_path = None		for opt, arg in opts:		if opt == '-h' or opt == '--help':			print_help()			return		if opt == '-c' or opt == '--chipset':			use_chipset = arg				if len(leftover) == 0:		raise Exception("No action specified.")			if len(leftover) >= 1:		action = leftover[0]				if action == "convert":		if len(leftover) == 1:			raise Exception("An rm2k map file must be specified to convert a map.")		if len(leftover) == 2:			raise Exception("An output map file must be specified to convert a map.")					map = LcfMapUnit(leftover[1])		out = leftover[2]		chipset_path = ""		if use_chipset is None:			# attempt to get the chipset from RPG_RT.ldb			db = LcfDataBase(path.join(path.dirname(leftover[1]), "RPG_RT.ldb"))			print "Searching for database chipset #%d: %s (%s)" % (map.chipset_id, db.chipsets[map.chipset_id]['name'], db.chipsets[map.chipset_id]['filename'])			filename = db.chipsets[map.chipset_id]['filename']			chip_path = path.join(path.dirname(leftover[1]), "ChipSet", filename)						chip_files = glob.glob(chip_path + ".*")			if len(chip_files):				chipset_path = chip_files[0]				print "Found at %s" % chipset_path			else:				raise Exception("Chipset could not be found in the project. It may be part of the RTP.")								else:			print "Using specified chipset: %s" % (use_chipset)		# convert here				print "Conversion..."				elif action == "info":				if len(leftover) == 1:			raise Exception("An rm2k map file must be specified to view information on.")					map = LcfMapUnit(leftover[1])		print "Map size: %dx%d" % (map.width, map.height)		print "Loop type: %d (%s)" % (map.loop_type, loop_type_string(map.loop_type))		print "Chipset ID: %d" % (map.chipset_id)		print "Parallax: %s" % (map.parallax)		print "Background: %s" % (map.background)		print "Panning:"		if map.pan_horizontal:			print " |- Horizontal: %d %s" % (map.pan_horizontal_speed, ["(Auto)", ""][int(map.pan_horizontal_auto)])		else:			print " |- Horizontal: None"		if map.pan_vertical:			print " |- Vertical: %d %s" % (map.pan_vertical_speed, ["(Auto)", ""][int(map.pan_vertical_auto)])		else:			print " |- Vertical: None"					print "Layer data lengths: %d, %d" % (len(map.layers['lower']), len(map.layers['upper']))		print "Save count: %d" % (map.save_count)		if __name__ == "__main__":	try:		run_convert()	except Exception, e:		print e		sys.exit(1)