|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package IETF::ACE;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
164878
 | 
 use strict;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
4
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
4
 | 
 use diagnostics;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
26
 | 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require Exporter;  | 
| 
9
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
268323
 | 
 use AutoLoader qw(AUTOLOAD);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1519
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
527
 | 
 use Unicode::String qw(utf8 ucs4 utf16);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6238
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75
 | 
    | 
| 
12
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
456
 | 
 use MIME::Base64;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
486
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3240
 | 
    | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 @ISA = qw(Exporter);  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Items to export into callers namespace by default. Note: do not export  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # names by default without a very good reason. Use EXPORT_OK instead.  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Do not simply export all your public functions/methods/constants.  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # This allows declaration	use IETF::ACE ':all';  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # will save memory.  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 %EXPORT_TAGS = ( 'all' => [ qw(  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ) ] );  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 @EXPORT_OK = qw (  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    @{ $EXPORT_TAGS{'all'} }  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &UCS4toName  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &UCS4toUPlus  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &UTF5toUCS4  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &GetCharFromUTF5  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &UCS4toRACE  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &RACEtoUCS4  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &UCS4toLACE  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &LACEtoUCS4  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &Base32Encode  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &Base32Decode  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &CheckForSTD13Name  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &CheckForBadSurrogates  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &HexOut  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &DebugOn  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &DebugOff  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    &DebugOut  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 @EXPORT = qw(  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $VERSION = '0.04';  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Preloaded methods go here.  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Autoload methods go after =cut, and are processed by the autosplit program.  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @Formats = ('utf8', 'utf16', 'ucs4', 'utf5', 'race', 'lace', 'name', 'u+');  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $UTF5Chars = '0123456789ABCDEFGHIJKLMNOPQRSTUV';  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $Base32Chars = 'abcdefghijklmnopqrstuvwxyz234567';  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $RACEPrefix = 'bq--';  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $LACEPrefix = 'lq--';  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $Debug = 0;  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UCS4toName {  | 
| 
66
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
67
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my @TheNames = ucs4($InString)->name;  | 
| 
68
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $NameString = join("\n", @TheNames) . "\n";  | 
| 
69
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return $NameString;  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UCS4toUPlus {  | 
| 
73
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
74
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $TheHex = ucs4($InString)->hex . "\n";  | 
| 
75
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$TheHex =~ s/ /\n/g;  | 
| 
76
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$TheHex = uc($TheHex);  | 
| 
77
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return $TheHex;  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UTF5toUCS4 {  | 
| 
81
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
82
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $OutString = '';  | 
| 
83
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($ThisUCS4, $ThisCharString, @RevString, $Char, $WhichChar);  | 
| 
84
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($TempNum, $TempChr, $TempPos);  | 
| 
85
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	until(length($InString) == 0) {  | 
| 
86
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		($ThisCharString, $InString) = &GetCharFromUTF5($InString);  | 
| 
87
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$ThisUCS4 = "\x00\x00\x00\x00";  | 
| 
88
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		@RevString = reverse(split(//, $ThisCharString));  | 
| 
89
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$WhichChar = 0;  | 
| 
90
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		foreach $Char (@RevString) {  | 
| 
91
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$TempNum = index($UTF5Chars, $Char) % 16;  | 
| 
92
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if(($WhichChar % 2) == 1) { $TempNum *= 16 };  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
93
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$TempChr = chr($TempNum);  | 
| 
94
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$TempPos = (int($WhichChar / 2));  | 
| 
95
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if($TempPos == 0) { $TempChr = "\x00" x 3 . $TempChr }  | 
| 
 
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
96
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			elsif($TempPos == 1) { $TempChr = "\x00" x 2 . $TempChr . "\x00" }  | 
| 
97
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			elsif($TempPos == 2) { $TempChr = "\x00" . $TempChr . "\x00" x 2 }  | 
| 
98
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			elsif($TempPos == 3) { $TempChr = $TempChr . "\x00" x 3 }  | 
| 
99
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$ThisUCS4 = $ThisUCS4 | $TempChr;  | 
| 
100
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$WhichChar += 1;  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
102
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$OutString .= $ThisUCS4;  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
104
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return $OutString;  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub GetCharFromUTF5 {  | 
| 
108
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
109
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $FirstChar = substr($InString, 0, 1);  | 
| 
110
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless(grep(/[GHIJKLMNOPQRSTUV]/, $FirstChar))  | 
| 
111
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found bad character string in UTF5 at $InString" .  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			" in GetCharFromUTF5\n") }  | 
| 
113
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $ThisCharString = $FirstChar;  | 
| 
114
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InString = substr($InString, 1);  | 
| 
115
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	until(grep(/[GHIJKLMNOPQRSTUV]/, substr($InString, 0, 1))) {  | 
| 
116
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$ThisCharString .= substr($InString, 0, 1);  | 
| 
117
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$InString = substr($InString, 1);  | 
| 
118
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		last if(length($InString) == 0);  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
120
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return ($ThisCharString, $InString);  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UCS4toUTF5 {  | 
| 
124
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
125
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $OutString = '';  | 
| 
126
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($ThisUCS4, $i, $Nibble, $HaveSeenFirst);  | 
| 
127
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	until(length($InString) == 0) {  | 
| 
128
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$ThisUCS4 = substr($InString, 0, 4);  | 
| 
129
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$InString = substr($InString, 4);  | 
| 
130
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my @Octets = split(//, $ThisUCS4);  | 
| 
131
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$HaveSeenFirst = 0;  | 
| 
132
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		foreach $i (0 .. 7) {  | 
| 
133
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if(($i % 2) == 0)  | 
| 
134
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ $Nibble = chr(ord($Octets[int($i / 2)] & "\xf0") >> 4) }  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			else  | 
| 
136
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ $Nibble = $Octets[int($i / 2)] & "\x0f" };  | 
| 
137
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 			next if(($Nibble eq "\x00") and !($HaveSeenFirst));  | 
| 
138
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if($HaveSeenFirst)  | 
| 
139
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ $OutString .= substr($UTF5Chars, ord($Nibble), 1) }  | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			else {  | 
| 
141
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$OutString .= substr($UTF5Chars, ord($Nibble)+16, 1);  | 
| 
142
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$HaveSeenFirst = 1;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
146
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return $OutString;  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UCS4toRACE {  | 
| 
151
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
28
 | 
 	my $InString = shift(@_);  | 
| 
152
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	my (@InArr, $InStr, $InputPointer, $DoStep3, @UpperUniq, %UpperSeen,  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$U1, $U2, $N1, $CompString,  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$PostBase32);  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
156
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	&DebugOut("Hex of input to UCS4toRACE:\n", &HexOut($InString));  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Make an array of the UTF16 octets  | 
| 
158
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 	@InArr = split(//, ucs4($InString)->utf16);  | 
| 
159
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106
 | 
 	$InStr = join('', @InArr);  | 
| 
160
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
 	&DebugOut("Hex of UTF16 input to UCS4toRACE:\n", &HexOut($InStr));  | 
| 
161
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	if(&CheckForSTD13Name($InStr))  | 
| 
162
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found all-STD13 name in input to UCS4toRACE\n") }  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Prepare for steps 1 and 2 by making an array of the upper octets  | 
| 
165
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	for($InputPointer = 0; $InputPointer <= $#InArr; $InputPointer += 2) {  | 
| 
166
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 		unless ($UpperSeen{$InArr[$InputPointer]}) {  | 
| 
167
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 			$UpperSeen{$InArr[$InputPointer]} = 1;  | 
| 
168
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 			push (@UpperUniq, $InArr[$InputPointer])  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
171
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	if($#UpperUniq == 0) { # Step 1  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
172
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$U1 = $UpperUniq[0];  | 
| 
173
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$DoStep3 = 0;  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} elsif($#UpperUniq == 1) {  # Step 2  | 
| 
175
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if($UpperUniq[0] eq "\x00") {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
176
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$U1 = $UpperUniq[1];  | 
| 
177
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$DoStep3 = 0;  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		} elsif($UpperUniq[1] eq "\x00") {  | 
| 
179
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$U1 = $UpperUniq[0];  | 
| 
180
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$DoStep3 = 0;  | 
| 
181
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		} else { $DoStep3 = 1 }  | 
| 
182
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	} else { $DoStep3 = 1 }  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Now output based on the value of $DoStep3  | 
| 
184
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	if($DoStep3) {  # Step 3  | 
| 
185
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		&DebugOut("Not compressing in UCS4toRACE (using D8 format).\n");  | 
| 
186
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$CompString = "\xd8" . join('', @InArr);  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  | 
| 
188
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
4
 | 
 		if(($U1 ge "\xd8") and ($U1 le "\xdc")) {  # Step 4a  | 
| 
189
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			my $DieOrd = sprintf("%04lX", ord($U1));  | 
| 
190
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			&DieOut("Found invalid input to UCS4toRACE step 4a: $DieOrd.\n");  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
192
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		&DebugOut("Compressing in UCS4toRACE (first octet is ",  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				sprintf("%04lX", ord($U1)), ").\n");  | 
| 
194
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
 		$CompString = $U1;  # Step 4b  | 
| 
195
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$InputPointer = 0;  | 
| 
196
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		while($InputPointer <= $#InArr) {  # Step 5a  | 
| 
197
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 			$U2 = $InArr[$InputPointer++]; $N1 = $InArr[$InputPointer++];  # Step 5b  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
198
 | 
5
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
15
 | 
 			if(($U2 eq "\x00") and ($N1 eq "\x99"))  # Step 5c  | 
| 
199
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ &DieOut("Found U+0099 in input stream to UCS4toRACE step 5c.\n"); }  | 
| 
200
 | 
5
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
15
 | 
 			if( ($U2 eq $U1) and ($N1 ne "\xff") )  # Step 6  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
201
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 				{ $CompString .= $N1 }  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			elsif( ($U2 eq $U1) and ($N1 eq "\xff") )  # Step 7  | 
| 
203
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ $CompString .= "\xff\x99" }  | 
| 
204
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			else { $CompString .= "\xff" . $N1 }  # Step 8  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
207
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	&DebugOut("Hex of output before Base32Encode:\n", &HexOut($CompString));  | 
| 
208
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	if(length($CompString) >= 37)  | 
| 
209
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{  &DieOut("Length of compressed string was >= 37 in UCS4toRACE.\n") }  | 
| 
210
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	$PostBase32 = &Base32Encode($CompString);  | 
| 
211
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	return "$RACEPrefix$PostBase32";  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub RACEtoUCS4 {  | 
| 
215
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = lc(shift(@_));  | 
| 
216
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($PostBase32, @DeArr, $i, $U1, $N1, $OutString, $LCheck,  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$InputPointer, @UpperUniq, %UpperSeen);  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Strip any whitespace  | 
| 
219
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InString =~ s/\s*//g;  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Strip of the prefix string  | 
| 
221
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless(substr($InString, 0, length($RACEPrefix)) eq $RACEPrefix)  | 
| 
222
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("The input to RACEtoUCS4 did not start with '$RACEPrefix'\n") }  | 
| 
223
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InString = substr($InString, length($RACEPrefix));  | 
| 
224
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("The string after stripping in RACEtoUCS4: $InString\n");  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
226
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$PostBase32 = &Base32Decode($InString);  | 
| 
227
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@DeArr = split(//, $PostBase32);  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Reverse the compression  | 
| 
230
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$U1 = $DeArr[0];  # Step 1a  | 
| 
231
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if($#DeArr < 1)  # Step 1b  | 
| 
232
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("The output of Base32Decode was too short.\n") }   | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
234
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless ($U1 eq "\xd8") {  # Step 1c  | 
| 
235
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$i = 1;  | 
| 
236
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		until($i > $#DeArr) {  # Step 2a  | 
| 
237
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$N1 = $DeArr[$i++];  # Step 2b  | 
| 
238
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			unless($N1 eq "\xff")  {  # Step 2c  | 
| 
239
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 				if(($U1 eq "\x00") and ($N1 eq "\x99"))  # Step 3  | 
| 
240
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 					{ &DieOut("Found 0099 in the input to RACEtoUCS4, step 3.\n") }  | 
| 
241
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$OutString .= $U1 . $N1;  # Step 4  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			} else {  | 
| 
243
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				if($i > $#DeArr)  # Step 5  | 
| 
244
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 					{ &DieOut("Input in RACE string at octet $i too short " .  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 						"at step 5\n") }  | 
| 
246
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$N1 = $DeArr[$i++];  # Step 6a  | 
| 
247
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				if($N1 eq "\x99")  # Step 6b  | 
| 
248
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 					{ $OutString .= $U1 . "\xff" }  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				else  # Step 7  | 
| 
250
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 					{ $OutString .= "\x00" . $N1 }  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
253
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if((length($OutString) % 2) == 1)  # Step 11  | 
| 
254
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			{ &DieOut("The output of RACEtoUCS4 for compressed input was " .  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				"an odd number of characters at step 11.\n") }  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  # Was not compressed   | 
| 
257
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$LCheck = substr(join('', @DeArr), 1);  # Step 8a  | 
| 
258
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if((length($LCheck) % 2 ) == 1 )  # Step 8b  | 
| 
259
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			{ &DieOut("The output of RACEtoUCS4 for uncompressed input was " .  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				"an odd number of characters at step 8b.\n") }  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Do the step 9 check to be sure the right length was used  | 
| 
262
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		my @CheckArr = split(//, $LCheck);  | 
| 
263
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		for($InputPointer = 0; $InputPointer <= $#CheckArr; $InputPointer += 2) {  | 
| 
264
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			unless ($UpperSeen{$CheckArr[$InputPointer]}) {  | 
| 
265
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$UpperSeen{$CheckArr[$InputPointer]} = 1;  | 
| 
266
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				push (@UpperUniq, $CheckArr[$InputPointer])  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Should it have been compressed?  | 
| 
270
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 		if( ($#UpperUniq == 0) or  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			( ($#UpperUniq == 1) and   | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				(($UpperUniq[0] eq "\x00") or ($UpperUniq[1] eq "\x00"))  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			)  | 
| 
274
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		) { &DieOut("Input to RACEtoUCS4 failed during LCHECK format test " .  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				"in step 9.\n") }  | 
| 
276
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if((length($LCheck) % 2) == 1)  # Step 10a  | 
| 
277
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			{ &DieOut("The output of RACEtoUCS4 for uncompressed input was " .  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				"an odd number of characters at step 10a.\n") }  | 
| 
279
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$OutString = $LCheck  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
281
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of output string:\n", &HexOut($OutString));  | 
| 
282
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(&CheckForSTD13Name($OutString))  | 
| 
283
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found all-STD13 name before output of RACEtoUCS4\n") }  | 
| 
284
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(&CheckForBadSurrogates($OutString))  | 
| 
285
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found bad surrogate before output of RACEtoUCS4\n") }  | 
| 
286
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return utf16($OutString)->ucs4;  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub UCS4toLACE {  | 
| 
290
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = shift(@_);  | 
| 
291
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my (@InArr, $InStr, $InputPointer, $High, $OutBuffer, $Count, $LowBuffer,  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$i, $CompString, $PostBase32);  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
294
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of input to UCS4toLACE:\n", &HexOut($InString));  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Make an array of the UTF16 octets  | 
| 
296
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@InArr = split(//, ucs4($InString)->utf16);  | 
| 
297
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InStr = join('', @InArr);  | 
| 
298
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of UTF16 input to UCS4toLACE:\n", &HexOut($InStr));  | 
| 
299
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(&CheckForSTD13Name($InStr))  | 
| 
300
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found all-STD13 name in input to UCS4toLACE\n") }  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
302
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	if(((length($InStr) % 2) == 1) or (length($InStr) < 2))  # Step 1  | 
| 
303
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Odd length or too short on input to UCS4toLACE\n") }  | 
| 
304
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InputPointer = 0;  # Step 2  | 
| 
305
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $OutputBuffer = '';  | 
| 
306
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	do {  | 
| 
307
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$High = $InArr[$InputPointer];  # Step 3  | 
| 
308
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$Count = 1; $LowBuffer = $InArr[$InputPointer+1];  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
309
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		for($i = $InputPointer + 2; $i <= $#InArr; $i+=2) {  # Step 4  | 
| 
310
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			last unless($InArr[$i] eq $High);  | 
| 
311
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$Count += 1;  | 
| 
312
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$LowBuffer .= $InArr[$i+1];  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
314
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$OutputBuffer .= sprintf("%c", $Count) . "$High$LowBuffer";  # Step 5a  | 
| 
315
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$InputPointer = $InputPointer + (2 * $Count);  # Step 5b  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} while($InputPointer <= $#InArr);  # Step 6  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
318
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(length($OutputBuffer) <= length($InStr))  # Step 7a  | 
| 
319
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ $CompString = $OutputBuffer }  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else  | 
| 
321
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ $CompString = "\xff" . $InStr; }  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
323
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of output before Base32Encode:\n", &HexOut($CompString));  | 
| 
324
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(length($CompString) >= 37)  | 
| 
325
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{  &DieOut("Length of compressed string was >= 37 in UCS4toLACE.\n") }  | 
| 
326
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$PostBase32 = &Base32Encode($CompString);  | 
| 
327
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return "$LACEPrefix$PostBase32";  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub LACEtoUCS4 {  | 
| 
331
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InString = lc(shift(@_));  | 
| 
332
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($PostBase32, @DeArr, $Count, $InputPointer, $OutString, $LCheck,  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$OutputBuffer, $CompBuffer, @LArr, $LPtr, $RunCount, $RunBuffer);  | 
| 
334
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my $Low;  | 
| 
335
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my $High;  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Strip any whitespace  | 
| 
337
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InString =~ s/\s*//g;  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Strip of the prefix string  | 
| 
339
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless(substr($InString, 0, length($LACEPrefix)) eq $LACEPrefix)  | 
| 
340
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("The input to LACEtoUCS4 did not start with '$LACEPrefix'\n") }  | 
| 
341
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InString = substr($InString, length($LACEPrefix));  | 
| 
342
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("The string after stripping in LACEtoUCS4: $InString\n");  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
344
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$PostBase32 = &Base32Decode($InString);  | 
| 
345
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@DeArr = split(//, $PostBase32);  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
347
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InputPointer = 0;  # Step 1a  | 
| 
348
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if($#DeArr < 1)  # Step 1b  | 
| 
349
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("The output of Base32Decode was too short.\n") }  | 
| 
350
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$OutputBuffer = '';  | 
| 
351
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless ($DeArr[$InputPointer] eq "\xff") {  # Step 2  | 
| 
352
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		do {  | 
| 
353
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$Count = $DeArr[$InputPointer]; # Step 3a  | 
| 
354
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 			if(($Count == 0) or ($Count > 36))  # Step 3b  | 
| 
355
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ &DieOut("Got bad count ($Count) in LACEtoUCS4 step 3b.\n") };  | 
| 
356
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if(++$InputPointer == $#DeArr)  # Step 3c and 3d  | 
| 
357
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ &DieOut("Got bad length input in LACEtoUCS4 step 3d.\n") };  | 
| 
358
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$High = $DeArr[$InputPointer++]; # Step 4a and 4b  | 
| 
359
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			do {  | 
| 
360
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			if($InputPointer == $#DeArr)  # Step 5a  | 
| 
361
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				{ &DieOut("Got bad length input in LACEtoUCS4 step 5a.\n") };  | 
| 
362
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$Low = $DeArr[$InputPointer++]; # Step 5c and 5c  | 
| 
363
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$OutputBuffer .= $High . $Low;  # Step 6  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			} until(--$Count > 0);  # Step 7  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  while($InputPointer < $#DeArr);  # Step 8  | 
| 
366
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if(length($OutputBuffer) > length($InString)) {  # Step 9b  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
367
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			&DieOut("Wrong compression format found in LACEtoUCS4 step 9b.\n");  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		} elsif((length($OutputBuffer) % 2) == 1) {  # Step 9c  | 
| 
369
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			&DieOut("Odd length output buffer found in LACEtoUCS4 step 9c.\n");  | 
| 
370
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		} else { $OutString = $OutputBuffer }  # Step 9d  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  # Step 10  | 
| 
372
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$OutputBuffer = substr(join('', @DeArr), 1);  # Step 10a  | 
| 
373
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if((length($OutputBuffer) % 2 ) == 1 )  # Step 10b  | 
| 
374
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			{ &DieOut("The output of LACEtoUCS4 for uncompressed input was " .  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				"an odd number of characters at step 10b.\n") }  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Step 11a  | 
| 
377
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$CompBuffer = ''; @LArr = split(//, $OutputBuffer); $LPtr = 0;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
378
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		do {  | 
| 
379
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$High = $LArr[$LPtr++];  # Step 3  | 
| 
380
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$RunCount = 1; $RunBuffer = $LArr[$LPtr++];  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
381
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			while(1) {  # Step 4  | 
| 
382
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				last if($LArr[$LPtr] ne $High);  | 
| 
383
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$LPtr +=1;  | 
| 
384
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$RunCount += 1;  | 
| 
385
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				$RunBuffer .= $LArr[$LPtr++];  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
387
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			$CompBuffer .= sprintf("%c", $RunCount) . $High .  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				$RunBuffer;  # Step 5  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		} while($LPtr <= $#LArr);  # Step 6  | 
| 
390
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		if(length($CompBuffer) <= length($OutputBuffer))  { # Step 11b  | 
| 
391
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			&DieOut("Wrong compression format found in LACEtoUCS4 step 11b.\n");  | 
| 
392
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		} else { $OutString = $OutputBuffer }  # Step 11c  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
394
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of output string:\n", &HexOut($OutString));  | 
| 
395
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(&CheckForSTD13Name($OutString))  | 
| 
396
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found all-STD13 name before output of LACEtoUCS4\n") }  | 
| 
397
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if(&CheckForBadSurrogates($OutString))  | 
| 
398
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found bad surrogate before output of LACEtoUCS4\n") }  | 
| 
399
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return utf16($OutString)->ucs4;  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub Base32Encode {  | 
| 
403
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
2
 | 
 	my($ToEncode) = shift(@_);  | 
| 
404
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	my ($i, $OutString, $CompBits, $FivePos, $FiveBitsString, $FiveIndex);  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
406
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	&DebugOut("Hex of input to Base32Encode:\n", &HexOut($ToEncode));  | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Turn the compressed string into a string that represents the bits as  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	#    0 and 1. This is wasteful of space but easy to read and debug.  | 
| 
410
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
 	$CompBits = '';  | 
| 
411
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	foreach $i (split(//, $ToEncode)) { $CompBits .= unpack("B8", $i) };  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Pad the value with enough 0's to make it a multiple of 5  | 
| 
414
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	if((length($CompBits) % 5) != 0)  | 
| 
415
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 		{ $CompBits .= '0' x (5 - (length($CompBits) % 5)) };  # Step 1a  | 
| 
416
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	&DebugOut("The compressed bits in Base32Encode after padding:\n"  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		. "$CompBits\n");  | 
| 
418
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
 	$FivePos = 0;  # Step 1b  | 
| 
419
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
 	do {  | 
| 
420
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 		$FiveBitsString = substr($CompBits, $FivePos, 5);  # Step 2  | 
| 
421
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 		$FiveIndex = unpack("N", pack("B32", ('0' x 27) . $FiveBitsString));  | 
| 
422
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 		$OutString .= substr($Base32Chars, $FiveIndex, 1);  # Step 3  | 
| 
423
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 		$FivePos += 5;  # Step 4a  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} until($FivePos == length($CompBits));  # Step 4b  | 
| 
425
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	&DebugOut("Output of Base32Encode:\n$OutString\n");  | 
| 
426
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	return $OutString;  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub Base32Decode {  | 
| 
430
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my ($ToDecode) = shift(@_);  | 
| 
431
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my ($InputCheck, $OutString, $DeCompBits, $DeCompIndex, @DeArr, $i,  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$PaddingLen, $PaddingContent);  | 
| 
433
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of input to Base32Decode:\n", &HexOut($ToDecode));  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
435
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$InputCheck = length($ToDecode) % 8;  # Step 1  | 
| 
436
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	if(($InputCheck == 1) or  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	   ($InputCheck == 3) or  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	   ($InputCheck == 6))  | 
| 
439
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Input to Base32Decode was a bad mod length: $InputCheck\n") }  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# $DeCompBits is a string that represents the bits as  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	#    0 and 1. This is wasteful of space but easy to read and debug.  | 
| 
443
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$DeCompBits = '';  | 
| 
444
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $InChar;  | 
| 
445
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	foreach $InChar (split(//, $ToDecode)) {   | 
| 
446
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$DeCompIndex = pack("N", index($Base32Chars, $InChar));  | 
| 
447
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$DeCompBits .= substr(unpack("B32", $DeCompIndex), 27);  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
449
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("The decompressed bits in Base32Decode:\n$DeCompBits\n");  | 
| 
450
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("The number of bits in Base32Decode: " ,  | 
| 
451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		length($DeCompBits), "\n");  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Step 5  | 
| 
454
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $Padding = length($DeCompBits) % 8;  | 
| 
455
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$PaddingContent = substr($DeCompBits, (length($DeCompBits) - $Padding));  | 
| 
456
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("The padding check in Base32Decode is \"$PaddingContent\"\n");  | 
| 
457
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unless(index($PaddingContent, '1') == -1)  | 
| 
458
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		{ &DieOut("Found non-zero padding in Base32Decode\n") }  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Break the decompressed string into octets for returning  | 
| 
461
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@DeArr = ();  | 
| 
462
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	for($i = 0; $i < int(length($DeCompBits) / 8); $i++) {  | 
| 
463
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$DeArr[$i] =  | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			chr(unpack("N", pack("B32", ('0' x 24) . substr($DeCompBits, $i * 8, 8))));  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
466
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$OutString = join('', @DeArr);  | 
| 
467
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	&DebugOut("Hex of the decompressed array:\n", &HexOut("$OutString"));  | 
| 
468
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return $OutString;  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub CheckForSTD13Name {  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# The input is in UTF-16  | 
| 
473
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
2
 | 
 	my $InCheck = shift(@_);  | 
| 
474
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
 	my (@CheckArr, $CheckPtr, $Lower, $Upper);  | 
| 
475
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
 	@CheckArr = split(//, $InCheck);  | 
| 
476
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	$CheckPtr = 0;  | 
| 
477
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 	my $STD13Chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYX' .  | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		'0123456789-';  | 
| 
479
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	until($CheckPtr > $#CheckArr) {  | 
| 
480
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$Upper = $CheckArr[$CheckPtr++];  | 
| 
481
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 		$Lower = $CheckArr[$CheckPtr++];  | 
| 
482
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
8
 | 
 		if(($Upper ne "\x00") or  | 
| 
483
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 			(index($STD13Chars, $Lower) == -1) ) { return 0 }  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
485
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return 1;  | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub CheckForBadSurrogates {  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# The input is in UTF-16  | 
| 
490
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	my $InCheck = shift(@_);  | 
| 
491
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my (@CheckArr, $CheckPtr, $Upper1, $Upper2);  | 
| 
492
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@CheckArr = split(//, $InCheck);  | 
| 
493
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$CheckPtr = 0;  | 
| 
494
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $HighSurr = "\xD8\xD9\xDA\xDB";  | 
| 
495
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $LowSurr = "\xDC\xDD\xDE\xDF";  | 
| 
496
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	until($CheckPtr > $#CheckArr) {  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		# Check for bad half-pair  | 
| 
498
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 		if((($CheckPtr + 2 ) >= $#CheckArr) and  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			(index($HighSurr.$LowSurr, $CheckArr[$CheckPtr]) > -1 )) {  | 
| 
500
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				&DebugOut("Found bad half-pair in CheckForBadSurrogates: " .  | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 					sprintf("%2.2x", ord($CheckArr[$CheckPtr])));  | 
| 
502
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				return 1;  | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
504
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		last unless(defined($CheckArr[$CheckPtr + 4]));  | 
| 
505
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$Upper1 = $CheckArr[$CheckPtr += 2];  | 
| 
506
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$Upper2 = $CheckArr[$CheckPtr += 2];  | 
| 
507
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 		if( ((index($HighSurr, $Upper1) > -1) and  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 (index($LowSurr, $Upper2) == -1))  | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			or  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			((index($HighSurr, $Upper1) == -1) and  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 (index($LowSurr, $Upper2) > -1))) {  | 
| 
512
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			&DebugOut("Found bad pair in CheckForBadSurrogates: " .  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				sprintf("%2.2x", ord($Upper1)) . " and " .  | 
| 
514
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 				sprintf("%2.2x", ord($Upper2)) . "\n");  | 
| 
515
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			return 1;  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
518
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return 0;  | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub HexOut {  | 
| 
522
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
0
  
 | 
6
 | 
 	my $AllInStr = shift(@_);  | 
| 
523
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	my($HexIn, $HexOut, @AllOrd, $i, $j, $k, $OutReg, $SpOut);  | 
| 
524
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my @HexIn;  | 
| 
525
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my($OctetIn, $LineCount);  | 
| 
526
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         my @OctetIn;  | 
| 
527
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 	my $OutString = '';  | 
| 
528
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	@AllOrd = split(//, $AllInStr);  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
530
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
 	$HexIn[23] = '';  | 
| 
531
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 	while(@AllOrd) {  | 
| 
532
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 		for($i = 0; $i < 24; $i++) {  | 
| 
533
 | 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
80
 | 
 			$OctetIn[$i] = shift(@AllOrd);  | 
| 
534
 | 
96
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
169
 | 
 			if(defined($OctetIn[$i])) {  | 
| 
535
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
53
 | 
 				$HexIn[$i] = sprintf('%2.2x', ord($OctetIn[$i]));  | 
| 
536
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
 				$LineCount = $i;  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			}  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
539
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 		for($j = 0; $j <= $LineCount; $j++ ) {  | 
| 
540
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
 			$HexOut .= $HexIn[$j];  | 
| 
541
 | 
42
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
 			if(($j % 4) == 3) { $HexOut .= ' ' }  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
542
 | 
42
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
90
 | 
 			if((ord($OctetIn[$j]) < 20) or (ord($OctetIn[$j]) > 126))  | 
| 
543
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
 				{ $OutReg .= '.' }  | 
| 
544
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
 			else { $OutReg .= $OctetIn[$j] }  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		}  | 
| 
546
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 		for ($k=length($HexOut); $k < 56; $k++) { $SpOut .= ' ' }  | 
| 
 
 | 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
178
 | 
    | 
| 
547
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
 		$OutString .= "$HexOut$SpOut$OutReg\n" ;  | 
| 
548
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
 		$HexOut = ''; $OutReg = ''; $SpOut = '';  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
550
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	return $OutString  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
553
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DebugOn {  | 
| 
554
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	$Debug = 1;  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DebugOff {  | 
| 
558
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 	$Debug = 0;  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
560
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DebugOut {  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Print out an error string if $Debug is set  | 
| 
563
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
0
  
 | 
12
 | 
 	my $DebugTemp = join('', @_);  | 
| 
564
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
 	if($Debug) { print STDERR $DebugTemp; }  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
565
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
567
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DieOut {  | 
| 
568
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
 
 | 
         my $DieTemp = shift(@_);  | 
| 
569
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #        if(defined($ErrTmp)) { print STDERR $DieTemp; }  | 
| 
570
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         die;  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
573
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
574
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |