r13793 - packages/trunk/funguloids/debian

Fabian Greffrath fabian-guest at alioth.debian.org
Thu Oct 4 10:54:20 UTC 2012


Author: fabian-guest
Date: 2012-10-04 10:54:19 +0000 (Thu, 04 Oct 2012)
New Revision: 13793

Added:
   packages/trunk/funguloids/debian/mpak.py
Modified:
   packages/trunk/funguloids/debian/control
   packages/trunk/funguloids/debian/copyright
   packages/trunk/funguloids/debian/rules
Log:
Add MPAK package handling utility from upstream, licensed under the MIT license, to fix broken data packages during package building.

Modified: packages/trunk/funguloids/debian/control
===================================================================
--- packages/trunk/funguloids/debian/control	2012-10-04 10:50:15 UTC (rev 13792)
+++ packages/trunk/funguloids/debian/control	2012-10-04 10:54:19 UTC (rev 13793)
@@ -13,7 +13,8 @@
  libopenal-dev,
  libogg-dev,
  libvorbis-dev,
- libmad0-dev
+ libmad0-dev,
+ python
 Standards-Version: 3.8.3
 Vcs-Svn: svn://svn.debian.org/svn/pkg-games/packages/trunk/funguloids/
 Vcs-Browser: http://svn.debian.org/wsvn/pkg-games/packages/trunk/funguloids/?op=log

Modified: packages/trunk/funguloids/debian/copyright
===================================================================
--- packages/trunk/funguloids/debian/copyright	2012-10-04 10:50:15 UTC (rev 13792)
+++ packages/trunk/funguloids/debian/copyright	2012-10-04 10:54:19 UTC (rev 13793)
@@ -45,3 +45,27 @@
 
 The Debian packaging is Copyright 2007, Andres Mejia <mcitadel at gmail.com> and
 is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
+Copyright and License for debian/mpak.py:
+
+	MPAK package handling utility
+	Version 1.5 (Python-implementation)
+	Copyright (c) 2008, 2012, Mika Halttunen. <http://www.mhgames.org>
+
+	Permission is hereby granted, free of charge, to any person obtaining a
+	copy of this software and associated documentation files (the "Software"),
+	to deal in the Software without restriction, including without limitation
+	the rights to use, copy, modify, merge, publish, distribute, sublicense,
+	and/or sell copies of the Software, and to permit persons to whom the
+	Software is furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+	DEALINGS IN THE SOFTWARE.

Added: packages/trunk/funguloids/debian/mpak.py
===================================================================
--- packages/trunk/funguloids/debian/mpak.py	                        (rev 0)
+++ packages/trunk/funguloids/debian/mpak.py	2012-10-04 10:54:19 UTC (rev 13793)
@@ -0,0 +1,376 @@
+#!/usr/bin/python
+"""
+	MPAK package handling utility
+	Version 1.5 (Python-implementation)
+	Copyright (c) 2008, 2012, Mika Halttunen. <http://www.mhgames.org>
+
+	Permission is hereby granted, free of charge, to any person obtaining a
+	copy of this software and associated documentation files (the "Software"),
+	to deal in the Software without restriction, including without limitation
+	the rights to use, copy, modify, merge, publish, distribute, sublicense,
+	and/or sell copies of the Software, and to permit persons to whom the
+	Software is furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+	DEALINGS IN THE SOFTWARE.
+	
+	- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+	Description follows:
+	
+	This command line tool allows creation and extraction of MPAK (.mpk) packages used
+	in several of my games. MPAK is a simple WAD-like file format of mine, that allows storing
+	the game data in one single .mpk file. I originally had a very crude command line program
+	bit like this one (written in C++), and decided to write this Python-implementation as
+	an Python-programming excercise. So, it's my first Python program. :)
+
+	Version history:
+	v1.5: Licensed under MIT license (no functional changes)
+	v1.4: The first Python version
+	v1.0 -- v1.31: The original C++ implementation
+"""
+import getopt, sys
+import os
+import traceback
+import struct
+import binascii
+import fnmatch
+import shutil
+from ctypes import c_uint32
+
+def usage():
+	"""
+	Prints the program usage.
+	"""
+	print "MPAK package handling utility"
+	print "Version 1.5 (Python-implementation)"
+	print "Copyright (c) 2008, 2012, Mika Halttunen."
+	print ""
+	print "Usage:", sys.argv[0],"[switch]","-f pakfile.mpk","[file1]","[file2]", "[...]", "[fileN]"
+	print "where [switch] is one of the following:"
+	print "  -f, --file=FILE   Use package FILE"
+	print "  -c, --create      Create a new package with files 'file1' to 'fileN'"
+	print "  -l, --list        List the files from given package"
+	print "  -e, --extract     Extract all files (by default) from given package. If you"
+	print "                    want to only extract some specific files, you can name"
+	print "                    them individually, and/or use wildcards (i.e. *.png)."
+	print "                    You can supply path where to extract with -p."
+	print "  -p, --path=PATH   Extract to PATH (created if doesn't exist)"
+	print "  -h, --help        Print this usage text"
+	print ""
+
+
+def errorMsg(msg):
+	"""
+	Prints an error message and exits.
+	"""
+	try:
+		pos = traceback.extract_stack(limit=2)
+		if pos:
+			print "ERROR: In %s:%s, line %d:" % (pos[0][0], pos[0][2], pos[0][1])
+		else: print "ERROR:"
+		print "\t",msg
+	except:
+		if __debug__:
+			traceback.print_exc()
+		pass
+	sys.exit(2)
+
+
+def separator():
+	"""
+	Prints the separator line.
+	"""
+	print "-"*75
+
+
+def computeCRC(file, offset):
+	"""
+	Computes the CRC32 for the file, starting at given offset.
+	"""
+	f = open(file, "rb")
+	f.seek(offset)
+	crc = 0
+
+	# Compute a running CRC32 for the file in 16kb chunks
+	while True:
+		buffer = f.read(16384)
+		if buffer == "": break		# End of file
+
+		crc = binascii.crc32(buffer, crc)
+
+	f.close()
+	return crc
+
+
+def createPackage(pakFile, files):
+	"""
+	Creates a new MPAK package.
+
+	This copies the given files into the new package file, writes the file table
+	and closes the package. MPAK doesn't support adding new files to an existing
+	package.
+	"""
+	print "Creating '%s'.." % pakFile
+	if len(files) < 1: errorMsg("No input files specified!")
+	separator()
+
+	# Open the package file for writing
+	out = open(pakFile, "wb")
+
+	# Write the header and reserve 4+4 bytes for CRC32 and file table offset
+	out.write("MPK1")
+	out.write("."*8)
+
+	# Write each file
+	package = { "fileNames": [], "fileOffsets": [] }
+	count = 0
+	for file in files:
+		# Get the basename
+		filename = os.path.basename(file)
+		print " <",filename,"...",
+		package["fileNames"].append(filename)
+
+		# Get the file size in bytes
+		stats = os.stat(file)
+
+		# Store the current offset
+		package["fileOffsets"].append(out.tell())
+
+		# Open the file and copy its contents
+		f = open(file, "rb")
+		shutil.copyfileobj(f, out, 16384)
+		f.close()
+
+		print "OK. (%.1f KB)" % (stats.st_size / 1024.0)
+		count = count + 1
+
+	separator()
+
+	# Grab the file table offset and write the table
+	ftOffset = out.tell()
+
+	# Write the number of files
+	out.write(struct.pack("<L", count))
+
+	# Write the file information
+	for i in range(count):
+		# File name length
+		length = len(package["fileNames"][i]) + 1
+		out.write(struct.pack("B", length))
+		# File name, plus one zero for the C++ implementation
+		out.write(package["fileNames"][i])
+		out.write(struct.pack("B", 0))
+		# File offset
+		out.write(struct.pack("<L", package["fileOffsets"][i]))
+
+	# Update the header to have the correct file table offset
+	out.seek(8)
+	out.write(struct.pack("<L", ftOffset))
+
+	# Compute the CRC32 and write it to the header
+	out.flush()
+	crc32 = c_uint32(0)
+	crc32.value = computeCRC(pakFile, 8)
+	out.seek(4)
+	out.write(struct.pack("<L", crc32.value))
+
+	print "Added %d files to %s" % (count, pakFile)
+	print "Package '%s' created successfully. CRC32 checksum is %s." % (pakFile, hex(crc32.value))
+	out.close()
+
+
+def readPackage(pakFile):
+	"""
+	Opens the given MPAK package, reads its information and stores it to a
+	package dictionary. Returns the dictionary.
+	"""
+	packageInfo = { "filename": pakFile }
+
+	f = open(pakFile, 'rb')
+	if f.read(4) != "MPK1": errorMsg("Unsupported file format!")
+
+	# Read the CRC32 checksum and the file table header offset
+	buffer = f.read(8)
+	crc32, headerOffset = struct.unpack("<LL", buffer)
+	crc32 = int(crc32)
+	packageInfo["crc"] = crc32
+
+	# Check that the CRC32 matches
+	checksum = c_uint32(0)
+	checksum.value = computeCRC(pakFile, 8)
+	if checksum.value != crc32:
+		f.close()
+		errorMsg("Checksum doesn't match; perhaps a corrupted package?")
+
+	# Seek to the file table, and read the number of files
+	f.seek(headerOffset)
+	numFiles = struct.unpack("<L", f.read(4))[0]
+	packageInfo["numFiles"] = numFiles
+
+	# Read the file information
+	fileNames = []
+	fileOffsets = []
+	for i in range(numFiles):
+		namelen = struct.unpack("B", f.read(1))[0]
+		file = f.read(namelen)
+		offset = struct.unpack("<L", f.read(4))[0]
+		fileNames.append(file[:-1])		# Remove the trailing null character
+		fileOffsets.append(offset)
+
+	# Compute the file sizes from the offsets
+	fileSizes = []
+	for i in range(numFiles-1):
+		fileSizes.append(fileOffsets[i+1] - fileOffsets[i])
+	fileSizes.append(headerOffset - fileOffsets[numFiles-1])
+
+	# Store the information
+	packageInfo["fileNames"] = fileNames
+	packageInfo["fileOffsets"] = fileOffsets
+	packageInfo["fileSizes"] = fileSizes
+	f.close()
+	return packageInfo
+
+
+def listPackage(pakFile):
+	"""
+	Lists the contents of a MPAK package.
+	"""
+	print "Listing '%s'.." % pakFile
+	package = readPackage(pakFile)
+
+	# Print the listing
+	numFiles = package["numFiles"]
+	print "'%s' (CRC32: %s) contains %d files:" % (pakFile, hex(package["crc"]), numFiles)
+	print ""
+	print " NUM : FILE                           : SIZE(KB)   : OFFSET"
+	separator()
+	for i in range(numFiles):
+		print " %3d : %30s : %-10.1f : (at %s)" % (i+1, package["fileNames"][i], package["fileSizes"][i] / 1024.0, hex(package["fileOffsets"][i]))
+
+	separator()
+	print " NUM : FILE                           : SIZE(KB)   : OFFSET"
+
+
+def extractPackage(pakFile, path, filters):
+	"""
+	Extracts files from a package to given path.
+
+	By default extracts all the files. Can be given list of wildcards (i.e. *.png) to
+	extract only the files that match given wildcards. Wildcards can also be file names
+	from the package.
+
+	The given path is created if it doesn't exist.
+	If the path is just a single directory name, it's assumed to exist in the current
+	working directory.
+	"""
+	print "Extracting files from '%s' to %s.." % (pakFile, path)
+	package = readPackage(pakFile)
+
+	# Try to create the path if it doesn't exist
+	path = os.path.abspath(path)
+	if not os.path.exists(path):
+		print "Path",path,"doesn't exist, creating it.."
+		try:
+			os.makedirs(path)
+		except:
+			errorMsg("Unable to create directory " + path + "!");
+
+	separator()
+
+	# Open the file, and extract all the individual files from it
+	count = 0
+	f = open(pakFile, "rb")
+	for i in range(package["numFiles"]):
+		# Test if the file name matches the given wildcard
+		if len(filters) > 0:
+			for filter in filters:
+				if fnmatch.fnmatch(package["fileNames"][i], filter):
+					break
+			else: continue
+
+		print " >", package["fileNames"][i],"...",
+		# Seek to the correct offset
+		f.seek(package["fileOffsets"][i])
+
+		# Open a new file for writing, and write the file out in 16kb chunks
+		out = open(os.path.join(path, package["fileNames"][i]), "wb")
+		bytesWritten = 0
+		bytesTotal = package["fileSizes"][i];
+		while True:
+			# We have to watch not to write too much
+			bytesLeft = bytesTotal - bytesWritten
+			if bytesLeft > 16384: bytesLeft = 16384
+
+			buffer = f.read(bytesLeft)
+			out.write(buffer)
+			bytesWritten = bytesWritten + bytesLeft
+
+			if bytesWritten == bytesTotal:
+				break
+
+		out.close()
+		print "OK."
+		count = count + 1
+
+	f.close()
+	separator()
+	print "%d (of %d) files extracted to %s." % (count, package["numFiles"], path)
+
+
+def main():
+	"""
+	Main method.
+	"""
+	try:
+		# Get the optiosn
+		opts, args = getopt.getopt(sys.argv[1:], "f:clep:h", ["file=", "create", "list", "extract", "path=", "help"])
+	except getopt.GetoptError, err:
+		# Print the program usage and exit
+		print "ERROR:", str(err)
+		usage()
+		sys.exit(2)
+
+	extractPath = os.getcwd()
+	pakFile = None
+	action = None
+
+	# Handle the options
+	for o, a in opts:
+		if o in ("-f", "--file"):
+			pakFile = a					# Grab the pakfile
+		elif o in ("-c", "--create"):
+			action = "create"
+		elif o in ("-l", "--list"):
+			action = "list"
+		elif o in ("-e", "--extract"):
+			action = "extract"
+		elif o in ("-p", "--path"):
+			extractPath = a				# Grab the path
+		elif o in ("-h", "--help"):
+			usage()
+			sys.exit()
+		else:
+			assert False, "Unhandled option"
+
+	# Check that we got a pakfile
+	if pakFile == None:
+		usage()
+		sys.exit(2)
+
+	if action == "create": createPackage(pakFile, args)
+	elif action == "list": listPackage(pakFile)
+	elif action == "extract": extractPackage(pakFile, extractPath, args)
+	else: usage()
+	sys.exit()
+
+if __name__ == "__main__":
+	main()
+


Property changes on: packages/trunk/funguloids/debian/mpak.py
___________________________________________________________________
Added: svn:executable
   + *

Modified: packages/trunk/funguloids/debian/rules
===================================================================
--- packages/trunk/funguloids/debian/rules	2012-10-04 10:50:15 UTC (rev 13792)
+++ packages/trunk/funguloids/debian/rules	2012-10-04 10:54:19 UTC (rev 13793)
@@ -10,6 +10,35 @@
 
 override_dh_auto_configure:
 	CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --with-fmod=no
+	
+	chmod +x debian/mpak.py
+	
+	if test ! -e bin/bootstrap.mpk.orig ; then \
+		cp bin/bootstrap.mpk bin/bootstrap.mpk.orig ; \
+		./debian/mpak.py -e -f bin/bootstrap.mpk  -p _bootstrap ; \
+		sed -ri '/^[A-Z]/ s/(.*)/overlay \1/' _bootstrap/*.overlay ; \
+		./debian/mpak.py -c -f bin/bootstrap.mpk  _bootstrap/* ; \
+		rm -rf _bootstrap ; \
+	fi
+	
+	if test ! -e bin/funguloids.mpk.orig ; then \
+		cp bin/funguloids.mpk bin/funguloids.mpk.orig ; \
+		./debian/mpak.py -e -f bin/funguloids.mpk -p _gamedata ; \
+		sed -ri '/^[A-Z]/ s/(.*)/overlay \1/' _gamedata/*.overlay ; \
+		sed -ri '/^[A-Z]/ s/(.*)/particle_system \1/' _gamedata/*.particle ; \
+		sed -ri 's/^(\t\t\t)(texture_unit) 1/\1\2\n\1{\n\1}\n\1\2/' _gamedata/materials.material ; \
+		./debian/mpak.py -c -f bin/funguloids.mpk _gamedata/* ; \
+		rm -rf _gamedata ; \
+	fi
 
 override_dh_auto_clean:
 	dh_auto_clean -- clean distclean
+	
+	if test -e bin/bootstrap.mpk.orig ; then \
+		mv bin/bootstrap.mpk.orig bin/bootstrap.mpk ; \
+	fi
+	
+	if test -e bin/funguloids.mpk.orig ; then \
+		mv bin/funguloids.mpk.orig bin/funguloids.mpk ; \
+	fi
+




More information about the Pkg-games-commits mailing list