#!/usr/bin/perl

#/*
#*  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.
#*
#*/


use strict;
use Fcntl ':mode';

my @sections;
my %strings;
my %version;
my $driver_name;
my $confdir = "/etc/ndiswrapper";
my $hotplug_conf = "modules.ndiswrapper";
my $instdir;
my %fuzzlist;
my $bustype;

#Blacklist of files not to install.
my @copy_blacklist;

#Fixup list for parameters. 
my %param_fixlist = ("EnableRadio|0" => "EnableRadio|1",
		     "IBSSGMode|0" => "IBSSGMode|2",
                     "PrivacyMode|0" => "PrivacyMode|2");

if(@ARGV < 1)
{
	usage();
	exit();
}

my $res;
if($ARGV[0] eq "-i" and @ARGV == 2)
{
	$res = install($ARGV[1]);
}
elsif($ARGV[0] eq "-d" and @ARGV == 3)
{
	$res = devid_driver($ARGV[1], $ARGV[2]);
}
elsif($ARGV[0] eq "-e" and @ARGV == 2)
{
	$res = remove($ARGV[1]);
}
elsif($ARGV[0] eq "-l" and @ARGV == 1)
{
	$res = list();
}
elsif($ARGV[0] eq "-m" and @ARGV == 1)
{
	$res = modconf();
}
elsif($ARGV[0] eq "-hotplug" and @ARGV == 1)
{
	$res = hotplug_conf();
}
else
{
	usage();
	exit();
}

exit $res;

sub usage
{
	print "Usage: ndiswrapper OPTION\n".
	      "\n".
	      "Manage ndis drivers for ndiswrapper.\n".
	      "-i inffile        Install driver described by 'inffile'\n".
	      "-d devid driver   Use installed 'driver' for 'devid'\n".
	      "-e driver         Remove 'driver'\n".
	      "-l                List installed drivers\n".
	      "-m                Write configuration for modprobe\n".
		"-hotplug          (Re)Generate hotplug information\n".
		"\n\nwhere 'devid' is either PCIID or USBID of the form ".
		"XXXX:XXXX\n";
	
}


sub install
{
	my $inf = shift;
	$driver_name = lc($inf);
	$driver_name =~ s/\.inf//;
	$driver_name = `basename $driver_name`;
	$instdir = `dirname $inf`;
	chomp($instdir);
	chomp($driver_name);

	if(isInstalled($driver_name))
	{
		print "$driver_name is already installed. Use -e to remove it\n";
		return -1;
	}
	
	if(!opendir(DH, $confdir))
	{
		mkdir($confdir);
	}
	else
	{
		close(DH);
	}
	
	print "Installing $driver_name\n";
	if(!mkdir("$confdir/$driver_name"))
	{
		print "Unable to create directory $confdir/$driver_name. Make sure you are running as root\n";
		return -1;
	}
	
	loadinf($inf);
	initStrings(); 
	parseVersion();
	`cp -u $inf $confdir/$driver_name/$driver_name.inf`;	
	processPCIFuzz();
}



sub isInstalled
{
	my $installed;
	my $name = shift;
	my $mode = (stat("$confdir"))[2];
	if (!S_ISDIR($mode)) {
	  return 0;
	}
	open(LS, "ls -1 $confdir|");
	while(my $f = <LS>)
	{
		chomp($f);
		$mode = (stat("$confdir/$f"))[2];
		if(S_ISDIR($mode) and $name eq $f)
		{
			$installed = 1;
		}
		
	}
	close(LS);	
	return $installed;
}


sub remove
{
	my $name = shift;
	if(!isInstalled($name))
	{
		print "Driver $name is not installed. Use -l to list installed drivers\n";
		return;
	}
	`rm -rf $confdir/$name`;
}

sub devid_driver
{
	my $devid = shift;
	my $driver = shift;
	my $done = 0;

	$devid = uc($devid);
	if (!($devid =~ /[0-9A-Z]{4}:[0-9A-Z]{4}/))
	{
		print "'$devid' is not a valid device ID\n";
		return;
	}
	open(LS, "ls -1 $confdir/$driver/ |");
	while(my $f = <LS>)
	{
		chomp($f);
		if ($f =~ /\.([05]).conf$/)
		{
			`ln -s $f $confdir/$driver/$devid.$1.conf`;
			print "Driver '$driver' is used for '$devid'\n";
			$done = 1;
			last;
		}
	}
	close(LS);	
	if ($done == 0)
	{
		print "Driver '$driver' is not installed properly!\n";
	}
	return;
}

sub hotplug_conf
{
	my $vendor;
	my $device;
	my $subvendor;
	my $subdevice;
	if(!open(CONF, ">$confdir/$hotplug_conf")) {
		print "Unable to create file hotplug modules configuration file";
		return -1;
	}
	printf CONF "# pci module         vendor     device     subvendor  subdevice  class      class_mask driver_data";

	open(LS, "ls -1 $confdir|");
	while(my $driver = <LS>) {
		chomp($driver);
		my $mode = (stat("$confdir/$driver"))[2];
		if(S_ISDIR($mode)) {
			open(LS2, "ls -1 $confdir/$driver/ |");
			while (my $file = <LS2>) {
				chomp ($file);
				if ($file =~ s/.conf//) {
					$file = lc($file);
					if($file =~ /(.{4}):(.{4}):(.{4}):(.{4})/) {
						$vendor = "0x0000$1";
						$device = "0x0000$2";
						$subvendor = "0x0000$3";
						$subdevice = "0x0000$4";
					}
					elsif($file =~ /(.{4}):(.{4})/) {
						$vendor = "0x0000$1";
						$device = "0x0000$2";
						$subvendor = "0xffffffff";
						$subdevice = "0xffffffff";
					}
					printf CONF "ndiswrapper    $vendor $device $subvendor $subdevice 0x00000000 0x00000000 0x0\n";
				}
			}
			close(LS2);
		}
	}

	close(CONF);
	close(LS);
	return 0;
}

sub list
{
	my $s;

	my $cards = getPresentCards();

	if(!$cards)
	{
		print "WARNING: Cannot locate lspci and lsusb. Unable to see if hardware is present.\n";
	}

	my $mode = (stat("$confdir"))[2];
	if (!S_ISDIR($mode)) {
	  print "No drivers installed\n$s";
	  return;
	}
	open(LS, "ls -1 $confdir|");
	while(my $f = <LS>)
	{
		chomp($f);
		my $mode = (stat("$confdir/$f"))[2];
		if(S_ISDIR($mode))
		{
			$s .= "$f\t".installStatus($cards, $f)."\n";
		}
	}
	if($s)
	{
		print "Installed ndis drivers:\n$s";
	}
	else
	{
		print "No drivers installed\n$s";
	}
	close(LS);	
}

sub modconf
{
	my $alias = 0;
	my $err = 0;

	my @modprobe = ("/sbin/modprobe", "/usr/sbin/modprobe", "modprobe");
	my $ok = 0;
	for(my $i = 0; $i < @modprobe; $i++)
	{
		if(open(MODPROBE, "$modprobe[$i] -c|"))
		{
			$ok = 1;
			$i = @modprobe;
		}
	}
	if(!$ok)
	{
		return -1;
	}

	while(my $line = <MODPROBE>)
	{
		if($line =~ /^alias\s.+\sndiswrapper/)
		{
			print "modprobe config already contains alias directive\n\n";
			$alias = 1;
		}
		elsif($line =~ /^install\s.*ndiswrapper/)
		{
			print "You should not need an install directive in you modprobe config file.\n";
			modconf_err($line);
			$err = 1;
		}
		elsif($line =~ /^post-install\s+ndiswrapper/)
		{
			print "You should not need a post-install directive in you modprobe config file.\n";
			modconf_err($line);
			$err = 1;
		}
	}
	close(MODPROBE);

	if($alias)
	{
		return;
	}
	

	my $v =  `uname -r`;	


	$v =~ /(\d+)\.(\d+)\.(\d+)/;
	my $major = $1;
	my $minor = $2;
	my $rev = $3;	
	my $modconf;
	if($minor > 4)
	{
		if(-d "/etc/modprobe.d")
		{
			$modconf = "/etc/modprobe.d/ndiswrapper" 
		}
		else
		{
			$modconf = "/etc/modprobe.conf" 
		}
	}
	else
	{
		if(-d "/etc/modutils")
		{
			$modconf = "/etc/modutils/ndiswrapper";
		}
		else
		{
			$modconf = "/etc/modules.conf";
		}
	}
	

	print "Adding \"alias wlan0 ndiswrapper\" to $modconf\n";
	system("echo \"alias wlan0 ndiswrapper\" >>$modconf");
	
    	if(-x "/sbin/update-modules")
	{
		system("/sbin/update-modules");
	}
}

sub modconf_err
{
	my $line = shift;
	print "Please remove the line saying:\n\n";
	print "$line\n";
	print "unless you are 100% sure of what you are doing.\n";			
}


sub getPresentCards
{
#01:00.0 Class 0300: 1002:4c66 (rev 01)
#        Subsystem: 1043:1732
	my @cards;
	
	my @lspci = ("/sbin/lspci", "/usr/sbin/lspci", "lspci");
	for(my $i = 0; $i < @lspci; $i++)
	{
		if(open(LSPCI, "$lspci[$i] -vn|"))
		{
			my $card;
			while(my $line = <LSPCI>)
			{
				if($line =~ /^[0-9]+.*:\s(.{4}):(.{4}).*/)
				{
					my %c;
					$card = \%c;
					$card->{vendor} = $1;
					$card->{device} = $2;
				}
				if($line =~ /.+Subsystem:\s*(.{4}):(.{4}).*/)
				{
					$card->{subvendor} = $1;
					$card->{subdevice} = $2;

					push(@cards, $card);
				}
					
			}
			last;
		}
	}

	my @lsusb = ("/sbin/lsusb", "/usr/sbin/lsusb", "lsusb");
	for(my $i = 0; $i < @lsusb; $i++)
	{
		if(open(LSUSB, "$lsusb[$i] |"))
		{
			my $card;
			while(my $line = <LSUSB>)
			{
				if($line =~ /.*: ID\s(.{4}):(.{4}).*/)
				{
					my %c;
					$card = \%c;
					$card->{vendor} = $1;
					$card->{device} = $2;

					push(@cards, $card);
				}
			}
			last;
		}
	}

	return \@cards;
}


sub installStatus
{
	my $cards = shift; 
	my $driver = shift;	

	my $sys = 0;
	my $conf = 0;
	my $inf = 0;

	if(!$cards)
	{
		return;
	}

	open(LS2, "ls -1 $confdir/$driver|");

	while(my $device = <LS2>)
	{
		chomp($device);
		my $d = $device;

		$sys = 1 if $d =~ /\.sys$/;
		$inf = 1 if $d =~ /\.inf$/;
		$conf = 1 if $conf eq 0 and $d =~ /\.conf$/;
		$d =~ s/.conf//;
		if($d =~ /(.{4}):(.{4}):(.{4}):(.{4})/)
		{
			for(my $i = 0; $$cards[$i]; $i++)
			{
				if($$cards[$i]->{vendor} == $1 and
				   $$cards[$i]->{device} == $2 and
				   $$cards[$i]->{subvendor} == $3 and
				   $$cards[$i]->{subdevice} == $4)
				{
					$conf = 3;
					last;
				}
			}
			
		}
		elsif($d =~ /(.{4}):(.{4})/)
		{
			for(my $i = 0; $$cards[$i]; $i++)
			{
				if($$cards[$i]->{vendor} == $1 and
				   $$cards[$i]->{device} == $2)
				{
					my $mode = (lstat("$confdir/$driver/$device"))[2];
					if(S_ISLNK($mode))
					{
						$conf = 2;
					}
					else
					{
						$conf = 3;
					}
					last;
				}
			}
		}
	}
	close(LS2);	

	my $ret;
	if ($sys eq 0 || $inf eq 0 || $conf eq 0)
	{
		$ret = "invalid driver!";
	}
	else
	{
		$ret = $ret . "driver present " if $conf eq 1;
		$ret = $ret . "driver present, hardware present " if
			$conf eq 2;
		$ret = $ret . "driver present, hardware present " if
			$conf eq 3;
	}
	return $ret;
}



#
# Create symlink for PCI general device if not existing
#
sub processPCIFuzz
{
	my @devs = keys(%fuzzlist);
	for(my $i = 0; $i < @devs; $i++)
	{
		my $dev = $devs[$i];
		if($dev ne $fuzzlist{$dev})
		{
			`ln -s $confdir/$driver_name/$fuzzlist{$dev}.$bustype.conf $confdir/$driver_name/$dev.$bustype.conf`;
		}
	}
}

#
# Collect a list of supported PCI-Id's so we can add fuzzy entries if needed.
#
sub addPCIFuzzEntry
{
	my $vendor = shift;
	my $device = shift;
	my $subvendor = shift;
	my $subdevice = shift;

	my $s = "$vendor:$device";

	if(!$subvendor or !$fuzzlist{$s})
	{
		my $s2 = $s;
		if($subvendor)
		{
			$s2 .= ":$subvendor:$subdevice";
		}
		$fuzzlist{$s} = $s2;
	}
}


sub parseVersion
{
  my $s = getSection("version");
  if(!$s)
    {
      return;
    }
  my @lines = split("\n", $s->{data});

  for(my $i = 0; $i < @lines; $i++)
    {
      (my $key, my $val) = getKeyVal($lines[$i]);
      if($key eq "Provider")
	{
	  $val =~ s/"(.+)"/$1/; 
	  $version{$key} = $val;
	}
      if($key eq "DriverVer")
	{
	  $val =~ s/"(.+)"/$1/; 
	  $version{$key} = $val;
	}
    }
  parseManu();
}

#
# Parse the [Manufacturer] section.
#
sub parseManu
{
#Examples:
#Vendor
#Vendor,ME,NT,NT.5.1
#Vendor.NTx86

	my $manu = getSection("manufacturer");
	if(!$manu)
	{
		return -1;
	}

	my @lines = split("\n", $manu->{data});
	for(my $i = 0; $i < @lines; $i++)
	{
		my $line = remComment($lines[$i]);
		(my $key, my $val) = getKeyVal($line, "=");

		if ($key eq $version{"Provider"})
		  {
		    $strings{$key} = trim($val);
		  }

		if($val)
		{
			my $section;
			my @flavours = split(",", $val);
			my $flavour = "";
			if(@flavours == 1)
			{
				#Vendor
				$section = $val;				
			}
			else
			{
				#Vendor,flavour1, flavour2 etc;
				for(my $i = 1; $i < @flavours; $i++)
				{
					my $flav = trim($flavours[$i]);
					$flav =~ s/\s*(\S+)\s*/$1/;
					if(uc($flav) eq "NT.5.1")
					{
						#This is the best (XP)
						$section = $flavours[0] . "." . $flav;
						$flavour = $flav;
					}
					elsif(substr(uc($flav),0,2) eq "NT" and $section eq "")
					{
						#This is the second best (win2k)
						$section = $flavours[0] . "." . $flav;
						$flavour = $flav;
					}
				}
				
			}
			my $res = parseVendor($flavour, $section);
			if(!$res)
			{
				return $res;
			}
		}
	}
}

#
# Parse a vendor section. This section contains the device-ids. Each poiting to a section with config info.
#	
sub parseVendor
{
	my $flavour = shift;
	my $vendor_name = shift;
	my $vend = getSection($vendor_name);

	if(!$vend)
	{
		print "no vendor\n";
		return -1;
	}

	my @lines = split("\n", $vend->{data});
	for(my $i = 0; $i < @lines; $i++)
	{
		my $line = remComment($lines[$i]);
		(my $name, my $val) = getKeyVal($line, "=");

		if($val)
		{
			(my $section, my $id) = split(",", $val);
			$section = trim($section);
			$id = trim($id);
			($bustype, my $vendor, my $device, my $subvendor, my $subdevice) = parseID($id);
			if($vendor)
			{
				parseDevice($flavour, $section, $vendor, $device, $subvendor, $subdevice);
			}
		}
	}
}


#
# This section contains pointers to registry sections and copyfiles sections. 
#
sub parseDevice
{
	my $flavour = shift;
	my $device_sect = shift;
	my $device = shift;
	my $vendor = shift;
	my $subvendor = shift;
	my $subdevice = shift;

	my $dev = getSection("$device_sect.$flavour");
	if(!$dev)
	{
		$dev = getSection("$device_sect.NT");
	}
	if(!$dev)
	{
		$dev = getSection("$device_sect.NTx86");
	}
	if(!$dev)
	{
		$dev = getSection("$device_sect");
	}

	if(!$dev)
	{
		print "no dev $device_sect $flavour\n";
		return -1;
	}

#	print "$device:$vendor:$subvendor:$subdevice  $flavour\n";

	my $copyfiles;
	my $addreg;
	my @lines = split("\n", $dev->{data});

	for(my $i = 0; $i < @lines; $i++)
	{
		my $line = remComment($lines[$i]);
		(my $key, my $val) = getKeyVal($line, "=");
		if($key)
		{
			if(lc($key) eq "addreg")
			{
				$addreg = $val;
			}
			if(lc($key) eq "copyfiles")
			{
				$copyfiles = $val;
			}
		}
	}		

	my $filename = "$device:$vendor";
	if($subvendor)
	{
		$filename .= ":$subvendor:$subdevice"
	}

	$filename .= ".$bustype.conf";
	
	if($bustype == 5)
	{
		addPCIFuzzEntry($device, $vendor, $subvendor, $subdevice);
	}

	if(!open(CONF, ">$confdir/$driver_name/$filename"))
	{
		print "Unable to create file $filename";
		return -1;
	}

	my $ver=$version{"DriverVer"};
	my $provider=$version{"Provider"};
	my $providerstring = stripquotes(substStr(trim($provider)));

	printf CONF "NdisVersion|0x50001\n";
	printf CONF "Environment|1\n";
 	printf CONF "BusType|$bustype\n";
	printf CONF "mac_address|XX:XX:XX:XX:XX:XX\n";
	printf CONF "ndis_version|$providerstring,$ver\n\n";
	close(CONF);

	if(!open(CONF, "|sort|uniq >>$confdir/$driver_name/$filename"))
	{
		print "Unable to create file $filename";
		return -1;
	}

	my @addregs = split(",", $addreg);
	for(my $i = 0; $i < @addregs; $i++)
	{
		my $reg = trim($addregs[$i]);
		addReg($reg);
	}
	
	my @copyfiles = split(",", $copyfiles);
	for(my $i = 0; $i < @copyfiles; $i++)
	{
		my $file = trim($copyfiles[$i]);
		copyfiles($file);
	}

	close(CONF);
}


#
# Process a copyfiles section.
#
sub copyfiles
{
	my $copy_name = shift;
	my $copy = getSection($copy_name);
	if(!$copy)
	{
		printf "Parse error in inf. Unable to find section $copy_name\n";
		return -1;
	}

	my @lines = split("\n", $copy->{data});

	for(my $i = 0; $i < @lines; $i++)
	{
	  my $line = $lines[$i];
	  $line = trim($line);

	  last if (!$line);
	  last if ($line =~ /^\[/);
	  my @files = split(",", $line);
	  for (my $j = 0; $j < @files; $j++)
	    {
	      my $file = $files[$j];
	      $file =~ s/^;//;
	      $file = trim(remComment($file));
	      $file =~ s/,+.*//;
	      $file = trim($file);
	      my $nocopy = 0;
	      for(my $k = 0; $k < @copy_blacklist; $k++)
			{
				if($copy_blacklist[$k] eq lc($file))
				{
					$nocopy = 1;
				}
			}

			my $dir = finddir($file);
			if($dir)
			{
				$dir = findfile("", $dir);
			}

			my $realname = findfile($dir, $file);

			if($realname)
			{
				my $newname = lc($realname);
				if($dir)
				{
					$realname = "$dir/$realname";
				}
				if(!$nocopy)
				{
					`cp -u $instdir/$realname $confdir/$driver_name/$newname`;	
					`chmod 644 $confdir/$driver_name/$newname`;	
				}
				
			}
		}
	}
}

sub finddir
{
	my $filename = shift;
	my $sourcedisksfiles = getSection("sourcedisksfiles");
	if(!$sourcedisksfiles)
	{
		return "";
	}
	my @lines = split("\n", $sourcedisksfiles->{data});
	for(my $i = 0; $i < @lines; $i++)
	{
		my $line = trim(remComment($lines[$i]));
		$line =~ /(.+)=.+,+(.*)/;
		my $file = trim($1);
		my $dir = trim($2);
		if($file and $dir and lc($filename) eq lc($file))
		{
			return $dir;
		}
	}
	return "";
}

#
# Find a file in a case-insensitive way.
#
sub findfile
{
	my $dir = shift;
	my $file = shift;

	if(!opendir(DIR, "$instdir/$dir"))
	{
		print "Unable to open $instdir\n";
		return "";
	}
	
	my @allfiles = readdir(DIR);
	for(my $i = 0; $i < @allfiles; $i++)
	{
		if(lc($allfiles[$i]) eq lc($file))
		{
			closedir(DIR);	
			return $allfiles[$i]; 
		}
	}
	closedir(DIR);	
	return "";
}


#
# This section contains pointers to the section with the parameters to be
# added to the registry.
#
sub addReg
{
	my $reg_name = shift;
	my $reg = getSection($reg_name);
	if(!$reg)
	{
		printf "Parse error in inf. Unable to find section $reg_name\n";
		return -1;
	}

	my $param;
	my $type;
	my $val;
	my $found;
	my $gotParam = 0;
	
	my @lines = split("\n", $reg->{data});
	for(my $i = 0; $i < @lines; $i++)
	{
		my $line = trim(remComment($lines[$i]));
		if($line)
		{
			$line =~ /([^,]*),([^,]*),([^,]*),([^,]*),(.*)/; 
			my $hkr = trim($1);
			my $p1 = stripquotes(substStr(trim($2)));
			my $p2 = stripquotes(substStr(trim($3)));
			my $p3 = stripquotes(substStr(trim($4)));
			my $p4 = stripquotes(substStr(trim($5)));

			if($p1)
			{
				if($p1 =~ /ndi\\params\\(.+)/i)
				{
					$1 =~ /(.+)\\.*/;
					
					if($1 ne $param)
					{
						$found = 0;
						$param = $1;
						$type = "";
						$val = "";
					}
					if(lc($p2) eq "type")
					{
						$found++;
						$type = $p4;
					}
					elsif(lc($p2) eq "default")
					{
						$found++;
						$val = $p4;
					}

					if($found == 2)
					{
						$gotParam = 1;
					}
				}
			}
			else
			{
				#print "type 2: $reg_name '$p1', '$p2', '$p3', '$p4':'$line'\n";		
				$param = $p2;
				$val = $p4;
				$gotParam = 1;
			}

			
			if($gotParam and $param ne "BusType" and $param ne "")
			{
				my $s = "$param|$val";
				if($param_fixlist{"$s"})
				{
					my $sOld = $s;
					$s = $param_fixlist{"$s"};
					print "Forcing parameter $sOld to $s\n"; 
				}
				
				print CONF "$s\n";
				$param = "";
				$gotParam = 0;
			}
		}
	}
}

sub substStr
{
	my $s = shift;
	if($s =~ /^\%(.+)$\%/)
	{
		return getString($1);
	}
	return $s;
}


#
# Parse a device-id line.
#
sub parseID
{
	my $s = uc(shift);
	if($s =~ /PCI\\VEN_(\w+)&DEV_(\w+)&SUBSYS_(\w{4})(\S{4})/)
	{
		return (5, $1, $2, $4, $3);
	}
	elsif($s =~ /PCI\\VEN_(\w+)&DEV_(\w+)/)
	{
		return (5, $1, $2);
	}
	elsif($s =~ /USB\\VID_(\w+)&PID_(\w+)/)
	{
		return (0, $1, $2);
	}
}

#
# remove whitsepace at front and end.
#
sub trim
{
	my $s = shift;
	$s =~ s/^\s*//;
	$s =~ s/\s*$//;
	return $s;
}


sub stripquotes
{
	my $s = shift;
	$s =~ s/"(.*)"/$1/;
	return $s;
}


sub getKeyVal
{
	my $line = shift;

	$line = remComment($line);
	(my $key, my $val) = split("=", $line);
	if($line =~ /(.+)=(.+)/)
	{
		return (trim($1), trim($2));
	}
}


sub remComment
{
	my $s = shift;
	$s=~ s/([^;]*);.*/$1/;
	return $s;
}

#
# Initialize the string symbol table
#
sub initStrings
{
	my $s = getSection("strings");
	if(!$s)
	{
		return;
	}
	my @lines = split("\n", $s->{data});

	for(my $i = 0; $i < @lines; $i++)
	{
		(my $key, my $val) = getKeyVal($lines[$i]);
		if($key)
		{
			$val =~ s/"(.+)"/$1/; 
			$strings{$key} = $val;
#			print "$key=$val\n";
		}
	}
}


#
# fetch a string from the symbol table
#
sub getString
{
	my $s = shift;
	return $strings{$s};
}


#
# Loacate a section.
#
sub getSection
{
	my $needle = shift;

	for(my $i = 0; $i < @sections;  $i++)
	{
#		print "Searching: '" . lc($sections[$i]->{name}) . "' == '" . lc($needle) . "'\n";

		if( lc($sections[$i]->{name}) eq lc($needle))
		{
#			print "found!\n\n";
			return $sections[$i];
		}
	}
#	print "not found!\n\n";
	return 0;
}


#
# Load inf and split into different sections.
#
sub loadinf
{
	my $filename = shift;
	my %def_section;
	my $section = \%def_section;
	
	if(!open(INF, $filename))
	{
		return -1;
	}

	my $i = 0;
	$section->{name} = "none";
	while(my $s = <INF>)
	{
		#Convert from unicode
		$s =~ s/\xff\xfe//;
		$s =~ s/\0//g;

		$s =~ s/\s*$//;	#Remove trailing whitespace and \r
		$s .= "\n";
		if($s =~ /^\[(.+)\]\s*/)
		{
			$sections[$i++] = $section;		
			my %new_section;
			$section = \%new_section;
			$section->{name} = $1;
		}
		else
		{
			$section->{data} .= $s;
		}
	}
	
	$sections[$i++] = $section;  
	close(INF);


#	print "Sections:\n";
#	for(my $i = 0; $i < @sections; $i++)
#	{
#		print $sections[$i]->{name} . "\n";		
#	}
#	print "\n";
}


