diff -r 000000000000 -r 08ec8eefde2f featuremgmt/featuremgr/tools/datfilehelpers/FMCreate.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/featuremgmt/featuremgr/tools/datfilehelpers/FMCreate.pm Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,529 @@ +#!perl -w +# Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# + +use strict; + +# +# Perl module to create and maintain feature manager data files. +# You can either set up the information programmatically or else load up +# information from a pre-existing feature data file and then modify it. You +# can also save the information to a file (in feature manager dataset format). +# +# This class maintains header information plus two arrays, one containing +# feature flag information and the other containing default supported range +# information. Those are themselves objects and have their own accessor +# methods. +# + +package FMCreate; + +use featureflag; +use featuredsr; + +# +# n e w +# +# Create a new FMCreate object. For example 'my $fmc = FMCreate->new(); +# +sub new +{ + my $arg = shift; + my $class = ref($arg) || $arg; + my $self = { + typefield => "feat", # 4 bytes wide. + fileversion => 1, # 2 bytes. + fileflags => 0, # 2 bytes. + numfeatures => 0, # 4 bytes. (this is 'x') + numdefuid => 0, # 4 bytes. (this is 'y') + endian => "LE", + packprefix => "V", # Changed with endian-ness. + # Used to create binary strings. + + featureflags => [], # There are x of these. + dsrs => [], # There are y of these. + }; + bless $self, $class; + return $self; +} + +# Print to STDOUT the header information, feature flags information and +# default supported range information. +sub ShowALL +{ + my $self = shift; + return undef unless(ref($self)); + $self->ShowHeader(); + $self->ShowFeatureFlags(); + $self->ShowDSRs(); + return 1; +} + +# Print to STDOUT the header information we have. +sub ShowHeader +{ + my $self = shift; + return undef unless(ref($self)); + + # Get header information.. + my $typefield = $self->TypeField(); + my $fileversion = $self->FileVersion(); + my $fileflags = $self->FileFlags(); + my $numfeatures = $self->NumFeatures(); + my $numdefuid = $self->NumDefUid(); + + # Display it in English. + print "TYPEFIELD: '$typefield'\n"; + print "FILEVERSION: '$fileversion'\n"; + print "FILEFLAGS: '$fileflags'\n"; + print "NUMFEATURES: '$numfeatures'\n"; + print "NUMDSRS: '$numdefuid'\n"; + + return(1); +} + +# Call the 'Show' method in each of the feature flag objects we +# have - this will print their content to STDOUT. +sub ShowFeatureFlags +{ + my $self = shift; + return undef unless(ref($self)); + my $ffs = $self->FeatureFlags; + return 1 unless(@$ffs); + + print "\nFeature Flags\n"; + print "=============\n"; + for my $ff (@$ffs) + { + $ff->Show(); + } + return 1; +} + +# Call the 'Show' method in each of the default supported range objects we +# have - this will print their content to STDOUT. +sub ShowDSRs +{ + my $self = shift; + return undef unless(ref($self)); + my $fds = $self->FeatureDSRs; + return 1 unless(@$fds); + print "\nFeature DSRs\n"; + print "============\n"; + for my $fd (@$fds) + { + $fd->Show(); + } + return 1; +} + +# Get/Set the endian-ness we want. Changes the 'packprefix' member which is +# used in the creation of binary data. +sub Endian +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + return $self->{endian} unless(defined($arg)); + if($arg =~ m/(LE|BE)/i) + { + my $endian = uc($1); + $self->{endian} = $endian; + # Used by 'pack' to generate binary strings. + $self->{packprefix} = "V" if($endian eq "LE"); + $self->{packprefix} = "N" if($endian eq "BE"); + } + return $self->{endian}; +} + +# This is 'feat'. +sub TypeField +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + $self->{typefield} = $arg if(defined($arg)); + return $self->{typefield}; +} + +sub FileVersion +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + # Should we be testing for a numeric value? + $self->{fileversion} = $arg if(defined($arg)); + return $self->{fileversion}; +} + +sub FileFlags +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + $self->{fileflags} = $arg if(defined($arg)); + return $self->{fileflags}; +} + +# How many feature flag objects have we got? +sub NumFeatures +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + $self->{numfeatures} = $arg if(defined($arg)); + return $self->{numfeatures}; +} + +# How many default supported range objects have we got? +sub NumDefUid +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + $self->{numdefuid} = $arg if(defined($arg)); + return $self->{numdefuid}; +} + +# Create a binary string containing the header information for the +# feature manager data file based on the various fields in this object. +sub CreateBinaryHeader +{ + my $self = shift; + return undef unless(ref($self)); + my $hdrstring; + + # Get the letter for packing information with 'pack' into a binary form. + my $pack16 = lc($self->{packprefix}); + my $pack32 = uc($self->{packprefix}); + + # Get header information.. + my $typefield = $self->TypeField(); + my $fileversion = $self->FileVersion(); + my $fileflags = $self->FileFlags(); + my $numfeatures = $self->NumFeatures(); + my $numdefuid = $self->NumDefUid(); + + # Write the 'type' field out. This is 'feat'. Would this be different on + # big-endian systems? + $hdrstring = $typefield; + + # Now the file version number. A 16-bit value.. Will this cause trouble + # if the shifted value is signed? + $hdrstring .= pack($pack16 . "1", $fileversion); + + # Now the file flags. Another 16-bit value.. + $hdrstring .= pack($pack16 . "1", $fileflags); + + # Now the number of listed features - a 32-bit value. + $hdrstring .= pack($pack32 . "1", $numfeatures); + + # Now the number of listed features - a 32-bit value. + $hdrstring .= pack($pack32 . "1", $numdefuid); + + return $hdrstring; +} + +# Writes the binary file specified as an argument with the content of this +# and contained feature flag and dsr objects. +sub WriteToFile +{ + my $self = shift; + return undef unless(ref($self)); + my $file = shift; + return undef unless(defined($file)); + open FILE, "> $file" or die "Couldn't open file '$file' for writing.\n"; + binmode FILE; + print FILE $self->BinaryContent(); + close FILE; + return 1; +} + + +# Create the binary equivalent of the internal data and return it as a +# string. +sub BinaryContent +{ + my $self = shift; + return undef unless(ref($self)); + + # First get the header information for the registry manager data file. + my $ret = $self->CreateBinaryHeader(); + + # Get the feature flag entries.. This is an array reference. + # For each one append the binary representation of the information + # contained. + my $ffs = $self->FeatureFlags; + for my $ff (@$ffs) + { + $ret .= $ff->BinaryContent(); + } + + # Get the feature default supported range entries.. This is an array + # reference too. For each one append the binary representation of + # uid range contained. + my $fdsrs = $self->FeatureDSRs; + for my $ff (@$fdsrs) + { + $ret .= $ff->BinaryContent(); + } + return $ret; +} + +# Return a reference to the 'feature flags' array. +sub FeatureFlags +{ + my $self = shift; + return undef unless(ref($self)); + return $self->{featureflags}; +} + +# Add a Feature Flag object. Perhaps there should be code to check if we +# already know about this feature flag. (i.e check the uid against the ones +# we have). +sub AddFeatureFlag +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + die "Method 'AddFeatureFlag' requires a 'FeatureFlag' object as argument.\n" + unless(ref($arg) eq "FeatureFlag"); + push @{$self->FeatureFlags()}, $arg; + $self->NumFeatures($self->NumFeatures() + 1); + return 1; +} + +# Return a reference to the 'feature dsrs' array. +sub FeatureDSRs +{ + my $self = shift; + return undef unless(ref($self)); + return $self->{dsrs}; +} + +# Add a Feature 'Default Support Range' object. +sub AddFeatureDSR +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + die "Method 'AddFeatureDSR' requires a 'FeatureDSR' object as argument.\n" + unless(ref($arg) eq "FeatureDSR"); + push @{$self->FeatureDSRs()}, $arg; + $self->NumDefUid($self->NumDefUid() + 1); + return 1; +} + +# This method loads up it's information from an existing feature manager +# data file. This will die if it thinks there is something wrong with the file. +sub LoadUp +{ + my $self = shift; + return undef unless(ref($self) eq "FMCreate"); + + my $packprefix16 = lc($self->{packprefix}); + my $packprefix32 = uc($self->{packprefix}); + + my $file = shift; + return undef unless(defined($file) and -f $file); + open FILE, $file or die "Couldn't open '$file'\n"; + binmode FILE; + my ($tmp, $feat); + + # First get the file size. + my $fsz = sysseek(FILE, 0, 2); + sysseek(FILE, 0, 0); + + # Read the 'feat' marker from the top of the file. Check it. + die "Unable to read first 4 bytes from '$file'" + unless(4 == sysread(FILE, $feat, 4) ); + die "First four bytes of '$file' do not contain 'feat'" + unless($feat eq "feat"); + $self->TypeField($feat); # Pointless. It's set to that anyway. + + # Read the file version number. + die "Unable to read two bytes from index 4 from '$file'" + unless(2 == sysread(FILE, $tmp, 2) ); + my $filever = unpack( $packprefix16, $tmp ); + $self->FileVersion($filever); + + # Read the file flags. + die "Unable to read two bytes from index 6 from '$file'" + unless(2 == sysread(FILE, $tmp, 2) ); + my $fileflags = unpack( $packprefix16, $tmp ); + $self->FileFlags($fileflags); + + # Read the number of features. Don't do anything with this yet.. + die "Unable to read four bytes from index 8 from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + my $nfeat = unpack( $packprefix32, $tmp ); + + # Read the number of DSRs. Don't do anything with this yet.. + die "Unable to read four bytes from index 12 from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + my $ndsr = unpack( $packprefix32, $tmp ); + + # Forget it if the filesize is clearly wrong. + my $expsz = 16 + 12*$nfeat + 8*$ndsr; + die "The file '$file' is $fsz bytes long, but the content suggests it should be $expsz bytes long. NFeatures: $nfeat NDSRs: $ndsr\n" unless($expsz == $fsz); + + # Now read in the feature flags. + my $offset = 16; + for(my $ff=0 ; $ff<$nfeat ; $ff++) + { + # Get the UID. + die "Unable to read four bytes (uid) from index $offset from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + $offset += 4; + my $uid = unpack( $packprefix32, $tmp ); + + # Get the status word. + die "Unable to read four bytes (sw) from index $offset from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + $offset += 4; + my $sw = unpack( $packprefix32, $tmp ); + + # Get the user data word. + die "Unable to read four bytes (udw) from index $offset from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + $offset += 4; + my $ud = unpack( $packprefix32, $tmp ); + + my $featflag = FeatureFlag->new($uid, $sw, $ud); + die "Couldn't create a feature flag object!\n" unless(ref($featflag)); + $self->AddFeatureFlag($featflag); + } + + # Now read in the DSRs. + for( my $dsr=0 ; $dsr<$ndsr ; $dsr++ ) + { + # Get the low UID. + die "Unable to read four bytes (lowuid) from index $offset from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + $offset += 4; + my $lowuid = unpack( $packprefix32, $tmp ); + + # Get the high UID. + die "Can't read four bytes (high uid) from index $offset from '$file'" + unless(4 == sysread(FILE, $tmp, 4) ); + $offset += 4; + my $highuid = unpack( $packprefix32, $tmp ); + + my $fd = FeatureDSR->new($lowuid, $highuid); + die "Couldn't create 'FeatureDSR' object!\n" unless(ref($fd)); + $self->AddFeatureDSR($fd); + } + + # Check if our calculated file offset matches the end of the file. + # This is pointless actually, because we've already checked the file + # size.. + my $fileoffset = sysseek(FILE, 0, 2); + die "End of file offset ($fileoffset) does not match end of DSRs!\n" + unless($fileoffset == $offset); + + close FILE; + return 1; +} + +# Remove the feature flag object specified by UID held in this object (in +# the internal 'featureflags' array). Returns 1 on success, undef otherwise. +sub RemoveFeatureFlagByUID +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + return undef unless(defined($arg)); + my $ffs = $self->FeatureFlags; + + my $idx = 0; + for my $ff (@$ffs) + { + if($ff->UID() == $arg) + { + splice(@$ffs, $idx, 1); + $self->NumFeatures($self->NumFeatures() - 1); + return 1; + } + $idx++; + } + return undef; +} + +# Return a reference to the 'FeatureFlag' object held in this object (in +# the internal 'featureflags' array) with the uid specified as an +# argument. This returns a reference so it's still in this object on return, +# you can modify it and then write out (for example) the data file. +sub GetFeatureFlagByUID +{ + my $self = shift; + return undef unless(ref($self)); + my $arg = shift; + return undef unless(defined($arg)); + my $ffs = $self->FeatureFlags; + for my $ff (@$ffs) + { + return $ff if($ff->UID() == $arg); + } + return undef; +} + + +# Remove the feature DSR object specified by UIDs held in this object (in +# the internal 'dsrs' array). Returns 1 on success, undef otherwise. +sub RemoveDSRByUIDs +{ + my $self = shift; + return undef unless(ref($self)); + my($lowuid, $highuid) = @_; + return undef unless(defined($lowuid) and defined($highuid)); + my $fdsrs = $self->FeatureDSRs; + + my $idx = 0; + for my $fdsr (@$fdsrs) + { + if( ($fdsrs->LowUID() == $lowuid) and + ($fdsrs->HighUID() == $highuid) ) + { + splice(@$fdsrs, $idx, 1); + $self->NumDefUid($self->NumDefUid() - 1); + return 1; + } + $idx++; + } + return undef; +} + +# Return a reference to the 'FeatureDSR' object held in this object (in +# the internal 'dsrs' array) with the low and high uids specified in the +# arguments. This returns a reference so it's still in this object on return, +# you can modify it (by changing the uids) and then write out (for example) +# the data file. +sub GetDSRByUIDs +{ + my $self = shift; + return undef unless(ref($self)); + my($lowuid, $highuid) = @_; + return undef unless(defined($lowuid) and defined($highuid)); + my $fdsrs = $self->FeatureDSRs; + for my $fdsr (@$fdsrs) + { + return $fdsr if( ($fdsr->LowUID() == $lowuid) and + ($fdsr->HighUID() == $highuid)); + } + return undef; +} + +1; +