File Coverage

blib/lib/IETF/ACE.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


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