This is a program to extract/compile car NAV .KWI extensions. Unfortunately, I do not know anything about Python though I will love to learn some time very soon. Could you help me compile this into an executable file for windows 7?

Will be reatly appreciated.

#!/usr/bin/env python
#
#       kiwi
#
#       Copyright 2009 Bert Vermeulen <bert@biot.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import os
import sys
from getopt import getopt
import string
from datetime import datetime
import struct

EXTRACT_BUFSIZE = 1024 * 1024


def usage():
	print """usage: kiwi [-v|-x] [-o outputdir] -d <dvd directory>
  -v	list modules contained in the LOADING.KWI FILE
  -x	extract modules from the LOADING.KWI file
  -d	directory where the DVD is mounted
  -o	target dir to extract modules into"""
	sys.exit(1)


def is_printable(text):
	for i in text:
		if i not in string.printable + '\x00':
			return False

	return True


def show_date(stamp):
	date = datetime.fromtimestamp(stamp)
	datestr = "%d-%.2d-%.2d" % (date.year, date.month, date.day)

	return datestr


def maybe_dump(text):
	if is_printable(text):
		return text
	else:
		hex = ''
		for i in text:
			hex += "%.2x " % int(ord(i))
		return hex


def show_kwi_info(lo):
	print "number of systems found:", lo['num_systems']
	syscnt = 1
	for s in lo['systems']:
		print "System %s\n    Manufacturer ID: %s" % (syscnt, maybe_dump(s['mid']))
		print "    Number of modules in this system:", len(s['modules'])
		modcnt = 1
		for modname, modversion, category, startdate, enddate, title, info, address, size in s['modules']:
			print "    Module %d:" % modcnt
			print "\tName:", modname
			print "\tVersion:", modversion
			print "\tCategory:", category
			if startdate:
				print "\tValid from:", show_date(startdate)
			if enddate:
				print "\tValid until:", show_date(enddate)
			print "\tAddress: 0x%X" % address
			size += 0.0
			if size > 1024 * 1024:
				size /= 1024 * 1024
				unit = "MB"
			elif size > 1024:
				size /= 1024
				unit = "KB"
			else:
				unit = "bytes"
			print "\tSize: %.1f %s" % (size, unit)

			print
			modcnt += 1

		syscnt += 1


def extract_modules(path, targetdir, system=1):
	try:
		lo = kiwi.parse_loading(path)
		if lo['num_systems'] < system:
			raise Exception, "only %s systems found" % lo['num_systems']

		if not os.path.exists(targetdir):
			os.mkdir(targetdir)

		s = lo['systems'][system-1]
		print "extracting modules into %s..." % targetdir
		fp = open(path)
		for modname, modversion, category, startdate, enddate, title, info, address, size in s['modules']:
			print "  ", modname
			fp.seek(address)
			cnt = 0
			outfile = open(targetdir + '/' + modname, 'w')
			while True:
				if cnt + EXTRACT_BUFSIZE > size:
					chunksize = size - cnt
				else:
					chunksize = EXTRACT_BUFSIZE
				buf = fp.read(chunksize)
				outfile.write(buf)
				cnt += chunksize
				if len(buf) < EXTRACT_BUFSIZE:
					break
			outfile.close()
		fp.close()
	except Exception, msg:
		print "Error:", str(msg)


module_categories = [
	'Initial program',
	'Program',
	'Library',
	'Data'
]

def parse_loading(path):
	lostruct = {}
	fp = open(path)
	data = fp.read(4)
	num_systems, dummy = struct.unpack_from(">HH", data)
	lostruct['num_systems'] = num_systems
	offset = 4
	lostruct['systems'] = []
	for s in range(num_systems):
		system = {}
		fp.seek(offset)
		data = fp.read(16)
		mid, num_modules, dummy = struct.unpack_from(">12sHH", data)
		offset += 16
		system['mid'] = mid
		system['modules'] = []
		# get Module Identification Information blocks
		for m in range(num_modules):
			fp.seek(offset)
			data = fp.read(64)
			cat, modname, modversion = struct.unpack_from(">cxxx52s4s", data)
			offset += 64
			cat = ord(cat)
			category = module_categories[cat & 3]
			if cat & 64:
				category += " (Test module)"
			if cat & 128:
				category += " (Diagnostic service module)"
			modname = modname.rstrip('\x00')
			system['modules'].append([modname, modversion, category])
		# get Module Management Information blocks
		address_multiplier = 0
		for m in range(num_modules):
			fp.seek(offset)
			data = fp.read(256)
			startdate, enddate, title, info, address, size = struct.unpack_from(">HH64s182sIH", data)
			offset += 256
			# dates are in number of days since 1997-01-01 00:00:00. that's
			# 852073200 seconds since the unix epoch, convert to that
			# if it's 0 no date is set, so preserve that
			if startdate:
				startdate += 852073200 + (startdate * 86400)
			if enddate:
				enddate += 852073200 + (enddate * 86400)
			# address is either in 2048-byte sized blocks, or some odd 3-byte
			# block size. try to grok this by the first one we
			# see, which will be right past this this Loading Module Management
			# block we're parsing now
			if m == 0:
				if address < 0x100:
					# too small to be an absolute address
					address_multiplier = 2048
				elif (address >> 8) < 0x100:
					address_multiplier = 8
				else:
					address_multiplier = 1
			address *= address_multiplier
			# size is in 2048-byte sized blocks
			size *= 2048
			system['modules'][m] += [startdate, enddate, title, info, address, size]
		lostruct['systems'].append(system)

	return lostruct




#
# main
#

opts, args = getopt(sys.argv[1:], "vxd:o:")

mode = dvddir = targetdir = None
for opt, arg in opts:
	if opt == '-v':
		if mode:
			usage()
		else:
			mode = 'view'
	elif opt == '-x':
		if mode:
			usage()
		else:
			mode = 'extract'
	elif opt == '-d':
		dvddir = arg
	elif opt == '-o':
		targetdir = arg

if not mode or not dvddir:
	usage()

try:
	path = dvddir + '/LOADING.KWI'
	if not os.path.exists(path):
		print "no LOADING.KWI found in %s" % dvddir
		sys.exit(1)
except Exception, msg:
	print "failed to open %s: %s" % (path, str(msg))
	sys.exit(1)
else:
	if mode == 'view':
		kwi_info = parse_loading(path)
		show_kwi_info(kwi_info)
	elif mode == 'extract':
		if not targetdir:
			print "please set a target directory to extract into."
			usage()
		else:
			extract_modules(path, targetdir)

I did try and it came up with a few errors and I have no clue what to do. Thanks.

I was able to compile it with IronPython's compiler, so I can give you that, if you don't mind it running on .NET of course.

This article has been dead for over six months. Start a new discussion instead.