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