charconvfw/charconvplugins/tools/cnvtool.pl
changeset 0 1fb32624e06b
equal deleted inserted replaced
-1:000000000000 0:1fb32624e06b
       
     1 #
       
     2 # Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 use strict;
       
    18 use integer;
       
    19 
       
    20 BEGIN
       
    21 	{
       
    22 	my $perlScriptPath=$0;
       
    23 	my $os = $^O; #get the OS type
       
    24 	#check OS type
       
    25   if($os=~/MSWin32/) #Windows OS
       
    26     {
       
    27     $perlScriptPath=~s/\//\\/g; # replace any forward-slashes with back-slashes
       
    28     $perlScriptPath=~s/(\\?)[^\\]+$/$1/; # get rid of this Perl-script's file-name
       
    29     }
       
    30   else #Unix OS
       
    31     {
       
    32     $perlScriptPath=~s/\\/\//g; # replace any back-slashes with forward-slashes
       
    33     $perlScriptPath=~s/(\/?)[^\/]+$/$1/; # get rid of this Perl-script's file-name
       
    34     }
       
    35 	unshift(@INC, $perlScriptPath); # can't do "use lib $perlScriptPath" here as "use lib" only seems to work with *hard-coded* directory names
       
    36 	}
       
    37 use PARSER;
       
    38 use WRITER;
       
    39 
       
    40 $|=1; # ensures that any progress information sent to the screen is displayed immediately and not buffered
       
    41 if ((@ARGV==0) || ($ARGV[0]=~/\?/i) || ($ARGV[0]=~/-h/i) || ($ARGV[0]=~/help/i))
       
    42 	{
       
    43 	die("\nVersion 021\n\nCharacter-set conversion-table generating tool\nCopyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).\n\nUsage:\n\n\tcnvtool <control-file> <source-file> <output-file> [options]\n\nwhere the following options are available (each has a short form and a long form which are shown below separated by a '|'):\n\n\t-s | -generateSourceCode\n\t-c | -columns(<a>: <b>, <c>)\n\t-r | -omitReplacementForUnconvertibleUnicodeCharacters\n\t-p | -cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed\n\t-u | -sourceFilesToSubtract(<a>, <b>, ...)\n\n");
       
    44 	}
       
    45 my $generateSourceCode=0;
       
    46 my @columns=(2, 1, 2);
       
    47 my $omitReplacementForUnconvertibleUnicodeCharacters=0;
       
    48 my $cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed=0;
       
    49 my @sourceFilesToSubtract=();
       
    50 my $flattenHashAndSave=0; # this flag is not published for use outside of the CHARCONV component
       
    51 &extractCommandLineFlags(\$generateSourceCode, \@columns, \$omitReplacementForUnconvertibleUnicodeCharacters, \$cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed, \@sourceFilesToSubtract, \$flattenHashAndSave);
       
    52 (!$omitReplacementForUnconvertibleUnicodeCharacters || $generateSourceCode) or die("Error: bad combination of flags\n");
       
    53 my $controlFile=shift;
       
    54 my $sourceFile=shift;
       
    55 my $outputFile=shift;
       
    56 print("Generating $outputFile...\n");
       
    57 my $uid=0;
       
    58 my $endiannessAsText='';
       
    59 my $endianness=0;
       
    60 my $replacementForUnconvertibleUnicodeCharacters='';
       
    61 my @foreignVariableByteData=();
       
    62 my @foreignToUnicodeData=();
       
    63 my @unicodeToForeignData=();
       
    64 my %foreignCharacterCodes=();
       
    65 my %unicodeCharacterCodes=();
       
    66 my %preferredForeignCharacterCodesForConflictResolution=();
       
    67 my %preferredUnicodeCharacterCodesForConflictResolution=();
       
    68 my %additionalSubsetTables=();
       
    69 my %privateUseUnicodeCharacterSlotsUsed=();
       
    70 
       
    71 print("    reading $controlFile...\n");
       
    72 open(CONTROL_FILE, "< $controlFile") or die("Error: could not open \"$controlFile\" for reading\n");
       
    73 &readHeaderFromControlFile(\*CONTROL_FILE, $controlFile, $generateSourceCode, \$uid, \$endiannessAsText, \$endianness, \$replacementForUnconvertibleUnicodeCharacters, $flattenHashAndSave);
       
    74 &readForeignVariableByteDataFromControlFile(\*CONTROL_FILE, $controlFile, \@foreignVariableByteData);
       
    75 &readOneDirectionDataFromControlFile(\*CONTROL_FILE, $controlFile, \@foreignToUnicodeData, \%preferredUnicodeCharacterCodesForConflictResolution, \%additionalSubsetTables, 1);
       
    76 &readOneDirectionDataFromControlFile(\*CONTROL_FILE, $controlFile, \@unicodeToForeignData, \%preferredForeignCharacterCodesForConflictResolution, \%additionalSubsetTables, 0);
       
    77 close(CONTROL_FILE) or die("Error: could not close \"$controlFile\"\n");
       
    78 
       
    79 print("    reading $sourceFile...\n");
       
    80 open(SOURCE_FILE, "< $sourceFile") or die("Error: could not open \"$sourceFile\" for reading\n");
       
    81 &readSourceFile(\*SOURCE_FILE, $sourceFile, \%foreignCharacterCodes, \%unicodeCharacterCodes, \@columns, $cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed, \%privateUseUnicodeCharacterSlotsUsed, 0);
       
    82 close(SOURCE_FILE) or die("Error: could not close \"$sourceFile\"\n");
       
    83 
       
    84 my $sourceFileToSubtract;
       
    85 foreach $sourceFileToSubtract (@sourceFilesToSubtract)
       
    86 	{
       
    87 	print("    subtracting from $sourceFileToSubtract...\n");
       
    88 	open(SOURCE_FILE_TO_SUBTRACT, "< $sourceFileToSubtract") or die("Error: could not open \"$sourceFileToSubtract\" for reading\n");
       
    89 	&readSourceFile(\*SOURCE_FILE_TO_SUBTRACT, $sourceFileToSubtract, \%foreignCharacterCodes, \%unicodeCharacterCodes, \@columns, $cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed, \%privateUseUnicodeCharacterSlotsUsed, 1);
       
    90 	close(SOURCE_FILE_TO_SUBTRACT) or die("Error: could not close \"$sourceFileToSubtract\"\n");
       
    91 	}
       
    92 
       
    93 &warnIfAnyPrivateUseUnicodeCharacterSlotsBeingUsed(\%privateUseUnicodeCharacterSlotsUsed);
       
    94 &resolveConflictsAndFlattenArraysToScalars(\%foreignCharacterCodes, \%preferredForeignCharacterCodesForConflictResolution, 'Unicode', 'foreign');
       
    95 &resolveConflictsAndFlattenArraysToScalars(\%unicodeCharacterCodes, \%preferredUnicodeCharacterCodesForConflictResolution, 'foreign', 'Unicode');
       
    96 &checkForeignVariableByteData($endianness, \@foreignVariableByteData, \@foreignToUnicodeData);
       
    97 
       
    98 print("    writing $outputFile...\n");
       
    99 open(OUTPUT_FILE, "> $outputFile") or die("Error: could not open \"$outputFile\" for writing\n");
       
   100 if ($generateSourceCode)
       
   101 	{
       
   102 	my @sourceCodeOfForeignToUnicodeIndexedTables16=();
       
   103 	my @sourceCodeOfForeignToUnicodeKeyedTables1616=();
       
   104 	my @sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_indexedEntries=();
       
   105 	my @sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_keyedEntries=();
       
   106 
       
   107 	my @sourceCodeOfUnicodeToForeignIndexedTables16=();
       
   108 	my @sourceCodeOfUnicodeToForeignKeyedTables1616=();
       
   109 	my @sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_indexedEntries=();
       
   110 	my @sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_keyedEntries=();
       
   111 
       
   112 	# new for 32 bit encoding begin
       
   113 	my @sourceCodeOfForeignToUnicodeIndexedTables32=();
       
   114 	my @sourceCodeOfForeignToUnicodeKeyedTables3232=();
       
   115 	my @sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_indexedEntries=();
       
   116 	my @sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_keyedEntries=();
       
   117 
       
   118 	my @sourceCodeOfUnicodeToForeignIndexedTables32=();
       
   119 	my @sourceCodeOfUnicodeToForeignKeyedTables3232=();
       
   120 	my @sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_indexedEntries=();
       
   121 	my @sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_keyedEntries=();
       
   122 	# new for 32 bit endcoding end
       
   123 
       
   124 	my @sourceCodeOfTopLevelStructures=();
       
   125 
       
   126 	&writeSourceCodeHeader(\*OUTPUT_FILE, $outputFile, $replacementForUnconvertibleUnicodeCharacters);
       
   127 	&writeSourceCodeForeignVariableByteData(\@sourceCodeOfTopLevelStructures, \@foreignVariableByteData);
       
   128 	&writeSourceCodeOneDirectionData(\@sourceCodeOfTopLevelStructures,
       
   129 		\@sourceCodeOfForeignToUnicodeIndexedTables16, \@sourceCodeOfForeignToUnicodeKeyedTables1616, \@sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_indexedEntries, \@sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_keyedEntries,
       
   130 		\@sourceCodeOfForeignToUnicodeIndexedTables32, \@sourceCodeOfForeignToUnicodeKeyedTables3232, \@sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_indexedEntries, \@sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_keyedEntries,
       
   131 		\@foreignToUnicodeData, \%unicodeCharacterCodes, 1);
       
   132 	&writeSourceCodeOneDirectionData(\@sourceCodeOfTopLevelStructures,
       
   133 		\@sourceCodeOfUnicodeToForeignIndexedTables16, \@sourceCodeOfUnicodeToForeignKeyedTables1616, \@sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_indexedEntries, \@sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_keyedEntries,
       
   134 		\@sourceCodeOfUnicodeToForeignIndexedTables32, \@sourceCodeOfUnicodeToForeignKeyedTables3232, \@sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_indexedEntries, \@sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_keyedEntries,
       
   135 		\@unicodeToForeignData, \%foreignCharacterCodes, 0);
       
   136 	&writeSourceCodeFinalStuff(\*OUTPUT_FILE,
       
   137 		\@sourceCodeOfForeignToUnicodeIndexedTables16, \@sourceCodeOfForeignToUnicodeKeyedTables1616, \@sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_indexedEntries, \@sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_keyedEntries,
       
   138 		\@sourceCodeOfUnicodeToForeignIndexedTables16, \@sourceCodeOfUnicodeToForeignKeyedTables1616, \@sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_indexedEntries, \@sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_keyedEntries,
       
   139 		\@sourceCodeOfForeignToUnicodeIndexedTables32, \@sourceCodeOfForeignToUnicodeKeyedTables3232, \@sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_indexedEntries, \@sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_keyedEntries,
       
   140 		\@sourceCodeOfUnicodeToForeignIndexedTables32, \@sourceCodeOfUnicodeToForeignKeyedTables3232, \@sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_indexedEntries, \@sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_keyedEntries,
       
   141 		\@sourceCodeOfTopLevelStructures, $endiannessAsText, \%additionalSubsetTables);
       
   142 	}
       
   143 elsif ($flattenHashAndSave)
       
   144 	{
       
   145 	binmode OUTPUT_FILE;
       
   146 	#instead of calling the writeBinaryHeader, just write the data I need followed by 
       
   147 	# writeBinaryForeignVariableByteData...
       
   148 	&write8(\*OUTPUT_FILE, $endianness);
       
   149 	&write8(\*OUTPUT_FILE, length($replacementForUnconvertibleUnicodeCharacters));
       
   150 	&writeString(\*OUTPUT_FILE, $replacementForUnconvertibleUnicodeCharacters);
       
   151 	&writeBinaryForeignVariableByteData(\*OUTPUT_FILE, \@foreignVariableByteData);
       
   152 	#choose %unicodeCharacterCodes and write the data as keypair
       
   153 	my $key;
       
   154 	my $rangekey;
       
   155 	my $limit;
       
   156 	foreach $key (keys(%unicodeCharacterCodes))
       
   157 		{
       
   158 		&write16(\*OUTPUT_FILE,$key);
       
   159 		&write16(\*OUTPUT_FILE,$unicodeCharacterCodes{$key});
       
   160 		}
       
   161 	}
       
   162 else
       
   163 	{
       
   164 	binmode OUTPUT_FILE;
       
   165 	&writeBinaryHeader(\*OUTPUT_FILE, $uid, $endianness, $replacementForUnconvertibleUnicodeCharacters);
       
   166 	&writeBinaryForeignVariableByteData(\*OUTPUT_FILE, \@foreignVariableByteData);
       
   167 	&writeBinaryOneDirectionData(\*OUTPUT_FILE, \@foreignToUnicodeData, \%unicodeCharacterCodes, 1);
       
   168 	&writeBinaryOneDirectionData(\*OUTPUT_FILE, \@unicodeToForeignData, \%foreignCharacterCodes, 0);
       
   169 	}
       
   170 close(OUTPUT_FILE) or die("Error: could not close \"$outputFile\"\n");
       
   171 print("complete\n\n");
       
   172 
       
   173 sub extractCommandLineFlags()
       
   174 	{
       
   175 	my $generateSourceCode=shift;
       
   176 	my $columns=shift;
       
   177 	my $omitReplacementForUnconvertibleUnicodeCharacters=shift;
       
   178 	my $cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed=shift;
       
   179 	my $sourceFilesToSubtract=shift;
       
   180 	my $flattenHashAndSave=shift;
       
   181 	my $i;
       
   182 	for ($i=0; $i<=$#ARGV;) # (i) not cache-ing $#ARGV into a variable as @ARGV may change length in this loop (ii) iterate forwards as some parameters may occupy more than one element in @ARGV
       
   183 		{
       
   184 		if (($ARGV[$i]=~/^-s$/i) || ($ARGV[$i]=~/^-generateSourceCode$/i))
       
   185 			{
       
   186 			if ($$flattenHashAndSave==1)
       
   187 				{
       
   188 				die ("Error: Cannot have -s and -b flags set at the same time");
       
   189 				}
       
   190 			else
       
   191 				{
       
   192 				splice(@ARGV, $i, 1);
       
   193 				$$generateSourceCode=1;
       
   194 				}
       
   195 			}
       
   196 		elsif (($ARGV[$i]=~/^-c\b(.*)$/i) || ($ARGV[$i]=~/^-columns\b(.*)$/i))
       
   197 			{
       
   198 			my $columnsData=$1;
       
   199 			splice(@ARGV, $i, 1);
       
   200 			for (;;)
       
   201 				{
       
   202 				if ($columnsData=~/^\s*\(\s*(\d+)\s*:\s*(\d+)\s*\,?\s*(\d+)\s*\)\s*$/)
       
   203 					{
       
   204 					@$columns=($1, $2, $3);
       
   205 					last;
       
   206 					}
       
   207 				($#ARGV>=$i) or die("Error: bad \"-columns\" format\n");
       
   208 				$columnsData.=(splice(@ARGV, $i, 1))[0];
       
   209 				}
       
   210 			}
       
   211 		elsif (($ARGV[$i]=~/^-r$/i) || ($ARGV[$i]=~/^-omitReplacementForUnconvertibleUnicodeCharacters$/i))
       
   212 			{
       
   213 			splice(@ARGV, $i, 1);
       
   214 			$$omitReplacementForUnconvertibleUnicodeCharacters=1;
       
   215 			}
       
   216 		elsif (($ARGV[$i]=~/^-p$/i) || ($ARGV[$i]=~/^-cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed$/i))
       
   217 			{
       
   218 			splice(@ARGV, $i, 1);
       
   219 			$$cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed=1;
       
   220 			}
       
   221 		elsif (($ARGV[$i]=~/^-u\b(.*)$/i) || ($ARGV[$i]=~/^-sourceFilesToSubtract\b(.*)$/i))
       
   222 			{
       
   223 			my $sourceFilesData=$1;
       
   224 			splice(@ARGV, $i, 1);
       
   225 			for (;;)
       
   226 				{
       
   227 				if ($sourceFilesData=~/^\s*\(\s*(.+)\)\s*$/)
       
   228 					{
       
   229 					my $sourceFilesData=$1;
       
   230 					@$sourceFilesToSubtract=split(/,/, $sourceFilesData, -1);
       
   231 					my $j;
       
   232 					for ($j=$#$sourceFilesToSubtract; $j>=0; --$j)
       
   233 						{
       
   234 						$sourceFilesToSubtract->[$j]=~s/^\s+//;
       
   235 						$sourceFilesToSubtract->[$j]=~s/\s+$//;
       
   236 						($sourceFilesToSubtract->[$j] ne '') or die("Error: bad \"-sourceFilesToSubtract\" format (1)\n");
       
   237 						}
       
   238 					last;
       
   239 					}
       
   240 				($#ARGV>=$i) or die("Error: bad \"-sourceFilesToSubtract\" format (2)\n");
       
   241 				$sourceFilesData.=(splice(@ARGV, $i, 1))[0];
       
   242 				}
       
   243 			}
       
   244 		elsif (($ARGV[$i]=~/^-f$/i) || ($ARGV[$i]=~/^-flattenHashAndSave$/i))
       
   245 			{
       
   246 			if ($$generateSourceCode==1)
       
   247 				{
       
   248 				die ("Error: Cannot have -s and -b flags set at the same time");
       
   249 				}
       
   250 			else
       
   251 				{
       
   252 				splice(@ARGV, $i, 1);
       
   253 				$$flattenHashAndSave=1;
       
   254 				}
       
   255 			}
       
   256 		else
       
   257 			{
       
   258 			++$i;
       
   259 			}
       
   260 		}
       
   261 	}
       
   262 
       
   263 sub algorithm
       
   264 	{
       
   265 	my $algorithmAsText=shift;
       
   266 	if ($algorithmAsText=~/^Direct$/i)
       
   267 		{
       
   268 		return 0;
       
   269 		}
       
   270 	elsif ($algorithmAsText=~/^Offset$/i)
       
   271 		{
       
   272 		return 1;
       
   273 		}
       
   274 	elsif ($algorithmAsText=~/^IndexedTable16$/i)
       
   275 		{
       
   276 		return 2;
       
   277 		}
       
   278 	elsif ($algorithmAsText=~/^KeyedTable1616$/i)
       
   279 		{
       
   280 		return 3;
       
   281 		}
       
   282 	elsif ($algorithmAsText=~/^KeyedTable16OfIndexedTables16$/i)
       
   283 		{
       
   284 		return 4;
       
   285 		}
       
   286 	elsif ($algorithmAsText=~/^IndexedTable32$/i)
       
   287 		{
       
   288 		return 5;
       
   289 		}
       
   290 	elsif ($algorithmAsText=~/^KeyedTable3232$/i)
       
   291 		{
       
   292 		return 6;
       
   293 		}
       
   294 	elsif ($algorithmAsText=~/^KeyedTable32OfIndexedTables32$/i)
       
   295 		{
       
   296 		return 7;
       
   297 		}
       
   298 	else
       
   299 		{
       
   300 		return -1;
       
   301 		}
       
   302 	}
       
   303 
       
   304 sub hexadecimalify
       
   305 	{
       
   306 	my $string=shift;
       
   307 	my $result='';
       
   308 	my $lengthOfString=length($string);
       
   309 	my $i;
       
   310 	for ($i=0; $i<$lengthOfString; ++$i)
       
   311 		{
       
   312 		$result.=sprintf("\\x%02x", (unpack('C', substr($string, $i, 1)))[0]);
       
   313 		}
       
   314 	return $result;
       
   315 	}
       
   316 
       
   317 sub readSourceFile
       
   318 	{
       
   319 	my $fileHandle=shift;
       
   320 	my $fileName=shift;
       
   321 	my $foreignCharacterCodes=shift;
       
   322 	my $unicodeCharacterCodes=shift;
       
   323 	my $columns=shift;
       
   324 	my $cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed=shift;
       
   325 	my $privateUseUnicodeCharacterSlotsUsed=shift;
       
   326 	my $subtract=shift;
       
   327 	my $foreignCharacterCodeProcessingCode='';
       
   328 	if (!(($columns->[0]>0) && ($columns->[1]>0) && ($columns->[2]>0) && ($columns->[1]<=$columns->[0]) && ($columns->[2]<=$columns->[0]) && ($columns->[1]!=$columns->[2])))
       
   329 		{
       
   330 		close($fileHandle);
       
   331 		die("Error: bad \"-columns\" data\n");
       
   332 		}
       
   333 	my $patternOfLineContainingCharacterCodes=join('\s+', ('0x([0-9a-f]+)') x $columns->[0]);
       
   334 	my $line;
       
   335 	my $strippedDownLine;
       
   336 	for (;;)
       
   337 		{
       
   338 		($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   339 		if (($strippedDownLine eq '')||(substr($strippedDownLine,0,1) eq chr(26)))  # if there are no more lines in the file or if we encountered EOF character
       
   340 			{
       
   341 			last;
       
   342 			}
       
   343 		if ($strippedDownLine=~/^SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE\s+(.*)$/i)
       
   344 			{
       
   345 			$foreignCharacterCodeProcessingCode=$1;
       
   346 			}
       
   347 		elsif ($strippedDownLine=~/^$patternOfLineContainingCharacterCodes$/i)
       
   348 			{
       
   349 			no strict 'refs'; # so that we can use symbolic references for $1, $2, etc
       
   350 			my $foreignCharacterCode=hex(${$columns->[1]});
       
   351 			my $unicodeCharacterCode=hex(${$columns->[2]});
       
   352 			use strict 'refs';
       
   353 			if ($foreignCharacterCodeProcessingCode ne '')
       
   354 				{
       
   355 				$foreignCharacterCode=eval($foreignCharacterCodeProcessingCode);
       
   356 				}
       
   357 			my $handleConversionPair=1;
       
   358 			if ((($unicodeCharacterCode>=0xe000) && ($unicodeCharacterCode<=0xf8ff)) || (($unicodeCharacterCode>=0xf0000) && ($unicodeCharacterCode<=0x10ffff)))
       
   359 				{
       
   360 				if ($cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed)
       
   361 					{
       
   362 					$handleConversionPair=0;
       
   363 					}
       
   364 				else
       
   365 					{
       
   366 					if ($subtract)
       
   367 						{
       
   368 						delete $privateUseUnicodeCharacterSlotsUsed->{$unicodeCharacterCode};
       
   369 						}
       
   370 					else
       
   371 						{
       
   372 						$privateUseUnicodeCharacterSlotsUsed->{$unicodeCharacterCode}=1;
       
   373 						}
       
   374 					}
       
   375 				}
       
   376 			if ($handleConversionPair)
       
   377 				{
       
   378 				if ($subtract)
       
   379 					{
       
   380 					if (!defined($foreignCharacterCodes->{$unicodeCharacterCode}->{$foreignCharacterCode}))
       
   381 						{
       
   382 						close($fileHandle);
       
   383 						die('Error: cannot subtract conversion pair ['.sprintf('foreign 0x%x, Unicode 0x%04x', $foreignCharacterCode, $unicodeCharacterCode)."] as it does not occur in \"$fileName\"\n");
       
   384 						}
       
   385 					if (!defined($unicodeCharacterCodes->{$foreignCharacterCode}->{$unicodeCharacterCode}))
       
   386 						{
       
   387 						close($fileHandle);
       
   388 						die('Error: cannot subtract conversion pair ['.sprintf('Unicode 0x%04x, foreign 0x%x', $unicodeCharacterCode, $foreignCharacterCode)."] as it does not occur in \"$fileName\"\n");
       
   389 						}
       
   390 					delete $foreignCharacterCodes->{$unicodeCharacterCode}->{$foreignCharacterCode};
       
   391 					if (keys(%{$foreignCharacterCodes->{$unicodeCharacterCode}})==0)
       
   392 						{
       
   393 						delete $foreignCharacterCodes->{$unicodeCharacterCode};
       
   394 						}
       
   395 					delete $unicodeCharacterCodes->{$foreignCharacterCode}->{$unicodeCharacterCode};
       
   396 					if (keys(%{$unicodeCharacterCodes->{$foreignCharacterCode}})==0)
       
   397 						{
       
   398 						delete $unicodeCharacterCodes->{$foreignCharacterCode};
       
   399 						}
       
   400 					}
       
   401 				else
       
   402 					{
       
   403 					if (defined($foreignCharacterCodes->{$unicodeCharacterCode}->{$foreignCharacterCode}))
       
   404 						{
       
   405 						close($fileHandle);
       
   406 						die('Error: same conversion pair ['.sprintf('foreign 0x%x, Unicode 0x%04x', $foreignCharacterCode, $unicodeCharacterCode)."] occurs more than once in \"$fileName\"\n");
       
   407 						}
       
   408 					if (defined($unicodeCharacterCodes->{$foreignCharacterCode}->{$unicodeCharacterCode}))
       
   409 						{
       
   410 						close($fileHandle);
       
   411 						die('Error: same conversion pair ['.sprintf('Unicode 0x%04x, foreign 0x%x', $unicodeCharacterCode, $foreignCharacterCode)."] occurs more than once in \"$fileName\"\n");
       
   412 						}
       
   413 					$foreignCharacterCodes->{$unicodeCharacterCode}->{$foreignCharacterCode}=1;
       
   414 					$unicodeCharacterCodes->{$foreignCharacterCode}->{$unicodeCharacterCode}=1;
       
   415 					}
       
   416 				}
       
   417 			}
       
   418 		elsif ($line!~/^\s*0x([0-9a-f]+)\s*#\s*undefined.*$/i)
       
   419 			{
       
   420 			close($fileHandle);
       
   421 			die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   422 			}
       
   423 		}
       
   424 	}
       
   425 
       
   426 sub readHeaderFromControlFile
       
   427 	{
       
   428 	my $fileHandle=shift;
       
   429 	my $fileName=shift;
       
   430 	my $generateSourceCode=shift;
       
   431 	my $uid=shift;
       
   432 	my $endiannessAsText=shift;
       
   433 	my $endianness=shift;
       
   434 	my $replacementForUnconvertibleUnicodeCharacters=shift;
       
   435 	my $flattenHashAndSave=shift;
       
   436 	my $line;
       
   437 	my $strippedDownLine;
       
   438 	($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   439 	if ($strippedDownLine=~/^UID\s+0x([0-9a-f]+)$/i)
       
   440 		{
       
   441 		if ($generateSourceCode)
       
   442 			{
       
   443 			print(STDERR "Warning: \"UID\" keyword should not be used with \"-generateSourceCode\" flag - specify the UID in the MMP file\n");
       
   444 			}
       
   445 		$$uid=hex($1);
       
   446 		($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   447 		}
       
   448 	else
       
   449 		{
       
   450 		if (!$generateSourceCode && !$flattenHashAndSave)
       
   451 			{
       
   452 			close($fileHandle);
       
   453 			die("Error: unexpected line in \"$fileName\" (\"UID\" keyword expected):\n    $line\n");
       
   454 			}
       
   455 		}
       
   456 	if ($strippedDownLine=~/^Name\s+"(.+?)"$/i)
       
   457 		{
       
   458 		print(STDERR "Warning: obsolete keyword \"Name\" used\n");
       
   459 		($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   460 		}
       
   461 	if ($strippedDownLine!~/^Endianness\s+(\w+)$/i)
       
   462 		{
       
   463 		close($fileHandle);
       
   464 		die("Error: unexpected line in \"$fileName\" (\"Endianness\" keyword expected):\n    $line\n");
       
   465 		}
       
   466 	$$endiannessAsText=$1;
       
   467 	if ($$endiannessAsText=~/Unspecified/i)
       
   468 		{
       
   469 		$$endianness=0; # SCnvConversionData::EUnspecified
       
   470 		}
       
   471 	elsif ($$endiannessAsText=~/FixedLittleEndian/i)
       
   472 		{
       
   473 		$$endianness=1; # SCnvConversionData::EFixedLittleEndian
       
   474 		}
       
   475 	elsif ($$endiannessAsText=~/FixedBigEndian/i)
       
   476 		{
       
   477 		$$endianness=2; # SCnvConversionData::EFixedBigEndian
       
   478 		}
       
   479 	else
       
   480 		{
       
   481 		close($fileHandle);
       
   482 		die("Error: \"$$endiannessAsText\" is not a legal value for \"Endianness\"\n");
       
   483 		}
       
   484 	($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   485 	if ($strippedDownLine!~/^ReplacementForUnconvertibleUnicodeCharacters\s+(.*?)$/i)
       
   486 		{
       
   487 		close($fileHandle);
       
   488 		die("Error: unexpected line in \"$fileName\" (\"ReplacementForUnconvertibleUnicodeCharacters\" keyword expected):\n    $line\n");
       
   489 		}
       
   490 	$$replacementForUnconvertibleUnicodeCharacters='';
       
   491 	my $remainderOfXxx=$1;
       
   492 	while ($remainderOfXxx ne '')
       
   493 		{
       
   494 		if ($remainderOfXxx!~/^0x([0-9a-f]{1,2})\s*(.*)$/i)
       
   495 			{
       
   496 			close($fileHandle);
       
   497 			die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   498 			}
       
   499 		$$replacementForUnconvertibleUnicodeCharacters.=pack("C", hex($1));
       
   500 		$remainderOfXxx=$2;
       
   501 		}
       
   502 	my @temp=&nextNonEmptyStrippedDownLine($fileHandle);
       
   503 	if ($temp[1]=~/^ForeignCharacterCodeProcessingCode/i)
       
   504 		{
       
   505 		print(STDERR "Warning: obsolete keyword \"ForeignCharacterCodeProcessingCode\" used\n");
       
   506 		}
       
   507 	else
       
   508 		{
       
   509 		ungetNonEmptyStrippedDownLine(@temp)
       
   510 		}
       
   511 	}
       
   512 
       
   513 sub readForeignVariableByteDataFromControlFile
       
   514 	{
       
   515 	my $fileHandle=shift;
       
   516 	my $fileName=shift;
       
   517 	my $foreignVariableByteData=shift;
       
   518 	my $line;
       
   519 	my $strippedDownLine;
       
   520 	($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   521 	if ($strippedDownLine!~/^StartForeignVariableByteData$/i)
       
   522 		{
       
   523 		close($fileHandle);
       
   524 		die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   525 		}
       
   526 
       
   527 	for (;;)
       
   528 		{
       
   529 		($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   530 		if ($strippedDownLine=~/^EndForeignVariableByteData$/i)
       
   531 			{
       
   532 			last;
       
   533 			}
       
   534 		if ($strippedDownLine!~/^0x([0-9a-f]+)\s+0x([0-9a-f]+)\s+(\d+)$/i)
       
   535 			{
       
   536 			close($fileHandle);
       
   537 			die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   538 			}
       
   539 		my $firstInitialByteValueInRange=hex($1);
       
   540 		my $lastInitialByteValueInRange=hex($2);
       
   541 		my $numberOfSubsequentBytes=$3;
       
   542 		if ($firstInitialByteValueInRange>0xff)
       
   543 			{
       
   544 			close($fileHandle);
       
   545 			die("Error: firstInitialByteValueInRange ".sprintf("0x%02x", $firstInitialByteValueInRange)." does not fit in a single byte\n");
       
   546 			}
       
   547 		if ($lastInitialByteValueInRange>0xff)
       
   548 			{
       
   549 			close($fileHandle);
       
   550 			die("Error: lastInitialByteValueInRange ".sprintf("0x%02x", $lastInitialByteValueInRange)." does not fit in a single byte\n");
       
   551 			}
       
   552 		if ($lastInitialByteValueInRange<$firstInitialByteValueInRange)
       
   553 			{
       
   554 			close($fileHandle);
       
   555 			die("Error: lastInitialByteValueInRange ".sprintf("0x%02x", $lastInitialByteValueInRange)." is less than firstInitialByteValueInRange ".sprintf("0x%02x", $firstInitialByteValueInRange)."\n");
       
   556 			}
       
   557 		push(@$foreignVariableByteData, [$firstInitialByteValueInRange, $lastInitialByteValueInRange, $numberOfSubsequentBytes]);
       
   558 		}
       
   559 	}
       
   560 
       
   561 sub readOneDirectionDataFromControlFile
       
   562 	{
       
   563 	my $fileHandle=shift;
       
   564 	my $fileName=shift;
       
   565 	my $oneDirectionData=shift;
       
   566 	my $preferredCharacterCodesForConflictResolution=shift;
       
   567 	my $additionalSubsetTables=shift;
       
   568 	my $outputIsUnicode=shift;
       
   569 	my $source=$outputIsUnicode? 'foreign': 'Unicode';
       
   570 	my $target=$outputIsUnicode? 'Unicode': 'foreign';
       
   571 	my $middlePortionOfKeyWords=$outputIsUnicode? "ForeignToUnicode": "UnicodeToForeign";
       
   572 	my $extraPatternToMatch=$outputIsUnicode? '()': '\s+(\d+)';
       
   573 	my $line;
       
   574 	my $strippedDownLine;
       
   575 	($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   576 	if ($strippedDownLine!~/^Start${middlePortionOfKeyWords}Data$/i)
       
   577 		{
       
   578 		close($fileHandle);
       
   579 		die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   580 		}
       
   581 	my $doingConflictResolution=0;
       
   582 	for (;;)
       
   583 		{
       
   584 		($line, $strippedDownLine)=&nextNonEmptyStrippedDownLine($fileHandle);
       
   585 		if ($strippedDownLine=~/^End${middlePortionOfKeyWords}Data$/i)
       
   586 			{
       
   587 			last;
       
   588 			}
       
   589 		if ($strippedDownLine=~/^ConflictResolution$/i)
       
   590 			{
       
   591 			$doingConflictResolution=1;
       
   592 			}
       
   593 		elsif ($doingConflictResolution)
       
   594 			{
       
   595 			if ($strippedDownLine!~/^0x([0-9a-f]+)\s+0x([0-9a-f]+)$/i)
       
   596 				{
       
   597 				close($fileHandle);
       
   598 				die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   599 				}
       
   600 			my $sourceCharacterCodeToResolve=hex($1);
       
   601 			my $targetCharacterCodePreferred=hex($2);
       
   602 			$preferredCharacterCodesForConflictResolution->{$sourceCharacterCodeToResolve}=$targetCharacterCodePreferred;
       
   603 			}
       
   604 		elsif ($strippedDownLine=~/^(Start|End)AdditionalSubsetTable\s+(.*)$/i)
       
   605 			{
       
   606 			my $prefix=$1;
       
   607 			my $nameOfAdditionalSubsetTable=$2;
       
   608 			my $index=$prefix=~(/^Start$/i)? 0: 1;
       
   609 			if (!$outputIsUnicode)
       
   610 				{
       
   611 				$index+=2;
       
   612 				}
       
   613 			if (defined($additionalSubsetTables{$nameOfAdditionalSubsetTable}->[$index]))
       
   614 				{
       
   615 				close($fileHandle);
       
   616 				die("Error: multiple redefinition of \"${prefix}AdditionalSubsetTable $nameOfAdditionalSubsetTable\"\n");
       
   617 				}
       
   618 			$additionalSubsetTables{$nameOfAdditionalSubsetTable}->[$index]=@$oneDirectionData;
       
   619 			}
       
   620 		else
       
   621 			{
       
   622 			if ($strippedDownLine!~/^(\d+)\s+(\d+)\s+0x([0-9a-f]+)\s+0x([0-9a-f]+)\s+(\w+)$extraPatternToMatch\s+\{(.*?)\}$/i)
       
   623 				{
       
   624 				close($fileHandle);
       
   625 				die("Error: unexpected line in \"$fileName\":\n    $line\n");
       
   626 				}
       
   627 			my $includePriority=$1;
       
   628 			my $searchPriority=$2;
       
   629 			my $firstInputCharacterCodeInRange=hex($3);
       
   630 			my $lastInputCharacterCodeInRange=hex($4);
       
   631 			my $algorithmAsText=$5;
       
   632 			my $sizeOfOutputCharacterCodeInBytes=$6;
       
   633 			my $parameters=$7;
       
   634 			if ($lastInputCharacterCodeInRange<$firstInputCharacterCodeInRange)
       
   635 				{
       
   636 				close($fileHandle);
       
   637 				die("Error: lastInputCharacterCodeInRange ".sprintf("0x%02x", $lastInputCharacterCodeInRange)." is less than firstInputCharacterCodeInRange ".sprintf("0x%02x", $firstInputCharacterCodeInRange)."\n");
       
   638 				}
       
   639 			my $algorithm=&algorithm($algorithmAsText);
       
   640 			if ($algorithm<0)
       
   641 				{
       
   642 				close($fileHandle);
       
   643 				die("Error: unexpected algorithm \"$algorithmAsText\"\n");
       
   644 				}
       
   645 			my $rangeData=[$includePriority, $searchPriority, $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange, $algorithm];
       
   646 			if (!$outputIsUnicode)
       
   647 				{
       
   648 				push(@$rangeData, $sizeOfOutputCharacterCodeInBytes);
       
   649 				}
       
   650 			push(@$rangeData, $parameters);
       
   651 			push(@$oneDirectionData, $rangeData);
       
   652 			}
       
   653 		}
       
   654 	}
       
   655 
       
   656 sub warnIfAnyPrivateUseUnicodeCharacterSlotsBeingUsed
       
   657 	{
       
   658 	my $privateUseUnicodeCharacterSlotsUsed=shift;
       
   659 	my @sortedPrivateUseUnicodeCharacterSlotsUsed=sort({$a<=>$b} keys(%$privateUseUnicodeCharacterSlotsUsed));
       
   660 	if (@sortedPrivateUseUnicodeCharacterSlotsUsed>0)
       
   661 		{
       
   662 		my $lastPrivateUseUnicodeCharacterSlotUsed=$sortedPrivateUseUnicodeCharacterSlotsUsed[0];
       
   663 		my $asText=sprintf('0x%04x', $lastPrivateUseUnicodeCharacterSlotUsed);
       
   664 		my @asText=($asText);
       
   665 		my $i;
       
   666 		for ($i=1; $i<@sortedPrivateUseUnicodeCharacterSlotsUsed; ++$i) # this loop starts from 1 not 0 as we have already dealt with $sortedPrivateUseUnicodeCharacterSlotsUsed[0]
       
   667 			{
       
   668 			($sortedPrivateUseUnicodeCharacterSlotsUsed[$i]>$lastPrivateUseUnicodeCharacterSlotUsed) or die("Error: internal error 1\n");
       
   669 			if ($sortedPrivateUseUnicodeCharacterSlotsUsed[$i]>$lastPrivateUseUnicodeCharacterSlotUsed+1)
       
   670 				{
       
   671 				$asText=sprintf('0x%04x', $lastPrivateUseUnicodeCharacterSlotUsed);
       
   672 				if ($asText[-1] ne $asText)
       
   673 					{
       
   674 					$asText[-1].='-'.$asText;
       
   675 					}
       
   676 				push(@asText, sprintf('0x%04x', $sortedPrivateUseUnicodeCharacterSlotsUsed[$i]));
       
   677 				}
       
   678 			$lastPrivateUseUnicodeCharacterSlotUsed=$sortedPrivateUseUnicodeCharacterSlotsUsed[$i];
       
   679 			}
       
   680 		$asText=sprintf('0x%04x', $lastPrivateUseUnicodeCharacterSlotUsed);
       
   681 		if ($asText[-1] ne $asText)
       
   682 			{
       
   683 			$asText[-1].='-'.$asText;
       
   684 			}
       
   685 		print(STDERR 'Warning: the following private-use Unicode character slots were used: ['.join(', ', @asText)."]\n");
       
   686 		}
       
   687 	}
       
   688 
       
   689 sub resolveConflictsAndFlattenArraysToScalars
       
   690 	{
       
   691 	my $characterCodes=shift;
       
   692 	my $preferredCharacterCodesForConflictResolution=shift;
       
   693 	my $source=shift;
       
   694 	my $target=shift;
       
   695 	my $sourceCharacterCode;
       
   696 	my $candidateTargetCharacterCodes;
       
   697 	while (($sourceCharacterCode, $candidateTargetCharacterCodes)=each(%$characterCodes))
       
   698 		{
       
   699 		my @candidateTargetCharacterCodes=keys(%$candidateTargetCharacterCodes);
       
   700 		if (@candidateTargetCharacterCodes<1)
       
   701 			{
       
   702 			die("Error: internal error 2\n");
       
   703 			}
       
   704 		if (@candidateTargetCharacterCodes==1)
       
   705 			{
       
   706 			$characterCodes->{$sourceCharacterCode}=$candidateTargetCharacterCodes[0];
       
   707 			}
       
   708 		else
       
   709 			{
       
   710 			if (!defined($preferredCharacterCodesForConflictResolution->{$sourceCharacterCode}))
       
   711 				{
       
   712 				die("Error: no preferred $target character code is specified for conflict resolution for the $source character code ".sprintf("0x%08x", $sourceCharacterCode)."\n");
       
   713 				}
       
   714 			my $preferredCharacterCodeIsNotACandidateForConflictResolution=1;
       
   715 			my $candidateTargetCharacterCode;
       
   716 			foreach $candidateTargetCharacterCode (@candidateTargetCharacterCodes)
       
   717 				{
       
   718 				if ($preferredCharacterCodesForConflictResolution->{$sourceCharacterCode}==$candidateTargetCharacterCode)
       
   719 					{
       
   720 					$preferredCharacterCodeIsNotACandidateForConflictResolution=0;
       
   721 					last;
       
   722 					}
       
   723 				}
       
   724 			if ($preferredCharacterCodeIsNotACandidateForConflictResolution)
       
   725 				{
       
   726 				die("Error: the preferred $target character code ".sprintf("0x%08x", $preferredCharacterCodesForConflictResolution->{$sourceCharacterCode})." is not a candidate for conflict resolution for the $source character code ".sprintf("0x%08x", $sourceCharacterCode)."\n");
       
   727 				}
       
   728 			$characterCodes->{$sourceCharacterCode}=$preferredCharacterCodesForConflictResolution->{$sourceCharacterCode};
       
   729 			delete $preferredCharacterCodesForConflictResolution->{$sourceCharacterCode};
       
   730 			}
       
   731 		}
       
   732 	my $numberOfPreferredCharacterCodesForConflictResolution=keys(%$preferredCharacterCodesForConflictResolution);
       
   733 	if ($numberOfPreferredCharacterCodesForConflictResolution!=0)
       
   734 		{
       
   735 		print(STDERR "Warning: there are $numberOfPreferredCharacterCodesForConflictResolution $target preferred character codes specified for which there are no conflicts to resolve\n");
       
   736 		}
       
   737 	}
       
   738 
       
   739 sub checkForeignVariableByteData
       
   740 	{
       
   741 	my $endianness=shift;
       
   742 	my $foreignVariableByteData=shift;
       
   743 	my $foreignToUnicodeData=shift;
       
   744 	my $rangeData;
       
   745 	my %initialForeignBytes=();
       
   746 	foreach $rangeData (@$foreignVariableByteData)
       
   747 		{
       
   748 		my $initialByte;
       
   749 		for ($initialByte=$rangeData->[0]; $initialByte<=$rangeData->[1]; ++$initialByte)
       
   750 			{
       
   751 			if (defined($initialForeignBytes{$initialByte}))
       
   752 				{
       
   753 				die("Error: the number of bytes subsequent to the initial foreign-byte $initialForeignBytes{$initialByte} is defined more than once\n");
       
   754 				}
       
   755 			$initialForeignBytes{$initialByte}=1;
       
   756 			}
       
   757 		}
       
   758 #	if ($endianness!=0) # unfortunately, nothing can be checked if the $endianness is 0 (SCnvConversionData::EUnspecified)
       
   759 #		{
       
   760 #		foreach $rangeData (@$foreignToUnicodeData)
       
   761 #			{
       
   762 #			my $inputCharacterCode;
       
   763 #			for ($inputCharacterCode=$rangeData->[2]; $inputCharacterCode<=$rangeData->[3]; ++$inputCharacterCode)
       
   764 #				{
       
   765 #				my $initialByte;
       
   766 #				if ($endianness==1) # SCnvConversionData::EFixedLittleEndian
       
   767 #					{
       
   768 #					$initialByte=($inputCharacterCode&0xff);
       
   769 #					}
       
   770 #				elsif ($endianness==2) # SCnvConversionData::EFixedBigEndian
       
   771 #					{
       
   772 #					$initialByte=($inputCharacterCode&0xff00)>>8; ## this is hard-coded and needs to be done properly!
       
   773 #					}
       
   774 #				else
       
   775 #					{
       
   776 #					die("Error: internal error ??\n");
       
   777 #					}
       
   778 #				if (!defined($initialForeignBytes{$initialByte}))
       
   779 #					{
       
   780 #					die("Error: no number-of-subsequent-bytes is specified for the initial byte $initialByte\n");
       
   781 #					}
       
   782 #				}
       
   783 #			}
       
   784 #		}
       
   785 	}
       
   786 
       
   787 sub writeSourceCodeHeader
       
   788 	{
       
   789 	my $fileHandle=shift;
       
   790 	my $fileName=shift;
       
   791 	my $replacementForUnconvertibleUnicodeCharacters=shift;
       
   792 	while ($fileName=~/^.*\\(.*)$/i)
       
   793 		{
       
   794 		$fileName=$1;
       
   795 		}
       
   796 	print($fileHandle "// $fileName\n//\n// Copyright (c) Nokia Corporation and/or its subsidiary(-ies) ".(1900+(gmtime(time))[5]).". All rights reserved.\n//\n\n");
       
   797 	print($fileHandle "#include <e32std.h>\n#include <convdata.h>\n#include <convgeneratedcpp.h>\n\n#define ARRAY_LENGTH(aArray) (sizeof(aArray)/sizeof((aArray)\[0\]))\n\n#pragma warning (disable: 4049) // compiler limit : terminating line number emission\n\n");
       
   798 	if (!$omitReplacementForUnconvertibleUnicodeCharacters)
       
   799 		{
       
   800 		print($fileHandle "_LIT8(KLit8ReplacementForUnconvertibleUnicodeCharacters, \"".&hexadecimalify($replacementForUnconvertibleUnicodeCharacters)."\");\n\n");
       
   801 		print($fileHandle "GLDEF_C const TDesC8& ReplacementForUnconvertibleUnicodeCharacters_internal()\n\t{\n\treturn KLit8ReplacementForUnconvertibleUnicodeCharacters;\n\t}\n\n");
       
   802 		}
       
   803 	}
       
   804 
       
   805 sub writeSourceCodeForeignVariableByteData
       
   806 	{
       
   807 	my $sourceCodeOfTopLevelStructures=shift;
       
   808 	my $foreignVariableByteData=shift;
       
   809 	push(@$sourceCodeOfTopLevelStructures, "LOCAL_D const SCnvConversionData::SVariableByteData::SRange foreignVariableByteDataRanges[]=\n\t\{\n");
       
   810 	my $indexOfLastRange=$#$foreignVariableByteData;
       
   811 	my $i;
       
   812 	for ($i=0; $i<=$indexOfLastRange; ++$i)
       
   813 		{
       
   814 		my $rangeData=$foreignVariableByteData->[$i];
       
   815 		if (@$rangeData!=3)
       
   816 			{
       
   817 			die("Error: internal error 3\n");
       
   818 			}
       
   819 		my $firstInitialByteValueInRange=$rangeData->[0];
       
   820 		my $lastInitialByteValueInRange=$rangeData->[1];
       
   821 		if ($lastInitialByteValueInRange<$firstInitialByteValueInRange)
       
   822 			{
       
   823 			die("Error: internal error 4\n");
       
   824 			}
       
   825 		my $numberOfSubsequentBytes=$rangeData->[2];
       
   826 		push(@$sourceCodeOfTopLevelStructures, "\t\t\{\n\t\t".sprintf("0x%02x", $firstInitialByteValueInRange).",\n\t\t".sprintf("0x%02x", $lastInitialByteValueInRange).",\n\t\t$numberOfSubsequentBytes,\n\t\t0\n\t\t\}");
       
   827 		if ($i<$indexOfLastRange)
       
   828 			{
       
   829 			push(@$sourceCodeOfTopLevelStructures, ',');
       
   830 			}
       
   831 		push(@$sourceCodeOfTopLevelStructures, "\n");
       
   832 		}
       
   833 	push(@$sourceCodeOfTopLevelStructures, "\t\};\n\n");
       
   834 	}
       
   835 
       
   836 sub writeSourceCodeOneDirectionData
       
   837 	{
       
   838 	my $sourceCodeOfTopLevelStructures=shift;
       
   839 	my $sourceCodeOfOneDirectionIndexedTables16=shift;
       
   840 	my $sourceCodeOfOneDirectionKeyedTables1616=shift;
       
   841 	my $sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_indexedEntries=shift;
       
   842 	my $sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_keyedEntries=shift;
       
   843 	# new for 32 bit encoding begin
       
   844 	my $sourceCodeOfOneDirectionIndexedTables32=shift;
       
   845 	my $sourceCodeOfOneDirectionKeyedTables3232=shift;
       
   846 	my $sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_indexedEntries=shift;
       
   847 	my $sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_keyedEntries=shift;
       
   848 	# new for 32 bit encoding end
       
   849 	
       
   850 	my $oneDirectionData=shift;
       
   851 	my $characterCodes=shift;
       
   852 	my $outputIsUnicode=shift;
       
   853 	push(@$sourceCodeOfTopLevelStructures, 'LOCAL_D const SCnvConversionData::SOneDirectionData::SRange '.($outputIsUnicode? 'foreignToUnicodeDataRanges': 'unicodeToForeignDataRanges')."[]=\n\t\{\n");
       
   854 	my $formatForInputCharacters=$outputIsUnicode? '0x%02x': '0x%04x';
       
   855 	my $formatForOutputCharacters=$outputIsUnicode? '0x%04x': '0x%02x';
       
   856 	my $indexOfLastRange=$#$oneDirectionData;
       
   857 	my $i;
       
   858 	for ($i=0; $i<=$indexOfLastRange; ++$i)
       
   859 		{
       
   860 		my $rangeData=$oneDirectionData->[$i];
       
   861 		# $rangeData is $includePriority, $searchPriority, $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange, $algorithm[, $sizeOfOutputCharacterCodeInBytes], $parameters
       
   862 		if (scalar(@$rangeData)!=($outputIsUnicode? 6: 7))
       
   863 			{
       
   864 			die("Error: internal error 5\n");
       
   865 			}
       
   866 		my $firstInputCharacterCodeInRange=$rangeData->[2];
       
   867 		my $lastInputCharacterCodeInRange=$rangeData->[3];
       
   868 		if ($lastInputCharacterCodeInRange<$firstInputCharacterCodeInRange)
       
   869 			{
       
   870 			die("Error: internal error 6\n");
       
   871 			}
       
   872 		my $algorithmAsText=''; # set by the if-elsif stuff below
       
   873 		my $sizeOfOutputCharacterCodeInBytesIfForeign=$outputIsUnicode? 0: $rangeData->[5];
       
   874 		my $parameters=$rangeData->[$outputIsUnicode? 5: 6];
       
   875 		my $word1=0; # set by the if-elsif stuff below
       
   876 		my $algorithm=$rangeData->[4];
       
   877 		if ($algorithm==0) # Direct
       
   878 			{
       
   879 			$algorithmAsText='Direct';
       
   880 			my $characterCode;
       
   881 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
   882 				{
       
   883 				if (!defined($characterCodes->{$characterCode}))
       
   884 					{
       
   885 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)."\n");
       
   886 					}
       
   887 				if ($characterCodes->{$characterCode}!=$characterCode)
       
   888 					{
       
   889 					die("Error: the conversion from ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)." to ".($outputIsUnicode? 'Unicode': 'foreign')." character code ".sprintf("0x%08x", $characterCodes->{$characterCode})." is not a direct conversion\n");
       
   890 					}
       
   891 				delete $characterCodes->{$characterCode};
       
   892 				}
       
   893 			}
       
   894 		elsif ($algorithm==1) # Offset
       
   895 			{
       
   896 			$algorithmAsText='Offset';
       
   897 			my $offset=$characterCodes->{$firstInputCharacterCodeInRange}-$firstInputCharacterCodeInRange;
       
   898 			delete $characterCodes->{$firstInputCharacterCodeInRange};
       
   899 			my $characterCode;
       
   900 			for ($characterCode=$firstInputCharacterCodeInRange+1; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
   901 				{
       
   902 				if (!defined($characterCodes->{$characterCode}))
       
   903 					{
       
   904 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x (0x%08x-0x%08x)", $characterCode, $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange)."\n");
       
   905 					}
       
   906 				if ($characterCodes->{$characterCode}-$characterCode!=$offset)
       
   907 					{
       
   908 					die("Error: the conversion from ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)." to ".($outputIsUnicode? 'Unicode': 'foreign')." character code ".sprintf("0x%08x", $characterCodes->{$characterCode})." has a different offset from the previous one in the range\n");
       
   909 					}
       
   910 				delete $characterCodes->{$characterCode};
       
   911 				}
       
   912 			$word1="STATIC_CAST(TUint, $offset)";
       
   913 			}
       
   914 		elsif ($algorithm==2) # IndexedTable16
       
   915 			{
       
   916 			$algorithmAsText='IndexedTable16';
       
   917 			my $nameOfNextOneDirectionIndexedTable16='indexedTable16_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionIndexedTables16+2);
       
   918 			my $sourceCodeOfNextOneDirectionIndexedTable16=[];
       
   919 			push(@$sourceCodeOfNextOneDirectionIndexedTable16, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable16::SEntry $nameOfNextOneDirectionIndexedTable16\[\]=\n\t\{\n");
       
   920 			my $characterCode;
       
   921 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
   922 				{
       
   923 				if (!defined($characterCodes->{$characterCode}))
       
   924 					{
       
   925 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)."\n");
       
   926 					}
       
   927 				push(@$sourceCodeOfNextOneDirectionIndexedTable16, "\t\t\{\n\t\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode})."\n\t\t\}");
       
   928 				if ($characterCode<$lastInputCharacterCodeInRange)
       
   929 					{
       
   930 					push(@$sourceCodeOfNextOneDirectionIndexedTable16, ',');
       
   931 					}
       
   932 				push(@$sourceCodeOfNextOneDirectionIndexedTable16, "\n");
       
   933 				delete $characterCodes->{$characterCode};
       
   934 				}
       
   935 			push(@$sourceCodeOfNextOneDirectionIndexedTable16, "\t\};\n\n");
       
   936 			push(@$sourceCodeOfOneDirectionIndexedTables16, $sourceCodeOfNextOneDirectionIndexedTable16);
       
   937 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionIndexedTable16)";
       
   938 			}
       
   939 		elsif ($algorithm==3) # KeyedTable1616
       
   940 			{
       
   941 			$algorithmAsText='KeyedTable1616';
       
   942 			my $nameOfNextOneDirectionKeyedTable1616='keyedTable1616_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables1616+2);
       
   943 			my $sourceCodeOfNextOneDirectionKeyedTable1616=[];
       
   944 			push(@$sourceCodeOfNextOneDirectionKeyedTable1616, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616::SEntry $nameOfNextOneDirectionKeyedTable1616\[\]=\n\t\{\n");
       
   945 			my @characterCodes=grep(($_>=$firstInputCharacterCodeInRange) && ($_<=$lastInputCharacterCodeInRange), sort({$a<=>$b} keys(%$characterCodes)));
       
   946 			if (@characterCodes==0)
       
   947 				{
       
   948 				die("Error: There are no ".($outputIsUnicode? 'foreign': 'Unicode').'-to-'.($outputIsUnicode? 'Unicode': 'foreign')." characters to convert using KeyedTable1616 (range ".sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).").\n");
       
   949 				}
       
   950 			if ($characterCodes[0]!=$firstInputCharacterCodeInRange)
       
   951 				{
       
   952 				print(STDERR 'Warning: the specified start of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[0])."\n");
       
   953 				}
       
   954 			if ($characterCodes[-1]!=$lastInputCharacterCodeInRange)
       
   955 				{
       
   956 				print(STDERR 'Warning: the specified end of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[-1])."\n");
       
   957 				}
       
   958 			my $characterCode;
       
   959 			foreach $characterCode (@characterCodes)
       
   960 				{
       
   961 				if (defined($characterCodes->{$characterCode}))
       
   962 					{
       
   963 					push(@$sourceCodeOfNextOneDirectionKeyedTable1616, "\t\t\{\n\t\t".sprintf($formatForInputCharacters, $characterCode).",\n\t\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode})."\n\t\t\}");
       
   964 					if ($characterCode<$characterCodes[-1])
       
   965 						{
       
   966 						push(@$sourceCodeOfNextOneDirectionKeyedTable1616, ',');
       
   967 						}
       
   968 					push(@$sourceCodeOfNextOneDirectionKeyedTable1616, "\n");
       
   969 					delete $characterCodes->{$characterCode};
       
   970 					}
       
   971 				}
       
   972 			push(@$sourceCodeOfNextOneDirectionKeyedTable1616, "\t\};\n\n");
       
   973 			push(@$sourceCodeOfOneDirectionKeyedTables1616, $sourceCodeOfNextOneDirectionKeyedTable1616);
       
   974 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionKeyedTable1616)";
       
   975 			}
       
   976 		elsif ($algorithm==4) # KeyedTable16OfIndexedTables16
       
   977 			{
       
   978 			$algorithmAsText='KeyedTable16OfIndexedTables16';
       
   979 			my $nameOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries='keyedTables16OfIndexedTables16_keyedEntries_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_keyedEntries+2);
       
   980 			my $sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries=[];
       
   981 			push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry $nameOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries\[\]=\n\t\{\n");
       
   982 			my @characterCodes=grep(($_>=$firstInputCharacterCodeInRange) && ($_<=$lastInputCharacterCodeInRange), sort({$a<=>$b} keys(%$characterCodes)));
       
   983 			if (@characterCodes==0)
       
   984 				{
       
   985 				die("Error: There are no ".($outputIsUnicode? 'foreign': 'Unicode').'-to-'.($outputIsUnicode? 'Unicode': 'foreign')." characters to convert using KeyedTable16OfIndexedTables16 (range ".sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).").\n");
       
   986 				}
       
   987 			if ($characterCodes[0]!=$firstInputCharacterCodeInRange)
       
   988 				{
       
   989 				print(STDERR 'Warning: the specified start of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[0])."\n");
       
   990 				}
       
   991 			if ($characterCodes[-1]!=$lastInputCharacterCodeInRange)
       
   992 				{
       
   993 				print(STDERR 'Warning: the specified end of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[-1])."\n");
       
   994 				}
       
   995 			my @characterCodeRanges=();
       
   996 			my $minimumNumberOfEntriesPerIndexedTable=($parameters ne '')? $parameters: 0;
       
   997 			my $firstInputCharacterCodeInIndexedTable=$characterCodes[0];
       
   998 			my $previousCharacterCode=$firstInputCharacterCodeInIndexedTable;
       
   999 			my $characterCode;
       
  1000 			foreach $characterCode (@characterCodes)
       
  1001 				{
       
  1002 				($characterCode>=$previousCharacterCode) or die("Error: internal error 7\n");
       
  1003 				if ($characterCode>$previousCharacterCode+1)
       
  1004 					{
       
  1005 					if (($previousCharacterCode-$firstInputCharacterCodeInIndexedTable)+1>=$minimumNumberOfEntriesPerIndexedTable)
       
  1006 						{
       
  1007 						push(@characterCodeRanges, [$firstInputCharacterCodeInIndexedTable, $previousCharacterCode]);
       
  1008 						}
       
  1009 					$firstInputCharacterCodeInIndexedTable=$characterCode;
       
  1010 					}
       
  1011 				$previousCharacterCode=$characterCode;
       
  1012 				}
       
  1013 			push(@characterCodeRanges, [$firstInputCharacterCodeInIndexedTable, $previousCharacterCode]);
       
  1014 			@characterCodes=();
       
  1015 			my $characterCodeRange;
       
  1016 			foreach $characterCodeRange (@characterCodeRanges)
       
  1017 				{
       
  1018 				my $nameOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries='keyedTables16OfIndexedTables16_indexedEntries_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_indexedEntries+2);
       
  1019 				my $sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries=[];
       
  1020 				push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, "LOCAL_D const TUint16 $nameOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries\[\]=\n\t\{\n");
       
  1021 				my $characterCode;
       
  1022 				my $lastInputCharacterCodeInIndexedTable=$characterCodeRange->[1];
       
  1023 				for ($characterCode=$characterCodeRange->[0]; $characterCode<=$lastInputCharacterCodeInIndexedTable; ++$characterCode)
       
  1024 					{
       
  1025 					if (!defined($characterCodes->{$characterCode}))
       
  1026 						{
       
  1027 						die("Error: internal error 8\n");
       
  1028 						}
       
  1029 					push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, "\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode}));
       
  1030 					if ($characterCode<$lastInputCharacterCodeInIndexedTable)
       
  1031 						{
       
  1032 						push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, ',');
       
  1033 						}
       
  1034 					push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, "\n");
       
  1035 					delete $characterCodes->{$characterCode};
       
  1036 					}
       
  1037 				push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, "\t\};\n\n");
       
  1038 				push(@$sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_indexedEntries, $sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries);
       
  1039 				push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, "\t\t\{\n\t\t".sprintf($formatForInputCharacters, $characterCodeRange->[0]).",\n\t\t".sprintf($formatForInputCharacters, $characterCodeRange->[1]).",\n\t\t$nameOfNextOneDirectionKeyedTables16OfIndexedTables16_indexedEntries\n\t\t\}");
       
  1040 				if ($characterCodeRange->[1]<$characterCodeRanges[-1]->[1])
       
  1041 					{
       
  1042 					push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, ',');
       
  1043 					}
       
  1044 				push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, "\n");
       
  1045 				}
       
  1046 			push(@$sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, "\t\};\n\n");
       
  1047 			push(@$sourceCodeOfOneDirectionKeyedTables16OfIndexedTables16_keyedEntries, $sourceCodeOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries);
       
  1048 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionKeyedTables16OfIndexedTables16_keyedEntries)";
       
  1049 			}
       
  1050 		elsif ($algorithm==5) # IndexedTable32
       
  1051 			{
       
  1052 			$algorithmAsText='IndexedTable32';
       
  1053 			my $nameOfNextOneDirectionIndexedTable32='indexedTable32_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionIndexedTables32+2);
       
  1054 			my $sourceCodeOfNextOneDirectionIndexedTable32=[];
       
  1055 			push(@$sourceCodeOfNextOneDirectionIndexedTable32, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable32::SEntry $nameOfNextOneDirectionIndexedTable32\[\]=\n\t\{\n");
       
  1056 			my $characterCode;
       
  1057 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
  1058 				{
       
  1059 				if (!defined($characterCodes->{$characterCode}))
       
  1060 					{
       
  1061 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)."\n");
       
  1062 					}
       
  1063 				push(@$sourceCodeOfNextOneDirectionIndexedTable32, "\t\t\{\n\t\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode})."\n\t\t\}");
       
  1064 				if ($characterCode<$lastInputCharacterCodeInRange)
       
  1065 					{
       
  1066 					push(@$sourceCodeOfNextOneDirectionIndexedTable32, ',');
       
  1067 					}
       
  1068 				push(@$sourceCodeOfNextOneDirectionIndexedTable32, "\n");
       
  1069 				delete $characterCodes->{$characterCode};
       
  1070 				}
       
  1071 			push(@$sourceCodeOfNextOneDirectionIndexedTable32, "\t\};\n\n");
       
  1072 			push(@$sourceCodeOfOneDirectionIndexedTables32, $sourceCodeOfNextOneDirectionIndexedTable32);
       
  1073 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionIndexedTable32)";
       
  1074 			}
       
  1075 		elsif ($algorithm==6) # KeyedTable3232
       
  1076 			{
       
  1077 			$algorithmAsText='KeyedTable3232';
       
  1078 			my $nameOfNextOneDirectionKeyedTable3232='keyedTable3232_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables3232+2);
       
  1079 			my $sourceCodeOfNextOneDirectionKeyedTable3232=[];
       
  1080 			push(@$sourceCodeOfNextOneDirectionKeyedTable3232, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable3232::SEntry $nameOfNextOneDirectionKeyedTable3232\[\]=\n\t\{\n");
       
  1081 			my @characterCodes=grep(($_>=$firstInputCharacterCodeInRange) && ($_<=$lastInputCharacterCodeInRange), sort({$a<=>$b} keys(%$characterCodes)));
       
  1082 			if (@characterCodes==0)
       
  1083 				{
       
  1084 				die("Error: There are no ".($outputIsUnicode? 'foreign': 'Unicode').'-to-'.($outputIsUnicode? 'Unicode': 'foreign')." characters to convert using KeyedTable3232 (range ".sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).").\n");
       
  1085 				}
       
  1086 			if ($characterCodes[0]!=$firstInputCharacterCodeInRange)
       
  1087 				{
       
  1088 				print(STDERR 'Warning: the specified start of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf($formatForInputCharacters, $characterCodes[0])."\n");
       
  1089 				}
       
  1090 			if ($characterCodes[-1]!=$lastInputCharacterCodeInRange)
       
  1091 				{
       
  1092 				print(STDERR 'Warning: the specified end of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf($formatForInputCharacters, $characterCodes[-1])."\n");
       
  1093 				}
       
  1094 			my $characterCode;
       
  1095 			foreach $characterCode (@characterCodes)
       
  1096 				{
       
  1097 				if (defined($characterCodes->{$characterCode}))
       
  1098 					{
       
  1099 					push(@$sourceCodeOfNextOneDirectionKeyedTable3232, "\t\t\{\n\t\t".sprintf($formatForInputCharacters, $characterCode).",\n\t\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode})."\n\t\t\}");
       
  1100 					if ($characterCode<$characterCodes[-1])
       
  1101 						{
       
  1102 						push(@$sourceCodeOfNextOneDirectionKeyedTable3232, ',');
       
  1103 						}
       
  1104 					push(@$sourceCodeOfNextOneDirectionKeyedTable3232, "\n");
       
  1105 					delete $characterCodes->{$characterCode};
       
  1106 					}
       
  1107 				}
       
  1108 			push(@$sourceCodeOfNextOneDirectionKeyedTable3232, "\t\};\n\n");
       
  1109 			push(@$sourceCodeOfOneDirectionKeyedTables3232, $sourceCodeOfNextOneDirectionKeyedTable3232);
       
  1110 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionKeyedTable3232)";
       
  1111 			}
       
  1112 		elsif ($algorithm==7) # KeyedTable32OfIndexedTables32
       
  1113 			{
       
  1114 			$algorithmAsText='KeyedTable32OfIndexedTables32';
       
  1115 			my $nameOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries='keyedTables32OfIndexedTables32_keyedEntries_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_keyedEntries+2);
       
  1116 			my $sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries=[];
       
  1117 			push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, "LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable32OfIndexedTables32::SKeyedEntry $nameOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries\[\]=\n\t\{\n");
       
  1118 			my @characterCodes=grep(($_>=$firstInputCharacterCodeInRange) && ($_<=$lastInputCharacterCodeInRange), sort({$a<=>$b} keys(%$characterCodes)));
       
  1119 			if (@characterCodes==0)
       
  1120 				{
       
  1121 				die("Error: There are no ".($outputIsUnicode? 'foreign': 'Unicode').'-to-'.($outputIsUnicode? 'Unicode': 'foreign')." characters to convert using KeyedTable32OfIndexedTables32 (range ".sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).").\n");
       
  1122 				}
       
  1123 			if ($characterCodes[0]!=$firstInputCharacterCodeInRange)
       
  1124 				{
       
  1125 				print(STDERR 'Warning: the specified start of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[0])."\n");
       
  1126 				}
       
  1127 			if ($characterCodes[-1]!=$lastInputCharacterCodeInRange)
       
  1128 				{
       
  1129 				print(STDERR 'Warning: the specified end of the '.($outputIsUnicode? 'foreign': 'Unicode').' range '.sprintf("$formatForInputCharacters-$formatForInputCharacters", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange).' could actually be '.sprintf("$formatForInputCharacters", $characterCodes[-1])."\n");
       
  1130 				}
       
  1131 			my @characterCodeRanges=();
       
  1132 			my $minimumNumberOfEntriesPerIndexedTable=($parameters ne '')? $parameters: 0;
       
  1133 			my $firstInputCharacterCodeInIndexedTable=$characterCodes[0];
       
  1134 			my $previousCharacterCode=$firstInputCharacterCodeInIndexedTable;
       
  1135 			my $characterCode;
       
  1136 			foreach $characterCode (@characterCodes)
       
  1137 				{
       
  1138 				($characterCode>=$previousCharacterCode) or die("Error: internal error 7\n");
       
  1139 				if ($characterCode>$previousCharacterCode+1)
       
  1140 					{
       
  1141 					if (($previousCharacterCode-$firstInputCharacterCodeInIndexedTable)+1>=$minimumNumberOfEntriesPerIndexedTable)
       
  1142 						{
       
  1143 						push(@characterCodeRanges, [$firstInputCharacterCodeInIndexedTable, $previousCharacterCode]);
       
  1144 						}
       
  1145 					$firstInputCharacterCodeInIndexedTable=$characterCode;
       
  1146 					}
       
  1147 				$previousCharacterCode=$characterCode;
       
  1148 				}
       
  1149 			push(@characterCodeRanges, [$firstInputCharacterCodeInIndexedTable, $previousCharacterCode]);
       
  1150 			@characterCodes=();
       
  1151 			my $characterCodeRange;
       
  1152 			foreach $characterCodeRange (@characterCodeRanges)
       
  1153 				{
       
  1154 				my $nameOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries='keyedTables32OfIndexedTables32_indexedEntries_'.($outputIsUnicode? 'foreignToUnicode': 'unicodeToForeign').'_'.($#$sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_indexedEntries+2);
       
  1155 				my $sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries=[];
       
  1156 				push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, "LOCAL_D const TUint32 $nameOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries\[\]=\n\t\{\n");
       
  1157 				my $characterCode;
       
  1158 				my $lastInputCharacterCodeInIndexedTable=$characterCodeRange->[1];
       
  1159 				for ($characterCode=$characterCodeRange->[0]; $characterCode<=$lastInputCharacterCodeInIndexedTable; ++$characterCode)
       
  1160 					{
       
  1161 					if (!defined($characterCodes->{$characterCode}))
       
  1162 						{
       
  1163 						die("Error: internal error 8\n");
       
  1164 						}
       
  1165 					push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, "\t".sprintf($formatForOutputCharacters, $characterCodes->{$characterCode}));
       
  1166 					if ($characterCode<$lastInputCharacterCodeInIndexedTable)
       
  1167 						{
       
  1168 						push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, ',');
       
  1169 						}
       
  1170 					push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, "\n");
       
  1171 					delete $characterCodes->{$characterCode};
       
  1172 					}
       
  1173 				push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, "\t\};\n\n");
       
  1174 				push(@$sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_indexedEntries, $sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries);
       
  1175 				push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, "\t\t\{\n\t\t".sprintf($formatForInputCharacters, $characterCodeRange->[0]).",\n\t\t".sprintf($formatForInputCharacters, $characterCodeRange->[1]).",\n\t\t$nameOfNextOneDirectionKeyedTables32OfIndexedTables32_indexedEntries\n\t\t\}");
       
  1176 				if ($characterCodeRange->[1]<$characterCodeRanges[-1]->[1])
       
  1177 					{
       
  1178 					push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, ',');
       
  1179 					}
       
  1180 				push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, "\n");
       
  1181 				}
       
  1182 			push(@$sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, "\t\};\n\n");
       
  1183 			push(@$sourceCodeOfOneDirectionKeyedTables32OfIndexedTables32_keyedEntries, $sourceCodeOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries);
       
  1184 			$word1="UData_S$algorithmAsText($nameOfNextOneDirectionKeyedTables32OfIndexedTables32_keyedEntries)";
       
  1185 			}
       
  1186 		else
       
  1187 			{
       
  1188 			die("Error: internal error 9\n");
       
  1189 			}
       
  1190 		push(@$sourceCodeOfTopLevelStructures, "\t\t\{\n\t\t".sprintf($formatForInputCharacters, $firstInputCharacterCodeInRange).",\n\t\t".sprintf($formatForInputCharacters, $lastInputCharacterCodeInRange).",\n\t\tSCnvConversionData::SOneDirectionData::SRange::E$algorithmAsText,\n\t\t".$sizeOfOutputCharacterCodeInBytesIfForeign.",\n\t\t0,\n\t\t\t\{\n\t\t\t".$word1."\n\t\t\t\}\n\t\t\}");
       
  1191 		if ($i<$indexOfLastRange)
       
  1192 			{
       
  1193 			push(@$sourceCodeOfTopLevelStructures, ',');
       
  1194 			}
       
  1195 		push(@$sourceCodeOfTopLevelStructures, "\n");
       
  1196 		}
       
  1197 	my @characterCodes=sort({$a<=>$b} keys(%$characterCodes));
       
  1198 	if (@characterCodes>0)
       
  1199 		{
       
  1200 		die('The following '.($outputIsUnicode? 'foreign': 'Unicode').' characters have no conversion algorithm specified: ['.join(', ', map(sprintf($formatForInputCharacters, $_), @characterCodes))."\]\n");
       
  1201 		}
       
  1202 	push(@$sourceCodeOfTopLevelStructures, "\t\};\n\n");
       
  1203 	}
       
  1204 
       
  1205 sub writeSourceCodeFinalStuff
       
  1206 	{
       
  1207 	my $fileHandle=shift;
       
  1208 	my $sourceCodeOfForeignToUnicodeIndexedTables16=shift;
       
  1209 	my $sourceCodeOfForeignToUnicodeKeyedTables1616=shift;
       
  1210 	my $sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_indexedEntries=shift;
       
  1211 	my $sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_keyedEntries=shift;
       
  1212 	my $sourceCodeOfUnicodeToForeignIndexedTables16=shift;
       
  1213 	my $sourceCodeOfUnicodeToForeignKeyedTables1616=shift;
       
  1214 	my $sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_indexedEntries=shift;
       
  1215 	my $sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_keyedEntries=shift;
       
  1216 
       
  1217 	my $sourceCodeOfForeignToUnicodeIndexedTables32=shift;
       
  1218 	my $sourceCodeOfForeignToUnicodeKeyedTables3232=shift;
       
  1219 	my $sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_indexedEntries=shift;
       
  1220 	my $sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_keyedEntries=shift;
       
  1221 	my $sourceCodeOfUnicodeToForeignIndexedTables32=shift;
       
  1222 	my $sourceCodeOfUnicodeToForeignKeyedTables3232=shift;
       
  1223 	my $sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_indexedEntries=shift;
       
  1224 	my $sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_keyedEntries=shift;
       
  1225 
       
  1226 	my $sourceCodeOfTopLevelStructures=shift;
       
  1227 	my $endiannessAsText=shift;
       
  1228 	my $additionalSubsetTables=shift;
       
  1229 	my $sourceCodeChunk;
       
  1230 	my $arrayOfSourceCodeChunks;
       
  1231 
       
  1232 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeIndexedTables16)
       
  1233 		{
       
  1234 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1235 			{
       
  1236 			print($fileHandle $sourceCodeChunk);
       
  1237 			}
       
  1238 		}
       
  1239 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables1616)
       
  1240 		{
       
  1241 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1242 			{
       
  1243 			print($fileHandle $sourceCodeChunk);
       
  1244 			}
       
  1245 		}
       
  1246 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_indexedEntries)
       
  1247 		{
       
  1248 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1249 			{
       
  1250 			print($fileHandle $sourceCodeChunk);
       
  1251 			}
       
  1252 		}
       
  1253 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables16OfIndexedTables16_keyedEntries)
       
  1254 		{
       
  1255 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1256 			{
       
  1257 			print($fileHandle $sourceCodeChunk);
       
  1258 			}
       
  1259 		}
       
  1260 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignIndexedTables16)
       
  1261 		{
       
  1262 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1263 			{
       
  1264 			print($fileHandle $sourceCodeChunk);
       
  1265 			}
       
  1266 		}
       
  1267 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables1616)
       
  1268 		{
       
  1269 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1270 			{
       
  1271 			print($fileHandle $sourceCodeChunk);
       
  1272 			}
       
  1273 		}
       
  1274 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_indexedEntries)
       
  1275 		{
       
  1276 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1277 			{
       
  1278 			print($fileHandle $sourceCodeChunk);
       
  1279 			}
       
  1280 		}
       
  1281 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables16OfIndexedTables16_keyedEntries)
       
  1282 		{
       
  1283 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1284 			{
       
  1285 			print($fileHandle $sourceCodeChunk);
       
  1286 			}
       
  1287 		}
       
  1288 	# for 32 bit encoding begin
       
  1289 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeIndexedTables32)
       
  1290 		{
       
  1291 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1292 			{
       
  1293 			print($fileHandle $sourceCodeChunk);
       
  1294 			}
       
  1295 		}
       
  1296 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables3232)
       
  1297 		{
       
  1298 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1299 			{
       
  1300 			print($fileHandle $sourceCodeChunk);
       
  1301 			}
       
  1302 		}
       
  1303 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_indexedEntries)
       
  1304 		{
       
  1305 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1306 			{
       
  1307 			print($fileHandle $sourceCodeChunk);
       
  1308 			}
       
  1309 		}
       
  1310 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfForeignToUnicodeKeyedTables32OfIndexedTables32_keyedEntries)
       
  1311 		{
       
  1312 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1313 			{
       
  1314 			print($fileHandle $sourceCodeChunk);
       
  1315 			}
       
  1316 		}
       
  1317 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignIndexedTables32)
       
  1318 		{
       
  1319 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1320 			{
       
  1321 			print($fileHandle $sourceCodeChunk);
       
  1322 			}
       
  1323 		}
       
  1324 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables3232)
       
  1325 		{
       
  1326 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1327 			{
       
  1328 			print($fileHandle $sourceCodeChunk);
       
  1329 			}
       
  1330 		}
       
  1331 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_indexedEntries)
       
  1332 		{
       
  1333 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1334 			{
       
  1335 			print($fileHandle $sourceCodeChunk);
       
  1336 			}
       
  1337 		}
       
  1338 	foreach $arrayOfSourceCodeChunks (@$sourceCodeOfUnicodeToForeignKeyedTables32OfIndexedTables32_keyedEntries)
       
  1339 		{
       
  1340 		foreach $sourceCodeChunk (@$arrayOfSourceCodeChunks)
       
  1341 			{
       
  1342 			print($fileHandle $sourceCodeChunk);
       
  1343 			}
       
  1344 		}
       
  1345 	# for 32 bit encoding end
       
  1346 	foreach $sourceCodeChunk (@$sourceCodeOfTopLevelStructures)
       
  1347 		{
       
  1348 		print($fileHandle $sourceCodeChunk);
       
  1349 		}
       
  1350 
       
  1351 	print($fileHandle "GLDEF_D const SCnvConversionData conversionData=\n\t\{\n\tSCnvConversionData::E$endiannessAsText,\n\t\t\{\n\t\tARRAY_LENGTH(foreignVariableByteDataRanges),\n\t\tforeignVariableByteDataRanges\n\t\t\},\n\t\t\{\n\t\tARRAY_LENGTH(foreignToUnicodeDataRanges),\n\t\tforeignToUnicodeDataRanges\n\t\t\},\n\t\t\{\n\t\tARRAY_LENGTH(unicodeToForeignDataRanges),\n\t\tunicodeToForeignDataRanges\n\t\t\},\n\tNULL,\n\tNULL\n\t\};\n\n");
       
  1352 
       
  1353 	my $additionalSubsetTableName;
       
  1354 	my $additionalSubsetTableData;
       
  1355 	while (($additionalSubsetTableName, $additionalSubsetTableData)=each(%$additionalSubsetTables))
       
  1356 		{
       
  1357 		(defined($additionalSubsetTableData->[0]) && defined($additionalSubsetTableData->[1]) && defined($additionalSubsetTableData->[2]) && defined($additionalSubsetTableData->[3])) or die("Error: incomplete definition of \"$additionalSubsetTableName\"\n");
       
  1358 		print($fileHandle "GLREF_D const SCnvConversionData $additionalSubsetTableName;\n");
       
  1359 		print($fileHandle "GLDEF_D const SCnvConversionData $additionalSubsetTableName=\n\t\{\n\tSCnvConversionData::E$endiannessAsText,\n\t\t\{\n\t\tARRAY_LENGTH(foreignVariableByteDataRanges),\n\t\tforeignVariableByteDataRanges\n\t\t\},\n\t\t\{\n\t\t$additionalSubsetTableData->[1]-$additionalSubsetTableData->[0],\n\t\tforeignToUnicodeDataRanges+$additionalSubsetTableData->[0]\n\t\t\},\n\t\t\{\n\t\t$additionalSubsetTableData->[3]-$additionalSubsetTableData->[2],\n\t\tunicodeToForeignDataRanges+$additionalSubsetTableData->[2]\n\t\t\}\n\t\};\n\n");
       
  1360 		}
       
  1361 	}
       
  1362 
       
  1363 sub writeBinaryHeader
       
  1364 	{
       
  1365 	my $fileHandle=shift;
       
  1366 	my $uid=shift;
       
  1367 	my $endianness=shift;
       
  1368 	my $replacementForUnconvertibleUnicodeCharacters=shift;
       
  1369 	&writeUids($fileHandle, 0x100011bd, $uid, 0);
       
  1370 	&write32($fileHandle, 1); # version number of the file format
       
  1371 	&write32($fileHandle, 0); # not currently used
       
  1372 	&write8($fileHandle, 0); # number of Unicode characters in the name (which is now derived from the file-name, hence why this is zero)
       
  1373 	&write8($fileHandle, $endianness);
       
  1374 	&write8($fileHandle, length($replacementForUnconvertibleUnicodeCharacters));
       
  1375 	&writeString($fileHandle, $replacementForUnconvertibleUnicodeCharacters);
       
  1376 	}
       
  1377 
       
  1378 sub writeBinaryForeignVariableByteData
       
  1379 	{
       
  1380 	my $fileHandle=shift;
       
  1381 	my $foreignVariableByteData=shift;
       
  1382 	&writePositiveIntegerCompacted30($fileHandle, scalar(@$foreignVariableByteData));
       
  1383 	my $rangeData;
       
  1384 	foreach $rangeData (@$foreignVariableByteData)
       
  1385 		{
       
  1386 		if (@$rangeData!=3)
       
  1387 			{
       
  1388 			die("Error: internal error 10\n");
       
  1389 			}
       
  1390 		my $firstInitialByteValueInRange=$rangeData->[0];
       
  1391 		my $lastInitialByteValueInRange=$rangeData->[1];
       
  1392 		if ($lastInitialByteValueInRange<$firstInitialByteValueInRange)
       
  1393 			{
       
  1394 			die("Error: internal error 11\n");
       
  1395 			}
       
  1396 		&write8($fileHandle, $firstInitialByteValueInRange);
       
  1397 		&write8($fileHandle, $lastInitialByteValueInRange);
       
  1398 		&write8($fileHandle, $rangeData->[2]); # numberOfSubsequentBytes
       
  1399 		}
       
  1400 	}
       
  1401 
       
  1402 sub writeBinaryOneDirectionData
       
  1403 	{
       
  1404 	my $fileHandle=shift;
       
  1405 	my $oneDirectionData=shift;
       
  1406 	my $characterCodes=shift;
       
  1407 	my $outputIsUnicode=shift;
       
  1408 	&writePositiveIntegerCompacted30($fileHandle, scalar(@$oneDirectionData));
       
  1409 	my $rangeData;
       
  1410 	foreach $rangeData (@$oneDirectionData)
       
  1411 		{
       
  1412 ##		$rangeData is $includePriority, $searchPriority, $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange, $algorithm[, $sizeOfOutputCharacterCodeInBytes], $parameters
       
  1413 		if (scalar(@$rangeData)!=($outputIsUnicode? 6: 7))
       
  1414 			{
       
  1415 			die("Error: internal error 12\n");
       
  1416 			}
       
  1417 		my $firstInputCharacterCodeInRange=$rangeData->[2];
       
  1418 		my $lastInputCharacterCodeInRange=$rangeData->[3];
       
  1419 		if ($lastInputCharacterCodeInRange<$firstInputCharacterCodeInRange)
       
  1420 			{
       
  1421 			die("Error: internal error 13\n");
       
  1422 			}
       
  1423 		&writePositiveIntegerCompacted30($fileHandle, $firstInputCharacterCodeInRange);
       
  1424 		&writePositiveIntegerCompacted30($fileHandle, $lastInputCharacterCodeInRange);
       
  1425 		my $algorithm=$rangeData->[4];
       
  1426 		&write8($fileHandle, $algorithm);
       
  1427 		if (!$outputIsUnicode)
       
  1428 			{
       
  1429 			&write8($fileHandle, $rangeData->[5]); # sizeOfOutputCharacterCodeInBytesIfForeign
       
  1430 			}
       
  1431 		if ($algorithm==0) # Direct
       
  1432 			{
       
  1433 			my $characterCode;
       
  1434 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
  1435 				{
       
  1436 				if (!defined($characterCodes->{$characterCode}))
       
  1437 					{
       
  1438 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)."\n");
       
  1439 					}
       
  1440 				if ($characterCodes->{$characterCode}!=$characterCode)
       
  1441 					{
       
  1442 					die("Error: the conversion from ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)." to ".($outputIsUnicode? 'Unicode': 'foreign')." character code ".sprintf("0x%08x", $characterCodes->{$characterCode})." is not a direct conversion\n");
       
  1443 					}
       
  1444 				delete $characterCodes->{$characterCode};
       
  1445 				}
       
  1446 			}
       
  1447 		elsif ($algorithm==1) # Offset
       
  1448 			{
       
  1449 			my $offset=$characterCodes->{$firstInputCharacterCodeInRange}-$firstInputCharacterCodeInRange;
       
  1450 			delete $characterCodes->{$firstInputCharacterCodeInRange};
       
  1451 			my $characterCode;
       
  1452 			for ($characterCode=$firstInputCharacterCodeInRange+1; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
  1453 				{
       
  1454 				if (!defined($characterCodes->{$characterCode}))
       
  1455 					{
       
  1456 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x (0x%08x-0x%08x)", $characterCode, $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange)."\n");
       
  1457 					}
       
  1458 				if ($characterCodes->{$characterCode}-$characterCode!=$offset)
       
  1459 					{
       
  1460 					die("Error: the conversion from ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)." to ".($outputIsUnicode? 'Unicode': 'foreign')." character code ".sprintf("0x%08x", $characterCodes->{$characterCode})." has a different offset from the previous one in the range\n");
       
  1461 					}
       
  1462 				delete $characterCodes->{$characterCode};
       
  1463 				}
       
  1464 			&writeSignedIntegerCompacted29($fileHandle, $offset);
       
  1465 			}
       
  1466 		elsif ($algorithm==2) # IndexedTable16
       
  1467 			{
       
  1468 			my $characterCode;
       
  1469 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
  1470 				{
       
  1471 				if (!defined($characterCodes->{$characterCode}))
       
  1472 					{
       
  1473 					die("Error: There is no conversion defined for ".($outputIsUnicode? 'foreign': 'Unicode')." character code ".sprintf("0x%08x", $characterCode)."\n");
       
  1474 					}
       
  1475 				&write16($fileHandle, $characterCodes->{$characterCode});
       
  1476 				delete $characterCodes->{$characterCode};
       
  1477 				}
       
  1478 			}
       
  1479 		elsif ($algorithm==3) # KeyedTable1616
       
  1480 			{
       
  1481 			my $characterCode;
       
  1482 			my @table=();
       
  1483 			for ($characterCode=$firstInputCharacterCodeInRange; $characterCode<=$lastInputCharacterCodeInRange; ++$characterCode)
       
  1484 				{
       
  1485 				if (defined($characterCodes->{$characterCode}))
       
  1486 					{
       
  1487 					push(@table, [$characterCode, $characterCodes->{$characterCode}]);
       
  1488 					delete $characterCodes->{$characterCode};
       
  1489 					}
       
  1490 				}
       
  1491 			my $firstIteration=1;
       
  1492 			my $lastKey;
       
  1493 			&writePositiveIntegerCompacted30($fileHandle, scalar(@table));
       
  1494 			if ($table[0][0]!=$firstInputCharacterCodeInRange)
       
  1495 				{
       
  1496 				die("Error: no conversion is specified for the first ".($outputIsUnicode? 'foreign': 'Unicode')." character code in the KeyedTable1616 range ".sprintf("0x%08x to 0x%08x", $firstInputCharacterCodeInRange, $lastInputCharacterCodeInRange)."\n");
       
  1497 				}
       
  1498 			my $pair;
       
  1499 			foreach $pair (@table)
       
  1500 				{
       
  1501 				my $key=$pair->[0];
       
  1502 				if ($firstIteration)
       
  1503 					{
       
  1504 					$firstIteration=0;
       
  1505 					}
       
  1506 				else
       
  1507 					{
       
  1508 					if ($key<=$lastKey)
       
  1509 						{
       
  1510 						die("Error: internal error 14\n");
       
  1511 						}
       
  1512 					&writePositiveIntegerCompacted15($fileHandle, $key-$lastKey);
       
  1513 					}
       
  1514 				&write16($fileHandle, $pair->[1]);
       
  1515 				$lastKey=$key;
       
  1516 				}
       
  1517 			}
       
  1518 		elsif ($algorithm==4) # KeyedTable16OfIndexedTables16
       
  1519 			{
       
  1520 			die("Error: \"KeyedTable16OfIndexedTables16\" is only supported if generating source code\n");
       
  1521 			}
       
  1522 		else
       
  1523 			{
       
  1524 			die("Error: internal error 15\n");
       
  1525 			}
       
  1526 		}
       
  1527 	my @characterCodes=sort({$a<=>$b} keys(%$characterCodes));
       
  1528 	if (@characterCodes>0)
       
  1529 		{
       
  1530 		die('The following '.($outputIsUnicode? 'foreign': 'Unicode').'characters have no conversion algorithm specified: ['.join(', ', map({sprintf('0x%x', $_)} @characterCodes))."\]\n");
       
  1531 		}
       
  1532 	}
       
  1533