diff -r 000000000000 -r 8e480a14352b messagingfw/biomsgfw/wapptsrc/xml2wap.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/messagingfw/biomsgfw/wapptsrc/xml2wap.pl Mon Jan 18 20:36:02 2010 +0200 @@ -0,0 +1,572 @@ +# Copyright (c) 2004-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: +# + +#!/usr/bin/perl + +# xml2wap.pl +# This script takes an XML file and creates a WAP Binary encoded file from it. +# The constants derfined here are for the WAP Provisioning messages - to handle a different DTD +# you should just be able to change the constants (but I haven't tested that). +# Ian McDowall December 2001 + +use strict; + +$Main::DebugLevel = 2; # Set higher for more debug or lower for less. + +# Global variables used to set standard header values - modify these here +$Main::XMLVersion = 0x01 ; # 0x01 = v1.1 +$Main::PublicId = 0x01 ; # Magic number taken from OTA doc +$Main::Charset = 106 ; # Magic number from OTA + +$Main::EndToken = 1 ; #Magic number from OTA +$Main::InLineString = 3 ; # Magic number from OTA + +# Hash containing defined tag tokens +%Main::TagTokens = ( + "CHARACTERISTIC-LIST", 0x05, + "CHARACTERISTIC", 0x06, + "PARM", 0x07); + +# Hash containing defined attribute name-value pairs. +# Ones which do not appear here are handled as inline strings +%Main::AttributePairs = ( + "TYPE=ADDRESS", 0x06, + "TYPE=URL", 0x07, + "TYPE=NAME", 0x08, + "TYPE=MMSURL", 0x7c, + "NAME=BEARER", 0x12, + "NAME=PROXY", 0x13, + "NAME=PORT", 0x14, + "NAME=NAME", 0x15, + "NAME=PROXY_TYPE", 0x16, + "NAME=URL", 0x17, + "NAME=PROXY_AUTHNAME", 0x18, + "NAME=PROXY_AUTHSECRET", 0x19, + "NAME=SMS_SMSC_ADDRESS", 0x1A, + "NAME=USSD_SERVICE_CODE", 0x1B, + "NAME=GPRS_ACCESSPOINTNAME", 0x1C, + "NAME=PPP_LOGINTYPE", 0x1D, + "NAME=PROXY_LOGINTYPE", 0x1E, + "NAME=CSD_DIALSTRING", 0x21, + "NAME=CSD_CALLTYPE", 0x28, + "NAME=CSD_CALLSPEED", 0x29, + "NAME=PPP_AUTHTYPE", 0x22, + "NAME=PPP_AUTHNAME", 0x23, + "NAME=PPP_AUTHSECRET", 0x24, + "VALUE=GSM/CSD", 0x45, + "VALUE=GSM/SMS", 0x46, + "VALUE=GSM/USSD", 0x47, + "VALUE=IS-136/CSD", 0x48, + "VALUE=GPRS", 0x49, + "VALUE=9200", 0x60, + "VALUE=9201", 0x61, + "VALUE=9202", 0x62, + "VALUE=9203", 0x63, + "VALUE=AUTOMATIC", 0x64, + "VALUE=MANUAL", 0x65, + "VALUE=AUTO", 0x6a, + "VALUE=9600", 0x6b, + "VALUE=14400", 0x6c, + "VALUE=19200", 0x6d, + "VALUE=28800", 0x6e, + "VALUE=38400", 0x6f, + "VALUE=PAP", 0x70, + "VALUE=CHAP", 0x71, + "VALUE=ANALOGUE", 0x72, + "VALUE=ISDN", 0x73, + "VALUE=43200", 0x74, + "VALUE=57600", 0x75, + "VALUE=MSISDN_NO", 0x76, + "VALUE=IPV4", 0x77, + "VALUE=MS_CHAP", 0x78, + "TYPE=MMSURL", 0x7c, + "TYPE=ID", 0x7d, + "NAME=ISP_NAME", 0x7e, + "TYPE=BOOKMARK", 0x7f +); + +# Hash containing defined attribute names which get linked to inline strings +%Main::AttributeSingles = ( + "NAME", 0x10, + "VALUE", 0x11); + +# Global Variables used for data storage :-( +$Main::ReadBuffer = ''; # Buffer holds a line at a time as read in +$Main::InFileComplete = 0; # Boolean - have we finished reading the input file +$Main::ReadAllTokens = 0; # Boolean - have we read all tokens yet + +# Global variables used for pending writes. +# The octet used for a tag has the top two bits set depending on whether or +# it includes content (i.e. other elements) and / or attributes. +# We don't know whether or not it includes these until we hit another tag or an +# end tag. Therefore, we build up a string of pending attribute data and have a +# pending tag identifier. We never need more than one. +$Main::PendingTag = 0; +$Main::PendingAttribs = 0; +$Main::TagHasContent = 0; +$Main::TagHasAttribs = 0; + +############################################################################### +# Main entry point + +if(!$ARGV[0] || !$ARGV[1]) + { + &OutputHelp(); + } +else + { + my($InFileName, $OutFileName);# Input and output file names + $InFileName = $ARGV[0]; + $OutFileName = $ARGV[1]; + + # Open the XML file + open( INFILE, $InFileName ) or die("Unable to open $InFileName for reading"); + print "Reading $InFileName\n"; + + # Open the output file and create the binary encoded version of the XML + open( OUTFILE, ">$OutFileName" ) or die("Unable to open $OutFileName for writing"); + print "Creating $OutFileName\n"; + + &ParseXMLFile(); + + close( INFILE ); + close( OUTFILE ); + print "Processing complete\n"; + } + + +############################################################################### +# Describe required arguments +sub OutputHelp + { + print "This script requires two arguments. The first is the name of an XML file\n"; + print "to be taken as input. The second is the name of a WAP encoded binary XML\n"; + print "to be created.\n"; + } + +############################################################################### +# Routine to read and parse an input XML file +sub ParseXMLFile + { + # Output the version, publicid and charset + &OutputStandardHeader(); + + my $Token = &ReadToken(); + while(!$Main::ReadAllTokens) + { + # Behaviour depends on the token type + if($Token eq ''); + } + elsif($Token eq ''); + } + elsif(substr($Token,0,1) eq '<') + {# Element - process it + &ParseElement($Token); + } + $Token = &ReadToken(); + } + } + +############################################################################### +# Routine to parse an element +sub ParseElement + { + my $ElementName = shift(@_); + $ElementName = substr($ElementName,1); #trim leading '<' + if(substr($ElementName,0,1) eq '/') + {# closing tag + chop($ElementName); + &DebugPrint(2,"Parsing end of element $ElementName\n"); + + # Flush any pending tag + if($Main::PendingTag != 0) + { + &OutputPendingTag(); + } + + # Output an end token, regardless of what closing tag we have + &OutputOctet($Main::EndToken); + } + else + { + my $HasAttribs = 1; + if(substr($ElementName,-1) eq '>') + { + $HasAttribs = 0; + chop($ElementName); + } + my $HasContent = 1; + if(substr($ElementName,-1) eq '/') + { + $HasContent = 0; + chop($ElementName); + } + &DebugPrint(2,"Parsing element $ElementName\n"); + + # Flush any pending tag + if($Main::PendingTag != 0) + { + &OutputPendingTag(); + } + + # We have a new tag - make it pending + $Main::PendingTag = $Main::TagTokens{$ElementName}; + if(!$Main::PendingTag) + { + print "Unrecognised tag $ElementName\n"; + } + splice(@Main::PendingAttribs,0); #empty pending attribs array + + if($HasAttribs) + { + my $AttToken = &ReadToken(); + while(substr($AttToken,-1) ne '>') # sloppy I know + { + my $EqToken = &ReadToken(); # we could check this + my $ValToken = &ReadToken(); + &PushAttribute($AttToken, $ValToken); + &DebugPrint(2,"Attribute $AttToken = $ValToken\n"); + $AttToken = &ReadToken(); + } + if(substr($AttToken,-2) eq '/>') + { + $HasContent = 0; + } + } + + # If we had any attributes then flag this + if(@Main::PendingAttribs > 0) + { + $Main::TagHasAttributes = 1; + } + $Main::TagHasContent = $HasContent; + + # Flush any pending tag + if($Main::PendingTag != 0) + { + &OutputPendingTag(); + } + + } + } + +############################################################################### +# Routine to skip until it matches a token (eating the matched token) +sub SkipTill + { + my $SkipToken = shift(@_); + my $Token = &ReadToken(); + while(!$Main::ReadAllTokens && ($Token ne $SkipToken)) + { + $Token = &ReadToken(); + } + &DebugPrint(3,"Skipped till $SkipToken\n"); + } + +############################################################################### +# Routine to read the next token from the input file +# A token is delineated by whitespace (so it won't work too well with strings with +# embedded newlines) or quotes +sub ReadToken + { + my($FoundToken); + $FoundToken = ''; + + if(!$Main::ReadAllTokens) + { + &RefreshInputBuffer; + if(@Main::ReadTokens > 0) + { + $FoundToken = shift(@Main::ReadTokens); + } + while(length($FoundToken) <= 0) + { + if((@Main::ReadTokens <= 0) && $Main::InFileComplete) + { + $Main::ReadAllTokens = 1; + last; + } + &RefreshInputBuffer; + if(@Main::ReadTokens > 0) + { + $FoundToken = shift(@Main::ReadTokens); + } + } + } + + &DebugPrint(4,"Token :$FoundToken:\n"); + return $FoundToken; + } + +############################################################################### +# Routine to refresh the input buffer +sub RefreshInputBuffer + { + while((@Main::ReadTokens <= 0) && !$Main::InFileComplete) + { + $Main::ReadBuffer = ; + &DebugPrint(5, $Main::ReadBuffer); + + if(length($Main::ReadBuffer) <= 0) + { + $Main::InFileComplete = 1; + &DebugPrint(4,"Input file exhausted\n"); + } + else + { + # Remove leading and trailing whitespace + $Main::ReadBuffer =~ s/^\s+//; + $Main::ReadBuffer =~ s/\s+$//; + # Split into an array of tokens on whitespace and quotes and equals - lose the quotes on the way + my ($OneToken, $OneChar); + while(length($Main::ReadBuffer) > 0) + { + $OneChar = substr($Main::ReadBuffer,0,1); + $Main::ReadBuffer = substr($Main::ReadBuffer,1); + if(($OneChar eq ' ') || ($OneChar eq "\t")) + { # whitespace is separator outside quotes + &DebugPrint(6,"Whitespace\n"); + if(length($OneToken) > 0) + { + push(@Main::ReadTokens, $OneToken); + $OneToken = ''; + } + } + elsif($OneChar eq '"') + { # copy to next quote, including whitespace + &DebugPrint(6,"Start of quotes\n"); + if(length($OneToken) > 0) + { + push(@Main::ReadTokens, $OneToken); + $OneToken = ''; + } + $OneChar = ''; + until(($OneChar eq '"') || (length($Main::ReadBuffer) <= 0)) + { + $OneToken = $OneToken.$OneChar; + $OneChar = substr($Main::ReadBuffer,0,1); + $Main::ReadBuffer = substr($Main::ReadBuffer,1); + } + &DebugPrint(6,"quoted string '$OneToken'\n"); + push(@Main::ReadTokens, $OneToken); + $OneToken = ''; + } + elsif($OneChar eq '=') + { # = is separate token + &DebugPrint(6,"char =\n"); + if(length($OneToken) > 0) + { + push(@Main::ReadTokens, $OneToken); + $OneToken = ''; + } + push(@Main::ReadTokens,'='); + } + else + { # routine char - append to building token + &DebugPrint(6,"Char $OneChar\n"); + $OneToken = $OneToken.$OneChar; + } + }#endwhile + #last token on the line + if(length($OneToken) > 0) + { + push(@Main::ReadTokens, $OneToken); + $OneToken = ''; + } + + &DebugPrint(5,join( ':', @Main::ReadTokens)."\n"); + } + } + } + +############################################################################### +# Routine to output a standard set of header fields +# These are all set by globals at the head of the script (for ease of modification) +sub OutputStandardHeader() + { + # Output the XML version + &OutputOctet($Main::XMLVersion); + + # Output a standard public Id + &Output_mb_u_int32($Main::PublicId); + + # Output charset + &Output_mb_u_int32($Main::Charset); + + # Output a zero-length string table + &OutputOctet(0); + + } + +############################################################################### +# Routine to push an attribute name, value pair in one of a number of ways +sub PushAttribute() + { + my $AttName = shift(@_); + my $AttVal = shift(@_); + + my $PairToken = $Main::AttributePairs{$AttName.'='.$AttVal}; + if($PairToken) + { + push(@Main::PendingAttribs,$PairToken); + } + else + { + my $AttribToken = $Main::AttributeSingles{$AttName}; + if($AttribToken) + { + push(@Main::PendingAttribs,$AttribToken); + &PushInLineString($AttVal); + print "Attribute $AttName has string (rather than token) value $AttVal\n"; + } + else + { + print "Unrecognised attribute $AttName\n"; + } + } + } + +############################################################################### +# Routine to flush a pending tag and any attributes +# +sub OutputPendingTag() + { + &DebugPrint(3,"Output pending tag $Main::PendingTag\n"); + my $TagOctet = $Main::PendingTag; + if( $Main::TagHasContent) + { + $TagOctet = $TagOctet | 0x40 ; # Set next-to-top bit for has content + } + if( $Main::TagHasAttributes) + { + $TagOctet = $TagOctet | 0x80 ; # Set top bit for has attributes + } + &OutputOctet($TagOctet); + + if($Main::TagHasAttributes) + { + &OutputOctetArray(@Main::PendingAttribs); + &OutputOctet($Main::EndToken); # END after attributes + } + else + { + &DebugPrint(3,"Tag has no attributes\n"); + } + + # Clean out pending + $Main::PendingTag = 0; + splice(@Main::PendingAttribs,0); #empty pending attribs array + } + +############################################################################### +# Routine to output a mb_u_int32 value - up to 32 bits but divided into 7-bit +# chunks and the top bit is set for continuation +sub Output_mb_u_int32() + { + my $InNum = shift(@_); + + my @OutBytes; + my $ByteCount = 0; + while( $ByteCount < 5 ) # magic number - maximum number of octets output + { + my $OctetValue = $InNum & 0x7f; + if($OctetValue > 0) + { + push(@OutBytes, $OctetValue); + $InNum = $InNum >> 7; + $ByteCount ++; + } + else + { + last; + } + } + + if($ByteCount > 0) + { + while($ByteCount > 0) + { + if($ByteCount == 1) + { # Output last byte without continuation bit + &OutputOctet($OutBytes[$ByteCount-1]); + } + else + { # Output byte with continuation bit + &OutputOctet($OutBytes[$ByteCount-1]|0x80); + } + $ByteCount --; + } + } + else # zero - just output a zero byte + { + &OutputOctet(0); + } + } + +############################################################################### +# Output a single octet +sub OutputOctet + { + my $OctetValue = shift(@_); + print OUTFILE chr($OctetValue); + &DebugPrint(3, sprintf(":%lx:", $OctetValue)); + } + +############################################################################### +# Add an inline string to the pending attributes buffer +sub PushInLineString + { + my $InString = shift(@_); + push(@Main::PendingAttribs, $Main::InLineString); + my $Index; + for( $Index = 0 ; $Index < length($InString) ; $Index ++) + { + push(@Main::PendingAttribs, ord(substr($InString,$Index,1))); + } + push(@Main::PendingAttribs, 0); # terminating null + } + +############################################################################### +# Output an array of octet values +sub OutputOctetArray + { + while(@_ > 0) + { + my $OctetValue = shift(@_); + &OutputOctet($OctetValue); + } + } + +############################################################################### +# Debug print routine - takes a level of detail and a string and conditionally +# prints the string +sub DebugPrint() + { + my $DebugLevel = shift(@_); + my $DebugString = shift(@_); + if( $DebugLevel <= $Main::DebugLevel ) + { + print $DebugString; + } + } + +###### End of File ###### +