File Coverage

blib/lib/WDDX/Parser.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             #!/usr/bin/perl -w
2             #
3             # $Id: Parser.pm,v 1.1.1.1 2003/10/28 16:04:37 andy Exp $
4             #
5             # This code is copyright 1999-2000 by Scott Guelich
6             # and is distributed according to the same conditions as Perl itself
7             # Please visit http://www.scripted.com/wddx/ for more information
8             #
9              
10             package WDDX::Parser;
11              
12             # Auto-inserted by build scripts
13             $VERSION = "1.01";
14              
15 3     3   15 use strict;
  3         6  
  3         98  
16 3     3   3414 use XML::Parser;
  0            
  0            
17              
18             require WDDX;
19              
20             ## Necessary??
21             # die "WDDX.pm Requires XML::Parser 2.x or greater"
22             # unless $XML::Parser::VERSION >= 2;
23              
24             # This creates a tainted empty string (well, unless someone has
25             # untainted $0) see &taint at bottom
26             $WDDX::Parser::TAINTED = substr( $0, 0, 0 );
27              
28             { my $i_hate_the_w_flag_sometimes = [
29             $XML::Parser::VERSION,
30             $WDDX::Parser::TAINTED,
31             \@WDDX::Data_Types,
32             $WDDX::Parser::VERSION
33             ] }
34              
35             1;
36              
37              
38             #/-----------------------------------------------------------------------
39             # Public Constructor
40             #
41              
42             # Takes no parameters
43             sub new {
44             my( $class ) = @_;
45             my $self = {
46             data => undef,
47             meta_tags => [ qw(
48             ) ],
49             };
50            
51             bless $self, $class;
52             return $self;
53             }
54              
55              
56             # This starts the whole process rolling...
57             # Takes one parameter containing a WDDX Packet in either a string
58             # or open IO::Handle (i.e. file handle or socket)
59             sub parse {
60             my( $self, $arg ) = @_;
61             my $p = new XML::Parser(
62             Handlers => {
63             Start => sub { $self->start_handler( @_ ) }, # closures...
64             End => sub { $self->end_handler ( @_ ) }, # isn't
65             Char => sub { $self->char_handler ( @_ ) }, # perl
66             Final => sub { $self->final_handler( @_ ) }, # cool?
67             } );
68            
69             $p->parse( $arg );
70            
71             return $self->root_var;
72             }
73              
74              
75             #/-----------------------------------------------------------------------
76             # Private Handlers for XML::Parser
77             #
78              
79             # Start of XML tag
80             sub start_handler {
81             my( $self, $expat, $element, %attribs ) = @_;
82            
83             # Force lowercase for element and attrib names
84             $element = taint( lc $element );
85             %attribs = map { taint( lc $_ ), taint( $attribs{$_} ) } keys %attribs;
86            
87             eval {
88            
89             if ( $element eq "wddxpacket" or
90             $element eq "header" or
91             $element eq "data" ) {
92             $self->update_status( "<$element>" );
93             }
94            
95             else {
96             my $root_var = $self->root_var;
97            
98             unless ( $root_var ) {
99             $root_var = $self->create_var( $element ) or
100             die "Expecting some data type element (e.g., ), " .
101             "found: <$element>\n";
102             $self->root_var( $root_var );
103             }
104             $root_var->start_tag( $element, \%attribs );
105             }
106            
107             };
108             if ( $@ ) {
109             $self->parse_err( $expat, $@ );
110             }
111             }
112              
113             # End of XML tag
114             sub end_handler {
115             my( $self, $expat, $element ) = @_;
116             $element = taint( lc $element );
117            
118             eval {
119            
120             if ( $element eq "wddxpacket" or
121             $element eq "header" or
122             $element eq "data" ) {
123             $self->update_status( "" );
124             }
125            
126             else {
127             my $root_var = $self->root_var or
128             die "Found before <$element>\n";
129            
130             $self->root_var( $root_var->end_tag( $element ) );
131             }
132            
133             };
134             if ( $@ ) {
135             $self->parse_err( $expat, $@ );
136             }
137             }
138              
139              
140             # Characters within and between tags
141             sub char_handler {
142             my( $self, $expat, $text ) = @_;
143             my $root_var = $self->root_var;
144            
145             $text = taint( $text );
146            
147             unless ( $root_var && $root_var->is_parser ) {
148             return unless $text =~ /\S/; # ignore whitespace
149             die "Illegal text outside of tags\n";
150             }
151            
152             eval {
153             $root_var->append_data( $text );
154             };
155             if ( $@ ) {
156             $self->parse_err( $expat, $@ );
157             }
158             }
159              
160              
161             # Final validation
162             sub final_handler {
163             my( $self, $expat ) = @_;
164            
165             # This error appears even if other tags are missing too
166             unless ( $self->complete ) {
167             $self->parse_err( $expat,
168             "Incomplete packet: no tag found" );
169             }
170             }
171              
172              
173             #/-----------------------------------------------------------------------
174             # Private Helper Subs & Methods
175             #
176              
177             sub parse_err {
178             my( $self, $expat, $err_msg ) = @_;
179             my $line = $expat->current_line;
180            
181             die "Error deserializing line $line of WDDX packet,\n$err_msg\n";
182             }
183              
184              
185             # Returns the top level var object we're parsing in this packet
186             # Sets this attribute if it's passed a value
187             sub root_var {
188             my( $self, $var ) = @_;
189            
190             $self->{data} = $var if $var;
191             return $self->{data};
192             }
193              
194              
195             # This simplifies the process of creating WDDX::* objects
196             # Can be called as a class method
197             sub create_var {
198             my( $this, $element ) = @_;
199            
200             return undef unless grep $_ eq $element, @WDDX::Data_Types;
201             my( $untainted_element ) = $element =~ /(\w+)/ or
202             die "Invalid data type name!";
203             my $new_var = eval "new WDDX::\u${untainted_element}::Parser()";
204             die $@ if $@;
205             return $new_var;
206             }
207              
208              
209             # Checks given tag against next one on the queue of expected meta tags
210             sub update_status {
211             my( $self, $tag ) = @_;
212             my $expected_tag = shift @{ $self->{meta_tags} };
213            
214             unless ( $tag eq $expected_tag ) {
215             die "Found $tag before $expected_tag\n";
216             }
217             }
218              
219              
220             # Checks if anything left on the queue of expected meta tags
221             sub complete {
222             my( $self ) = @_;
223             return ( @{ $self->{meta_tags} } ? 0 : 1 );
224             }
225              
226              
227             # Ack, XML::Parser untaints data!!! This is a kludge to retaint it...
228             sub taint {
229             return shift() . $WDDX::Parser::TAINTED;
230             }