sl@0: # Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: # All rights reserved. sl@0: # This component and the accompanying materials are made available sl@0: # under the terms of "Eclipse Public License v1.0" sl@0: # which accompanies this distribution, and is available sl@0: # at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: # sl@0: # Initial Contributors: sl@0: # Nokia Corporation - initial contribution. sl@0: # sl@0: # Contributors: sl@0: # sl@0: # Description: sl@0: # sl@0: sl@0: use strict; sl@0: sl@0: ## Used as global variables, probably need to change and pass variables through as parameters. sl@0: my %globalValues=(); sl@0: ##initialise filenames sl@0: $globalValues{'inputFile'} = 'mglyphs.txt'; sl@0: $globalValues{'outputFileName'} = 'mglyphs.inl'; sl@0: $globalValues{'htmlFileName'} = 'mglyphs.html'; sl@0: $globalValues{'lgtablesize'} = 9; # Default tablesize value is 512 sl@0: $globalValues{'tablesize'} = 1 << $globalValues{'lgtablesize'}; sl@0: $globalValues{'storeashex'} = 0; sl@0: $globalValues{'stepOffset'} = 72; sl@0: $globalValues{'stepShift'} = 0; sl@0: sl@0: ## die if the correct number of argumements have not been entered sl@0: &extractFlags(\@ARGV, \%globalValues); sl@0: &printDebug("Remainder:$globalValues{'tablesize'}\n"); sl@0: &printDebug("StoreAsHex:$globalValues{'storeashex'}\n"); sl@0: sl@0: if ($globalValues{"information"}) sl@0: { sl@0: &dieShowingUsage(); sl@0: } sl@0: sl@0: &printDebug("Creating HashTable....\n"); sl@0: my %hashTable = &createHashTable($globalValues{'inputFile'}); sl@0: if (!defined(%hashTable)) sl@0: { sl@0: die("ERROR: Hash table was not created\n"); sl@0: } sl@0: if ($globalValues{"outputtohtml"}) sl@0: { sl@0: my $htmlFileName = $globalValues{'htmlFileName'}; sl@0: &printDebug("Creating HTML output to file: $htmlFileName\n"); sl@0: &createHTMLOfMappings($htmlFileName, %hashTable); sl@0: } sl@0: my $outputFileName = $globalValues{'outputFileName'}; sl@0: &printDebug("Writing Hash table to file: $outputFileName\n"); sl@0: &writeHashTableToFile($outputFileName, %hashTable); sl@0: &printDebug("$outputFileName created."); sl@0: sl@0: ##################### end of main section sl@0: sub extractFlags sl@0: { sl@0: my $aArgumentArray=shift; sl@0: my $aArguments=shift; sl@0: my $expectedArg = 'lgtablesize'; sl@0: my $expectedExtension; sl@0: foreach my $argument (@$aArgumentArray) sl@0: { sl@0: if ($argument =~ m!^[-/]([a-zA-Z].*)$!) sl@0: { sl@0: my $switch = $1; sl@0: $expectedArg = 'lgtablesize'; sl@0: $expectedExtension = undef; sl@0: if ($switch=~/^(x|hexoutput)$/i) sl@0: { sl@0: $$aArguments{'storeashex'}=1; sl@0: } sl@0: elsif ($switch=~/^(\?|help)$/i) sl@0: { sl@0: $$aArguments{'information'}=1; sl@0: } sl@0: elsif ($switch=~/^(v|verbose)$/i) sl@0: { sl@0: $$aArguments{'verbose'}=1; sl@0: } sl@0: elsif ($switch=~/^(h|outputtohtml)$/i) sl@0: { sl@0: $$aArguments{'outputtohtml'}=1; sl@0: $expectedArg = 'htmlFileName'; sl@0: $expectedExtension = '.html'; sl@0: } sl@0: elsif ($switch=~/^(i|input)$/i) sl@0: { sl@0: $expectedArg = 'inputFile'; sl@0: } sl@0: elsif ($switch=~/^(o|output)$/i) sl@0: { sl@0: $expectedArg = 'outputFileName'; sl@0: $expectedExtension = '.inl'; sl@0: } sl@0: elsif ($switch=~/^(offset)$/i) sl@0: { sl@0: $expectedArg = 'stepOffset'; sl@0: } sl@0: elsif ($switch=~/^(shift)$/i) sl@0: { sl@0: $expectedArg = 'stepShift'; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (defined $expectedExtension && $argument !~ m!\.[^/\\]*$!) sl@0: { sl@0: $argument .= $expectedExtension; sl@0: } sl@0: $$aArguments{$expectedArg} = $argument; sl@0: $expectedArg = 'lgtablesize'; sl@0: } sl@0: } sl@0: $globalValues{'tablesize'} = 1 << $globalValues{'lgtablesize'}; sl@0: $globalValues{'stepOffset'} &= 0xFFFFFE; sl@0: } sl@0: ##################### sl@0: sub dieShowingUsage sl@0: { sl@0: print <] [-x] [-i ] sl@0: [-o ] [-h [] [-shift ] sl@0: sl@0: the default log(base 2) table size is 9. This gives a table sl@0: size of 512 entries (2 to the power 9). So 7 gives a size of 128, 8 gives sl@0: 256, 9 gives 512, 10 gives 1024 and so on. sl@0: sl@0: options: -x -o -i -h sl@0: sl@0: -? Shows help sl@0: sl@0: The -x flag stores values into the .inl file in hex format: sl@0: hex(OriginalKeyCodeMirrorGlyphCode), sl@0: By default the values are stored in string hex format i.e 0x220C2209 sl@0: sl@0: The -h flag generates a html file displaying hash table information. sl@0: This may be followed by the filename to be output. sl@0: Default is 'mglyphs.html' sl@0: sl@0: The -i file specifies input file name. Default is 'mglyphs.txt'. sl@0: sl@0: The -o file specifies output file name. Default is 'mglyphs.inl'. sl@0: sl@0: -shift and -offset alter the "step" hash algorithm. sl@0: sl@0: USAGE_EOF sl@0: exit 0; sl@0: } sl@0: ######### sl@0: # sl@0: # Writes a hash table to file. sl@0: # Current format: sl@0: # Hex mode: "hex number created" sl@0: # Hex string mode: "Original keyMapped key" sl@0: ##################### sl@0: sub writeHashTableToFile sl@0: { sl@0: &printDebug("Writing to .inl file"); sl@0: my ($aOutputFileName, %aHashTable) = @_; sl@0: open(OUTPUT_FILE, '> ' . $aOutputFileName) or die('Error: could not open $aOutputFileName to write to\n'); sl@0: ## Print comments at top of .inl file sl@0: printf(OUTPUT_FILE "\/\/ mGlyphs.inl\n"); sl@0: printf(OUTPUT_FILE "\/\/\n"); sl@0: printf(OUTPUT_FILE "\/\/ Generated by mglyphtool.pl from '$globalValues{'inputFile'}'\n"); sl@0: printf(OUTPUT_FILE "\/\/\n\n"); sl@0: ## Declare array and fill in values sl@0: printf(OUTPUT_FILE "const unsigned long mGlyphArray[] = {\n\t"); sl@0: for (my $counter = 0; $counter < $globalValues{'tablesize'}; $counter++) sl@0: { sl@0: my $storeValue = "00000000"; sl@0: if (defined($aHashTable{$counter})) sl@0: { sl@0: $storeValue = $aHashTable{$counter}; sl@0: } sl@0: $storeValue = ($globalValues{'storeashex'}) ? hex($storeValue) : "0x$storeValue"; sl@0: print OUTPUT_FILE $storeValue; sl@0: if (($counter+1) < $globalValues{'tablesize'}) sl@0: { sl@0: print OUTPUT_FILE (($counter + 1) % 8 == 0? ",\n\t" : ', '); sl@0: } sl@0: } sl@0: print(OUTPUT_FILE "};\n"); sl@0: print(OUTPUT_FILE "\nconst int KLgMirrorTableSize=$globalValues{'lgtablesize'};\n"); sl@0: print(OUTPUT_FILE "const int KMirrorTableSize=$globalValues{'tablesize'};\n"); sl@0: # Inline functions sl@0: # Get a Hash value from a given key sl@0: print(OUTPUT_FILE "\n// Returns the first index to probe for character aKey.\n"); sl@0: print(OUTPUT_FILE "inline long MirrorStart(long aKey)\n"); sl@0: print(OUTPUT_FILE "\t{ return aKey \& (KMirrorTableSize-1); }\n"); sl@0: print(OUTPUT_FILE "\n// Returns the offset for further probes for character aKey.\n"); sl@0: print(OUTPUT_FILE "inline long MirrorStep(long aKey)\n"); sl@0: my $stepShift = $globalValues{'stepShift'}; sl@0: print(OUTPUT_FILE "\t{ return ("); sl@0: if ($stepShift == 0) sl@0: { sl@0: print(OUTPUT_FILE "aKey"); sl@0: } sl@0: elsif (0 < $stepShift) sl@0: { sl@0: print(OUTPUT_FILE "(aKey >> $stepShift)"); sl@0: } sl@0: else sl@0: { sl@0: $stepShift = -$stepShift; sl@0: print(OUTPUT_FILE "(aKey << $stepShift)"); sl@0: } sl@0: print(OUTPUT_FILE " | 1) + $globalValues{'stepOffset'}; }\n\n"); sl@0: sl@0: close(OUTPUT_FILE); sl@0: } sl@0: ##################### listing of hash indexes values for original and mirrored glyphs sl@0: sub createHTMLOfMappings sl@0: { sl@0: my ($aOutputFileName, %aHashTable )= @_; sl@0: open(OUTPUT_FILE, '> ' . $aOutputFileName) or die('Error: could not open $aOutputFileName to create HTML output'); sl@0: printf(OUTPUT_FILE "MirrorGlyph Hash Output<\/TITLE><\/HEAD><BODY>"); sl@0: ## print hash table details sl@0: printf(OUTPUT_FILE "<P>Values in hash Table - <B>(Hash Function: Key mod $globalValues{'tablesize'})<\/B><\/P><TABLE border=1>"); sl@0: printf(OUTPUT_FILE "<TR><TD><B>---<\/B><\/TD><TD BGCOLOR=\#8888FF><B>Character code:<\/B><\/TD><TD><B>Hash Index:<\/B><\/TD><TD BGCOLOR=\#8888FF><B>Mirror Glyph Value:<\/B><\/TD><TD><b>Search Jump Count<\/b>"); sl@0: my %keySet; sl@0: foreach my $value (values %aHashTable) sl@0: { sl@0: $keySet{&getLower(hex $value)} = 1; sl@0: } sl@0: foreach my $key (32..127) sl@0: { sl@0: $keySet{$key} = 1; sl@0: } sl@0: my @keys = sort {$a <=> $b} (keys %keySet); sl@0: foreach my $key (@keys) sl@0: { sl@0: my $counter = 0; sl@0: my $HKey = &findHashTableIndex($key, \$counter, \%aHashTable); sl@0: my $stored = $aHashTable{$HKey}; sl@0: my $storedValue = 'no change'; sl@0: my $storedKey = $key; sl@0: if (defined $stored) sl@0: { sl@0: $storedValue = sprintf('%02x', &getLower(hex $stored)); sl@0: $storedKey = &getUpper(hex $stored); sl@0: } sl@0: if ($storedKey) sl@0: { sl@0: die('incorrect key found in hash table') unless ($storedKey == $key); sl@0: printf(OUTPUT_FILE "<TR><TD>---<\/TD><TD BGCOLOR=\#8888FF><B>%02x<\/B><\/TD><TD>%02x<\/TD><TD BGCOLOR=\#8888FF><B>%s<\/B><\/TD><TD>%d<\/TD><\/TR>", $key, $HKey, $storedValue, $counter); sl@0: } sl@0: } sl@0: printf(OUTPUT_FILE "<\/TABLE>"); sl@0: printf(OUTPUT_FILE "<\/BODY><\/HTML>"); sl@0: close(OUTPUT_FILE); sl@0: } sl@0: ##################### sl@0: # Hash Table functions sl@0: ##################### sl@0: sl@0: ##################### sl@0: #Returns a new Hash Table sl@0: ##################### sl@0: sub createHashTable sl@0: { sl@0: my $aInputFileName = shift; sl@0: my $lineNumber = 1; sl@0: my %newHashTable = (); sl@0: open(INPUT_FILE, '< ' . $aInputFileName) or die('ERROR: Could not open $aInputFileName to read from'); sl@0: while (my $line=<INPUT_FILE>) sl@0: { sl@0: if ($line=~/^(.*);\s(.*\w)\s\W.*$/) ## Grab Original glyph value and mirrored glyph value sl@0: { sl@0: &updateHashTable($1, $2, \%newHashTable); sl@0: } sl@0: $lineNumber++; sl@0: } sl@0: close(INPUT_FILE); sl@0: return %newHashTable; sl@0: } sl@0: ##################### sl@0: # sl@0: # Retrieves a HashKey which is not currently being used in a given HashTable sl@0: # sl@0: ##################### sl@0: sub findHashTableIndex sl@0: { sl@0: my ($aHashKey, $aCounter, $aHashTable) = @_; sl@0: my $current = &hashFunction($aHashKey); sl@0: my $step = &hashStepFunction($aHashKey); sl@0: my $tableSize = $globalValues{'tablesize'}; sl@0: while (defined($$aHashTable{$current}) && &getUpper(hex($$aHashTable{$current})) != $aHashKey) sl@0: { sl@0: ++$$aCounter; sl@0: $current += $step; sl@0: $current &= $tableSize - 1; sl@0: } sl@0: if (2 < $$aCounter) sl@0: { sl@0: printf STDERR ("WARNING: Jumped $$aCounter times, inefficient hash for %02x ($current, $step)\n", $aHashKey); sl@0: } sl@0: return $current; sl@0: } sl@0: sl@0: ##################### sl@0: sub updateHashTable sl@0: { sl@0: my ($aKey, $aValueToStore, $aHashTable) = @_; sl@0: my $counter = 0; sl@0: my $key = hex($aKey); sl@0: my $hashKey = &findHashTableIndex($key, \$counter, $aHashTable); sl@0: $$aHashTable{$hashKey} = "$aKey$aValueToStore"; sl@0: return $hashKey; sl@0: } sl@0: ##################### sl@0: # Returns a hash key for a given key sl@0: # Currently using a simple hash function sl@0: ##################### sl@0: sub hashFunction sl@0: { sl@0: my $aKey = shift; sl@0: return $aKey & ($globalValues{'tablesize'}-1); sl@0: } sl@0: sl@0: # Returns second hash value: used for the step size sl@0: sub hashStepFunction sl@0: { sl@0: my $aKey = shift; sl@0: my $stepShift = $globalValues{'stepShift'}; sl@0: if ($stepShift < 0) sl@0: { sl@0: $aKey <<= -$stepShift; sl@0: } sl@0: elsif (0 < $stepShift) sl@0: { sl@0: $aKey >>= $stepShift; sl@0: } sl@0: return ($aKey | 1) + $globalValues{'stepOffset'}; sl@0: } sl@0: sl@0: ##################### sl@0: # Utility functions sl@0: ##################### sl@0: sub getLower sl@0: { sl@0: my $aValue = shift; sl@0: return $aValue & hex("0000FFFF"); sl@0: } sl@0: sub getUpper sl@0: { sl@0: my $aValue = shift; sl@0: return ($aValue & hex("FFFF0000")) >> 16; sl@0: } sl@0: sub printDebug sl@0: { sl@0: my $string = shift; sl@0: if ($globalValues{'verbose'}) sl@0: { sl@0: print $string; sl@0: } sl@0: } sl@0: