File Coverage

blib/lib/XML/Encoding.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             ################################################################
2             # XML::Encoding
3             #
4             # Version 1.x Copyright 1998 Clark Cooper
5             # Changes in Version 2.00 onwards Copyright (C) 2007-2010 Steve Hay
6             # All rights reserved.
7             #
8             # This program is free software; you can redistribute it and/or
9             # modify it under the same terms as Perl itself.
10             #
11             # See pod documentation at the end of the file
12             #
13              
14             package XML::Encoding;
15              
16 1     1   23901 use 5.008001;
  1         4  
  1         52  
17              
18 1     1   408 use XML::Parser;
  0            
  0            
19              
20             use strict;
21             use vars qw(@ISA $VERSION);
22              
23             @ISA = qw(XML::Parser);
24             $VERSION = '2.09';
25              
26             sub new {
27             my $class = shift;
28             my $self = $class->SUPER::new(@_);
29              
30             # Maybe require setting of PushPrefixFcn, PopPrefixFcn, and RangeSetFcn
31              
32             $self->setHandlers(Start => \&start, End => \&end, Final => \&fini);
33             return $self;
34             }
35              
36             sub start {
37             my ($exp, $el, %attr) = @_;
38              
39             return if $exp->{EN_Skip};
40              
41             $exp->xpcroak("Root element must be encmap")
42             if ($exp->depth == 0 and $el ne 'encmap');
43              
44             my $xpmode = $exp->{EN_ExpatMode};
45              
46             if ($el eq 'ch'
47             or $el eq 'range')
48             {
49             my $byte = $attr{byte};
50             $exp->xpcroak("Missing required byte attribute")
51             unless defined($byte);
52              
53             $byte = cnvnumatt($exp, $byte, 'byte');
54             $exp->xpcroak("byte attribute > 255") if $byte > 255;
55              
56             my $uni = $attr{uni};
57             $exp->xpcroak("Missing required uni attribute")
58             unless defined($uni);
59              
60             $uni = cnvnumatt($exp, $uni, 'uni');
61             $exp->xpcroak("uni attribute > 0xFFFF") if $uni > 0xFFFF;
62              
63             my $len = 1;
64              
65             if ($el eq 'range') {
66             $len = $attr{len};
67             $exp->xpcroak("Missing required len attribute")
68             unless defined($len);
69              
70             $len = cnvnumatt($exp, $len, 'len');
71             $exp->xpcroak("Len plus byte > 256") if ($len + $byte) > 256;
72             }
73              
74             check_range($exp, $byte, $len, $uni)
75             if ($xpmode
76             and $byte < 128
77             and $byte != $uni
78             and not $exp->in_element('prefix'));
79              
80             my $range_set_fcn = $exp->{RangeSetFcn};
81             if (defined $range_set_fcn) {
82             my $result = &$range_set_fcn($byte, $uni, $len);
83             $exp->xpcroak($result)
84             if ($xpmode and $result);
85             }
86             }
87             elsif ($el eq 'prefix') {
88             $exp->xpcroak("prefix nested too deep")
89             if ($xpmode and $exp->within_element('prefix') >= 3);
90              
91             my $byte = $attr{byte};
92             $exp->xpcroak("Missing required byte attribute")
93             unless defined($byte);
94              
95             $byte = cnvnumatt($exp, $byte, 'byte');
96             $exp->xpcroak("byte attribute > 255") if $byte > 255;
97             my $push_pfx_fcn = $exp->{PushPrefixFcn};
98             if (defined $push_pfx_fcn) {
99             my $result = &$push_pfx_fcn($byte);
100             $exp->xpcroak($result)
101             if ($xpmode and $result);
102             }
103             }
104             elsif ($el eq 'encmap') {
105             my $name = $attr{name};
106              
107             $exp->xpcroak("Missing required name attribute")
108             unless defined($name);
109              
110             $exp->{EN_Name} = $name;
111              
112             my $expat = $attr{expat};
113             if (defined($expat)) {
114             $exp->xpcroak("Value of expat attribute should be yes or no")
115             unless ($expat eq 'yes' or $expat eq 'no');
116             $exp->{EN_ExpatMode} = $expat eq 'yes';
117             }
118             else {
119             $exp->{EN_ExpatMode} = 0;
120             }
121             $exp->xpcroak("Not an expat mode encmap")
122             if ($exp->{ExpatRequired} and ! $exp->{EN_ExpatMode});
123             }
124             else {
125             my $depth = $exp->depth;
126             $exp->xpcroak($exp, "Root element isn't encmap")
127             unless $depth;
128              
129             $exp->xpcarp("Skipping unrecognized element '$el'\n");
130             $exp->{EN_Skip} = $depth;
131             }
132              
133             } # End start
134              
135             sub end {
136             my ($exp, $el) = @_;
137              
138             if ($exp->{EN_Skip}) {
139             $exp->{EN_Skip} = 0
140             if $exp->{EN_Skip} == $exp->depth;
141             }
142             elsif ($el eq 'prefix') {
143             my $xpmode = $exp->{EN_ExpatMode};
144              
145             my $pop_pfx_fcn = $exp->{PopPrefixFcn};
146             if (defined $pop_pfx_fcn) {
147             my $result = &$pop_pfx_fcn();
148             $exp->xpcroak($result)
149             if ($xpmode and $result);
150             }
151             }
152             } # End end
153              
154             sub fini {
155             my ($exp) = @_;
156             $exp->{EN_Name};
157             } # End fini
158              
159             sub check_range {
160             my ($exp, $start, $len, $uni) = @_;
161              
162             # The following characters are exceptions to the expat rule that characters
163             # in the ascii set (ordinal values < 128) must have the same value in the
164             # source encoding: $@\^`{}~'
165             # The ordinal values for these are 36,92,94,96,123,125,126,39
166             # Any len >= 3 implies you have to be hitting some non-special
167             # For 2 just check start == 125 ('}')
168             # For 1 check individually.
169              
170             if ($len == 1) {
171             return if chr($start) =~ /[\$@\\^`{}~']/;
172             }
173             elsif ($len == 2 and $start == 125) {
174             return;
175             }
176              
177             $exp->xpcroak("Sets ascii character to non-ascii value");
178             }
179              
180             sub cnvnumatt {
181             my ($exp, $str, $name) = @_;
182              
183             $exp->xpcroak("$name attribute is not a decimal or hex value")
184             unless ($str =~ /^(?:(\d+)|x([0-9a-f]+))$/i);
185              
186             if (defined($1)) {
187             return $str + 0;
188             }
189             else {
190             return hex($2);
191             }
192             } # End cnvnumatt
193              
194             1;
195              
196             __END__