#!/usr/bin/perl
#
# This module parses NT .INF files containing printer driver information.
# The information is turned into a magical set of data strucutures
# allowing the driver programs to do something useful with the printer
# driver.
package inf_nt;
use strict;
use vars qw($VERSION @ISA @EXPORT_OK);
use Carp qw(carp croak);
use INF qw(inf_get_key inf_get_keys inf_has_key);
# Fill in the info hash with information on what the destination directories
# for the different file sections will be. The default destination directory
# is also determined here.
sub fill_destination_dirs
{
croak("fill_destination_dirs(INF,INFO)") if @_ != 2;
my($inf, $info) = @_;
# The DestDir member will hold the destination for any file section.
$info->{"DestDir"} = {};
# If a DestinationDirs section isn't present, bail out.
if (not inf_has_key($inf,"DestinationDirs")) {
$info->{"DefaultDestDir"} = "66000";
return;
}
# Find and handle a DefaultDestDir if it is present.
if (exists $inf->{"DestinationDirs"}{"DefaultDestDir"}) {
my($num, $subdir) = split(/,/, $inf->{"DestinationDirs"}{"DefaultDestDir"});
$info->{"DefaultDestDir"} = $num;
$info->{"DefaultDestDir"} .= "\\$subdir" if $subdir ne '';
}
# Loop for each file section and add it to the DestDir hash.
foreach my $key (keys %{$inf->{"DestinationDirs"}}) {
next if $key eq 'DefaultDestDir';
my $str = $inf->{"DestinationDirs"}{$key};
my($num, $subdir) = split(/,/, $str);
my $value = $num;
$value .= "\\$subdir" if $subdir ne '';
$info->{"DestDir"}{$key} = $value;
}
}
# The files to be copied for a particular driver are stored as hash refs
# inside an array ref. Each hash ref corresponds to a single file. The
# array ref stores all the files that will be copied.
sub handle_file
{
croak("handle_file(INFO,SRC_FILENAME,DST_FILENAME,DESTDIR)") if @_ != 4;
my($info, $src_filename, $dst_filename, $destdir) = @_;
# Create the CopyFiles node if it doesn't exists yet.
if (not exists $info->{"CopyFiles"}) {
$info->{"CopyFiles"} = [];
}
if (not exists $info->{"SourceDisksNames"}) {
$info->{"SourceDisksNames"} = {};
}
# If the ordinal already exists, skip over to allow overrides by
# the platform-specific sections.
next if exists $info->{"SourceDisksNames"}->{$ordinal};
# Insert an entry for this source disk.
$info->{"SourceDisksNames"}->{$ordinal} = {
'description' => $descr,
'tagfile' => $tagfile,
'path' => $path
};
}
}
sub handle_SourceDisksFiles
{
croak("handle_SourceDisksFiles(INFO,SECTION_HASH)") if @_ != 2;
my($info, $section) = @_;
if (not exists $info->{"SourceDisksFiles"}) {
$info->{"SourceDisksFiles"} = {};
}
# If the ordinal already exists, skip over to allow overrides by
# the platform-specific sections.
next if exists $info->{"SourceDisksFiles"}->{$fname};
# Insert an entry for this source file.
$info->{"SourceDisksFiles"}->{$fname} = {
'ordinal' => $ordinal
};
}
}
sub get_models
{
croak("get_manufacturers(INF, MANUFACTURER)") if @_ != 2;
my($inf, $manufacturer) = @_;
my($device_section_name);
sub parse_inf_nt
{
croak("parse_inf_nt(INF,MANUFACTURER,MODEL,ARCH)") if @_ != 4;
my($inf, $manufacturer, $model, $arch) = @_;
my(%info, $device_section_name);
# Make sure that the [Manufacturer] section exists.
if (not inf_has_key($inf, "Manufacturer")) {
print STDERR "[Manufacturer] section not present.\n";
return undef;
}
# Make sure that the manufacturer is actually listed.
if (inf_has_key(inf_get_key($inf, "Manufacturer"), $manufacturer)) {
if (inf_get_key(inf_get_key($inf, "Manufacturer"), $manufacturer) eq '') {
$device_section_name = $manufacturer;
} else {
$device_section_name = inf_get_key(inf_get_key($inf, "Manufacturer"), $manufacturer);
}
} else {
print STDERR "ERROR: Manufacturer $manufacturer not listed.\n";
return undef;
}
# We now know the name of the device section. Try to find the device that
# the caller gave us in this section.
if (not inf_has_key($inf, $device_section_name)) {
print STDERR "Device section `$device_section_name' does not exist.\n";
return undef;
}
if (not inf_has_key(inf_get_key($inf, $device_section_name), $model)) {
print STDERR "Specified model ($model) not present in .INF file.\n";
return undef;
}
# This model exists so fill in the device name.
$info{pName} = $model;
# Figure out the name of the install section. The install section is the
# heart of the .INF file and determines all actions to be taken.
my($install_section_name, @DEVICE_IDS) = split(/\s*,\s*/, inf_get_key(inf_get_key($inf, $device_section_name), $model));
if ($install_section_name eq '') {
print STDERR "Install section name is blank.\n";
return undef;
}
# Determine if this INF is for NT.
my $is_NT = 0;
$is_NT = 1 if $arch =~ /^W32X86$/i;
$is_NT = 1 if $arch =~ /^W32alpha$/i;
$is_NT = 1 if $arch =~ /^W32mips$/i;
$is_NT = 1 if $arch =~ /^W32ppc$/i;
# Make sure the install section exists.
if (not inf_has_key($inf, $install_section_name)
and not inf_has_key($inf, $install_section_name . ".nt")
and not inf_has_key($inf, $install_section_name . ".ntx86")) {
print STDERR "Install section ($install_section_name) not present.\n";
return undef;
}
my $install_section;
if ($is_NT and inf_has_key($inf, $install_section_name . ".ntx86")) {
$install_section = inf_get_key($inf, $install_section_name . ".ntx86");
} elsif ($is_NT and inf_has_key($inf, $install_section_name . ".nt")) {
$install_section = inf_get_key($inf, $install_section_name . ".nt");
} else {
$install_section = inf_get_key($inf, $install_section_name);
}
# See if there is an optional data section.
my $data_section = {};
if (inf_has_key($install_section, "DataSection")) {
if (not inf_has_key($inf, inf_get_key($install_section, "DataSection"))) {
print STDERR "DataSection directive given but section missing.\n";
return undef;
}
$data_section = inf_get_key($inf, inf_get_key($install_section, "DataSection"));
}
# Handle the ConfigFile directive.
if (inf_has_key($data_section, "ConfigFile")) {
$info{"ConfigFile"} = inf_get_key($data_section, "ConfigFile");
} elsif (inf_has_key($install_section, "ConfigFile")) {
$info{"ConfigFile"} = inf_get_key($install_section, "ConfigFile");
}
## Windows NT always splits the driver and config file up
## Windows 9x places them in the same file
if ($info{"ConfigFile"} eq '') {
# $info{"ConfigFile"} = $install_section_name;
$info{"ConfigFile"} = $info{"DriverFile"};
}
# Parse the destination directory information.
fill_destination_dirs($inf, \%info);
# Handle any files that need to be copied.
if (inf_has_key($data_section, "CopyFiles")) {
handle_CopyFiles(\%info, $inf, inf_get_key($data_section, "CopyFiles"));
}
if (inf_has_key($install_section, "CopyFiles")) {
handle_CopyFiles(\%info, $inf, inf_get_key($install_section, "CopyFiles"));
}
# Handle any AddReg sections.
if (inf_has_key($install_section, "AddReg")) {
foreach my $addreg_name (split(/\s*,\s*/,
inf_get_key($install_section, "AddReg"))) {
if (not inf_has_key($inf, $addreg_name)) {
print STDERR "ERROR: Section given in AddReg doesn't exist.\n";
return undef;
}
handle_AddReg(\%info, inf_get_key($inf, $addreg_name));
}
}
# Handle any DelReg sections.
if (inf_has_key($install_section, "DelReg")) {
foreach my $delreg_name (split(/\s*,\s*/,
inf_get_key($install_section, "DelReg"))) {
if (not inf_has_key($inf, $delreg_name)) {
print STDERR "ERROR: Section given in DelReg doesn't exist.\n";
return undef;
}
handle_DelReg(\%info, inf_get_key($inf, $delreg_name));
}
}
# Handle any SourceDisksNames sections.
if (inf_has_key($inf, "SourceDisksNames.x86")) {
handle_SourceDisksNames(\%info, inf_get_key($inf, "SourceDisksNames.x86"));
}
if (inf_has_key($inf, "SourceDisksNames")) {
handle_SourceDisksNames(\%info, inf_get_key($inf, "SourceDisksNames"));
}
# Handle any SourceDisksFiles section.
if (inf_has_key($inf, "SourceDisksFiles.x86")) {
handle_SourceDisksFiles(\%info, inf_get_key($inf, "SourceDisksFiles.x86"));
}
if (inf_has_key($inf, "SourceDisksFiles")) {
handle_SourceDisksFiles(\%info, inf_get_key($inf, "SourceDisksFiles"));
}