File Coverage

blib/lib/RPC/XML.pm
Criterion Covered Total %
statement 610 617 98.8
branch 137 144 95.1
condition 70 98 71.4
subroutine 106 106 100.0
pod 0 9 0.0
total 923 974 94.7


line stmt bran cond sub pod time code
1             ###############################################################################
2             #
3             # This file copyright (c) 2001-2014 Randy J. Ray, all rights reserved
4             #
5             # Copying and distribution are permitted under the terms of the Artistic
6             # License 2.0 (http://www.opensource.org/licenses/artistic-license-2.0.php) or
7             # the GNU LGPL (http://www.opensource.org/licenses/lgpl-2.1.php).
8             #
9             ###############################################################################
10             #
11             # Description: This module provides the core XML <-> RPC conversion and
12             # structural management.
13             #
14             # Functions: This module contains many, many subclasses. Better to
15             # examine them individually.
16             #
17             # Libraries: RPC::XML::base64 uses MIME::Base64
18             # DateTime::Format::ISO8601 is used if available
19             #
20             # Global Consts: $VERSION
21             #
22             ###############################################################################
23              
24             package RPC::XML;
25              
26 18     18   414659 use 5.008008;
  18         77  
  18         1796  
27 18     18   104 use strict;
  18         35  
  18         865  
28 18     18   168 use warnings;
  18         110  
  18         1107  
29 18         2960 use vars qw(@EXPORT_OK %EXPORT_TAGS $VERSION $ERROR
30             %XMLMAP $XMLRE $ENCODING $FORCE_STRING_ENCODING $ALLOW_NIL
31 18     18   96 $DATETIME_REGEXP $DATETIME_ISO8601_AVAILABLE);
  18         33  
32 18     18   14399 use subs qw(time2iso8601 smart_encode);
  18         278  
  18         665  
33 18     18   1242 use base 'Exporter';
  18         91  
  18         2152  
34              
35 18     18   15597 use Module::Load;
  18         20045  
  18         123  
36 18     18   1283 use Scalar::Util qw(blessed reftype);
  18         38  
  18         3503  
37              
38             # The RPC_* convenience-encoders need prototypes:
39             ## no critic (ProhibitSubroutinePrototypes)
40             # This module declares all the data-type packages:
41             ## no critic (ProhibitMultiplePackages)
42             # The data-type package names trigger this one:
43             ## no critic (Capitalization)
44              
45             BEGIN
46             {
47             # Default encoding:
48 18     18   45 $ENCODING = 'us-ascii';
49              
50             # force strings?
51 18         30 $FORCE_STRING_ENCODING = 0;
52              
53             # Allow the extension?
54 18         34 $ALLOW_NIL = 0;
55              
56             # Determine if the DateTime::Format::ISO8601 module is available for
57             # RPC::XML::datetime_iso8601 to use:
58 18         137 $DATETIME_ISO8601_AVAILABLE = eval { load DateTime::Format::ISO8601; 1; };
  18         83  
  18         5268135  
59             }
60              
61             @EXPORT_OK = qw(time2iso8601 smart_encode
62             RPC_BOOLEAN RPC_INT RPC_I4 RPC_I8 RPC_DOUBLE
63             RPC_DATETIME_ISO8601 RPC_BASE64 RPC_STRING RPC_NIL
64             $ENCODING $FORCE_STRING_ENCODING $ALLOW_NIL);
65             %EXPORT_TAGS = (types => [ qw(RPC_BOOLEAN RPC_INT RPC_I4 RPC_I8 RPC_DOUBLE
66             RPC_STRING RPC_DATETIME_ISO8601 RPC_BASE64
67             RPC_NIL) ],
68             all => [ @EXPORT_OK ]);
69              
70             $VERSION = '1.60';
71             $VERSION = eval $VERSION; ## no critic (ProhibitStringyEval)
72              
73             # Global error string
74             $ERROR = q{};
75              
76             # These are used for stringifying XML-sensitive characters that may appear
77             # in struct keys:
78             %XMLMAP = (
79             q{>} => '>',
80             q{<} => '<',
81             q{&} => '&',
82             q{"} => '"',
83             q{'} => ''',
84             "\x0d" => ' '
85             );
86             $XMLRE = join q{} => keys %XMLMAP; $XMLRE = qr/([$XMLRE])/;
87              
88             # The XMLRPC spec only allows for the incorrect iso8601 format
89             # without dashes, but dashes are part of the standard so we include
90             # them. Note that the actual RPC::XML::datetime_iso8601 class will strip
91             # them out if present.
92             my $date_re =
93             qr{
94             (\d{4})-?
95             ([01]\d)-?
96             ([0123]\d)
97             }x;
98             my $time_re =
99             qr{
100             ([012]\d):
101             ([0-5]\d):
102             ([0-5]\d)([.,]\d+)?
103             (Z|[-+]\d\d:\d\d)?
104             }x;
105             $DATETIME_REGEXP = qr{^${date_re}T?${time_re}$};
106              
107             # All of the RPC_* functions are convenience-encoders
108             sub RPC_STRING ($)
109             {
110 1     1 0 236 return RPC::XML::string->new(shift);
111             }
112             sub RPC_BOOLEAN ($)
113             {
114 1     1 0 9 return RPC::XML::boolean->new(shift);
115             }
116             sub RPC_INT ($)
117             {
118 1     1 0 10 return RPC::XML::int->new(shift);
119             }
120             sub RPC_I4 ($)
121             {
122 1     1 0 9 return RPC::XML::i4->new(shift);
123             }
124             sub RPC_I8 ($)
125             {
126 1     1 0 18 return RPC::XML::i8->new(shift);
127             }
128             sub RPC_DOUBLE ($)
129             {
130 1     1 0 11 return RPC::XML::double->new(shift);
131             }
132             sub RPC_DATETIME_ISO8601 ($)
133             {
134 1     1 0 10 return RPC::XML::datetime_iso8601->new(shift);
135             }
136             sub RPC_BASE64 ($;$)
137             {
138 1     1 0 9 return RPC::XML::base64->new(shift, shift);
139             }
140             sub RPC_NIL ()
141             {
142 2     2 0 21 return RPC::XML::nil->new();
143             }
144              
145             # This is a dead-simple ISO8601-from-UNIX-time stringifier. Always expresses
146             # time in UTC. The format isn't strictly ISO8601, though, as the XML-RPC spec
147             # fucked it up.
148             sub time2iso8601
149             {
150 2   66 2   2345 my $time = shift || time;
151              
152 2         51 my @time = gmtime $time;
153 2         23 $time = sprintf '%4d%02d%02dT%02d:%02d:%02dZ',
154             $time[5] + 1900, $time[4] + 1, @time[3, 2, 1, 0];
155              
156 2         11 return $time;
157             }
158              
159             # This is a (futile?) attempt to provide a "smart" encoding method that will
160             # take a Perl scalar and promote it to the appropriate RPC::XML::_type_.
161             {
162             my $MAX_INT = 2_147_483_647;
163             my $MIN_INT = -2_147_483_648;
164             my $MAX_BIG_INT = 9_223_372_036_854_775_807;
165             my $MIN_BIG_INT = -9_223_372_036_854_775_808;
166              
167             my $MAX_DOUBLE = 1e37;
168             my $MIN_DOUBLE = $MAX_DOUBLE * -1;
169              
170             sub smart_encode ## no critic (ProhibitExcessComplexity)
171             {
172 87     87   23209 my @values = @_;
173 87         125 my ($type, $seenrefs, @newvalues);
174              
175             # Look for sooper-sekrit pseudo-blessed hashref as first argument.
176             # It means this is a recursive call, and it contains a map of any
177             # references we've already seen.
178 87 100 100     709 if ((blessed $values[0]) && ($values[0]->isa('RPC::XML::refmap')))
179             {
180             # Peel it off of the list
181 34         53 $seenrefs = shift @values;
182             }
183             else
184             {
185             # Create one just in case we need it
186 53         221 $seenrefs = bless {}, 'RPC::XML::refmap';
187             }
188              
189 87         198 foreach (@values)
190             {
191 152 100 100     1926 if (! defined $_)
    100 66        
    100 66        
    100 100        
    100 100        
      100        
192             {
193 2 100       25 $type = $ALLOW_NIL ?
194             RPC::XML::nil->new() : RPC::XML::string->new(q{});
195             }
196             elsif (ref $_)
197             {
198             # Skip any that we've already seen
199 53 100       304 next if $seenrefs->{$_}++;
200              
201 49 100 100     549 if (blessed($_) &&
    100 66        
    100          
    100          
202             ($_->isa('RPC::XML::datatype') || $_->isa('DateTime')))
203             {
204             # Only if the reference is a datatype or a DateTime
205             # instance, do we short-cut here...
206              
207 27 100       88 if ($_->isa('RPC::XML::datatype'))
208             {
209             # Pass through any that have already been encoded
210 26         37 $type = $_;
211             }
212             else
213             {
214             # Must be a DateTime object, convert to ISO8601
215 1         7 $type = RPC::XML::datetime_iso8601
216             ->new($_->clone->set_time_zone('UTC'));
217             }
218             }
219             elsif (reftype($_) eq 'HASH')
220             {
221             # Per RT 41063, to catch circular refs I can't delegate
222             # to the struct constructor, I have to create my own
223             # copy of the hash with locally-recursively-encoded
224             # values
225 10         15 my %newhash;
226 10         16 for my $key (keys %{$_})
  10         37  
227             {
228             # Forcing this into a list-context *should* make the
229             # test be true even if the return value is a hard
230             # undef. Only if the return value is an empty list
231             # should this evaluate as false...
232 23 100       86 if (my @value = smart_encode($seenrefs, $_->{$key}))
233             {
234 22         63 $newhash{$key} = $value[0];
235             }
236             }
237              
238 10         61 $type = RPC::XML::struct->new(\%newhash);
239             }
240             elsif (reftype($_) eq 'ARRAY')
241             {
242             # This is a somewhat-ugly approach, but I don't want to
243             # dereference @$_, but I also want people to be able to
244             # pass array-refs in to this constructor and have them
245             # be treated as single elements, as one would expect
246             # (see RT 35106)
247             # Per RT 41063, looks like I get to deref $_ after all...
248 7         55 $type = RPC::XML::array->new(
249 7         11 from => [ smart_encode($seenrefs, @{$_}) ]
250             );
251             }
252             elsif (reftype($_) eq 'SCALAR')
253             {
254             # This is a rare excursion into recursion, since the scalar
255             # nature (de-refed from the object, so no longer magic)
256             # will prevent further recursing.
257 4         6 $type = smart_encode($seenrefs, ${$_});
  4         11  
258             }
259             else
260             {
261             # If the user passed in a reference that didn't pass one
262             # of the above tests, we can't do anything with it:
263 1         5 $type = reftype $_;
264 1         12 die "Un-convertable reference: $type, cannot use\n";
265             }
266 48         200 $seenrefs->{$_}--;
267             }
268             # You have to check ints first, because they match the
269             # next pattern (for doubles) too
270             elsif (! $FORCE_STRING_ENCODING &&
271             /^[-+]?\d+$/ &&
272             $_ >= $MIN_BIG_INT &&
273             $_ <= $MAX_BIG_INT)
274             {
275 53 100 100     264 if (($_ > $MAX_INT) || ($_ < $MIN_INT))
276             {
277 5         22 $type = RPC::XML::i8->new($_);
278             }
279             else
280             {
281 48         168 $type = RPC::XML::int->new($_);
282             }
283             }
284             # Pattern taken from perldata(1)
285             elsif (! $FORCE_STRING_ENCODING &&
286             /^[+-]?(?=\d|[.]\d)\d*(?:[.]\d*)?(?:[Ee](?:[+-]?\d+))?$/x &&
287             $_ > $MIN_DOUBLE &&
288             $_ < $MAX_DOUBLE)
289             {
290 4         20 $type = RPC::XML::double->new($_);
291             }
292             elsif (/$DATETIME_REGEXP/)
293             {
294 3         15 $type = RPC::XML::datetime_iso8601->new($_);
295             }
296             else
297             {
298 37         177 $type = RPC::XML::string->new($_);
299             }
300              
301 147         367 push @newvalues, $type;
302             }
303              
304 86 100       610 return (wantarray ? @newvalues : $newvalues[0]);
305             }
306             }
307              
308             # This is a (mostly) empty class used as a common superclass for simple and
309             # complex types, so that their derivatives may be universally type-checked.
310             package RPC::XML::datatype;
311              
312             sub type
313             {
314 130     130   29835 my $self = shift;
315              
316 130   33     1532 my $class = ref($self) || $self;
317 130         582 $class =~ s/.*://;
318              
319 130         500 return $class;
320             }
321              
322 1     1   5 sub is_fault { return 0; }
323              
324             ###############################################################################
325             #
326             # Package: RPC::XML::simple_type
327             #
328             # Description: A base class for the simpler type-classes to inherit from,
329             # for default constructor, stringification, etc.
330             #
331             ###############################################################################
332             package RPC::XML::simple_type;
333              
334 18     18   346 use strict;
  18         42  
  18         860  
335 18     18   109 use base 'RPC::XML::datatype';
  18         34  
  18         13543  
336              
337 18     18   138 use Scalar::Util 'reftype';
  18         36  
  18         10628  
338              
339             # new - a generic constructor that presumes the value being stored is scalar
340             sub new
341             {
342 126     126   20832 my $class = shift;
343 126         185 my $value = shift;
344              
345 126         196 $RPC::XML::ERROR = q{};
346 126   33     506 $class = ref($class) || $class;
347              
348 126 100       298 if ($class eq 'RPC::XML::simple_type')
349             {
350 1         4 $RPC::XML::ERROR = 'RPC::XML::simple_type::new: Cannot instantiate ' .
351             'this class directly';
352 1         4 return;
353             }
354              
355 125 100       473 if (ref $value)
356             {
357             # If it is a scalar reference, just deref
358 6 100       38 if (reftype($value) eq 'SCALAR')
359             {
360 5         8 $value = ${$value};
  5         13  
361             }
362             else
363             {
364             # We can only manage scalar references (or blessed scalar refs)
365 1         5 $RPC::XML::ERROR = "${class}::new: Cannot instantiate from a " .
366             'reference not derived from scalar';
367 1         4 return;
368             }
369             }
370              
371 124         480 return bless \$value, $class;
372             }
373              
374             # value - a generic accessor
375             sub value
376             {
377 131     131   108757 my $self = shift;
378              
379 131 100       421 if (! ref $self)
380             {
381 1         5 $RPC::XML::ERROR =
382             "{$self}::value: Cannot be called as a static method";
383 1         4 return;
384             }
385              
386 130         168 return ${$self};
  130         4954  
387             }
388              
389             # as_string - return the value as an XML snippet
390             sub as_string
391             {
392 164     164   783 my $self = shift;
393              
394 164         272 my $class = ref $self;
395 164 100       356 if (! $class)
396             {
397 1         5 $RPC::XML::ERROR =
398             "{$self}::as_string: Cannot be called as a static method";
399 1         5 return;
400             }
401 163         574 $class =~ s/^.*\://;
402 163         275 $class =~ s/_/./g;
403 163 100       439 if (substr($class, 0, 8) eq 'datetime')
404             {
405 11         21 substr $class, 0, 8, 'dateTime';
406             }
407              
408 163         369 return "<$class>${$self}";
  163         774  
409             }
410              
411             # Serialization for simple types is just a matter of sending as_string over
412             sub serialize
413             {
414 14     14   18 my ($self, $fh) = @_;
415              
416 14         28 utf8::encode(my $str = $self->as_string);
417 14         19 print {$fh} $str;
  14         151  
418              
419 14         25 return;
420             }
421              
422             # The switch to serialization instead of in-memory strings means having to
423             # calculate total size in bytes for Content-Length headers:
424             sub length ## no critic (ProhibitBuiltinHomonyms)
425             {
426 67     67   102 my $self = shift;
427              
428 67         135 utf8::encode(my $str = $self->as_string);
429              
430 67         213 return length $str;
431             }
432              
433             ###############################################################################
434             #
435             # Package: RPC::XML::int
436             #
437             # Description: Data-type class for integers
438             #
439             ###############################################################################
440             package RPC::XML::int;
441              
442 18     18   123 use strict;
  18         34  
  18         631  
443 18     18   95 use base 'RPC::XML::simple_type';
  18         32  
  18         10513  
444              
445             ###############################################################################
446             #
447             # Package: RPC::XML::i4
448             #
449             # Description: Data-type class for i4. Forces data into an int object.
450             #
451             ###############################################################################
452             package RPC::XML::i4;
453              
454 18     18   108 use strict;
  18         43  
  18         597  
455 18     18   100 use base 'RPC::XML::simple_type';
  18         34  
  18         9109  
456              
457             ###############################################################################
458             #
459             # Package: RPC::XML::i8
460             #
461             # Description: Data-type class for i8. Forces data into a 8-byte int.
462             #
463             ###############################################################################
464             package RPC::XML::i8;
465              
466 18     18   150 use strict;
  18         38  
  18         620  
467 18     18   96 use base 'RPC::XML::simple_type';
  18         33  
  18         9255  
468              
469             ###############################################################################
470             #
471             # Package: RPC::XML::double
472             #
473             # Description: The "double" type-class
474             #
475             ###############################################################################
476             package RPC::XML::double;
477              
478 18     18   131 use strict;
  18         35  
  18         630  
479 18     18   92 use base 'RPC::XML::simple_type';
  18         36  
  18         12270  
480              
481             sub as_string
482             {
483 15     15   33 my $self = shift;
484              
485 15 100       55 if (! ref $self)
486             {
487 1         5 $RPC::XML::ERROR =
488             "{$self}::as_string: Cannot be called as a static method";
489 1         6 return;
490             }
491 14         50 my $class = $self->type;
492              
493 14         30 (my $value = sprintf '%.20f', ${$self}) =~ s/([.]\d+?)0+$/$1/;
  14         250  
494              
495 14         104 return "<$class>$value";
496             }
497              
498             ###############################################################################
499             #
500             # Package: RPC::XML::string
501             #
502             # Description: The "string" type-class
503             #
504             ###############################################################################
505             package RPC::XML::string;
506              
507 18     18   123 use strict;
  18         34  
  18         590  
508 18     18   84 use base 'RPC::XML::simple_type';
  18         33  
  18         17999  
509              
510             # as_string - return the value as an XML snippet
511             sub as_string
512             {
513 57     57   87 my $self = shift;
514              
515 57         68 my ($class, $value);
516              
517 57 100       141 if (! ref $self)
518             {
519 1         5 $RPC::XML::ERROR =
520             "{$self}::as_string: Cannot be called as a static method";
521 1         45 return;
522             }
523 56         149 $class = $self->type;
524              
525 56 50       85 ($value = defined ${$self} ? ${$self} : q{} )
  56         137  
  56         230  
526 3         15 =~ s/$RPC::XML::XMLRE/$RPC::XML::XMLMAP{$1}/ge;
527              
528 56         294 return "<$class>$value";
529             }
530              
531             ###############################################################################
532             #
533             # Package: RPC::XML::boolean
534             #
535             # Description: The type-class for boolean data. Handles some "extra" cases
536             #
537             ###############################################################################
538             package RPC::XML::boolean;
539              
540 18     18   1327 use strict;
  18         51  
  18         631  
541 18     18   114 use base 'RPC::XML::simple_type';
  18         28  
  18         13328  
542              
543             # This constructor allows any of true, false, yes or no to be specified
544             sub new
545             {
546 8     8   2024 my $class = shift;
547 8   100     25 my $value = shift || 0;
548              
549 8         14 $RPC::XML::ERROR = q{};
550 8 100       51 if ($value =~ /true|yes|1/i)
    100          
551             {
552 4         8 $value = 1;
553             }
554             elsif ($value =~ /false|no|0/i)
555             {
556 3         7 $value = 0;
557             }
558             else
559             {
560 1   33     8 $class = ref($class) || $class;
561 1         5 $RPC::XML::ERROR = "${class}::new: Value must be one of yes, no, " .
562             'true, false, 1, 0 (case-insensitive)';
563 1         3 return;
564             }
565              
566 7         31 return bless \$value, $class;
567             }
568              
569             ###############################################################################
570             #
571             # Package: RPC::XML::datetime_iso8601
572             #
573             # Description: This is the class to manage ISO8601-style date/time values
574             #
575             ###############################################################################
576             package RPC::XML::datetime_iso8601;
577              
578 18     18   123 use strict;
  18         33  
  18         666  
579 18     18   138 use base 'RPC::XML::simple_type';
  18         37  
  18         9714  
580              
581 18     18   134 use Scalar::Util 'reftype';
  18         34  
  18         8940  
582              
583 7     7   1401 sub type { return 'dateTime.iso8601'; };
584              
585             # Check the value passed in for sanity, and normalize the string representation
586             sub new
587             {
588 70     70   40973 my ($class, $value) = @_;
589 70         162 my $newvalue;
590              
591 70 100 100     221 if (ref($value) && reftype($value) eq 'SCALAR')
592             {
593 1         2 $value = ${$value};
  1         3  
594             }
595              
596 70 100       156 if (defined $value)
597             {
598 69 100       528 if ($value =~ /$RPC::XML::DATETIME_REGEXP/)
    50          
599             {
600             # This is *not* a valid ISO 8601 format, but it's the way it is
601             # given in the spec, so assume that other implementations can only
602             # accept this form. Also, this should match the form that
603             # time2iso8601 produces.
604 10 100       120 $newvalue = $7 ? "$1$2$3T$4:$5:$6$7" : "$1$2$3T$4:$5:$6";
605 10 100       33 if ($8) {
606 6         13 $newvalue .= $8;
607             }
608             }
609             elsif ($RPC::XML::DATETIME_ISO8601_AVAILABLE)
610             {
611             $newvalue =
612 59         85 eval { DateTime::Format::ISO8601->parse_datetime($value) };
  59         267  
613 59 100       58263 if ($newvalue)
614             {
615             # This both removes the dashes (*sigh*) and forces it from an
616             # object to an ordinary string:
617 56         2377 $newvalue =~ s/-//g;
618             }
619             }
620              
621 69 100       2545 if (! $newvalue)
622             {
623 3         13 $RPC::XML::ERROR = "${class}::new: Malformed data ($value) " .
624             'passed as dateTime.iso8601';
625 3         11 return;
626             }
627             }
628             else
629             {
630 1         4 $RPC::XML::ERROR = "${class}::new: Value required in constructor";
631 1         4 return;
632             }
633              
634 66         326 return bless \$newvalue, $class;
635             }
636              
637             ###############################################################################
638             #
639             # Package: RPC::XML::nil
640             #
641             # Description: The "nil" type-class extension
642             #
643             ###############################################################################
644             package RPC::XML::nil;
645              
646 18     18   119 use strict;
  18         37  
  18         807  
647 18     18   103 use base 'RPC::XML::simple_type';
  18         54  
  18         13072  
648              
649             # no value need be passed to this method
650             sub new
651             {
652 6     6   2004 my ($class, $value, $flag) = @_;
653             # We need $value so we can bless a reference to it. But regardless of
654             # what was passed, it needs to be undef to be a proper "nil".
655 6         10 undef $value;
656              
657 6 50 66     27 if (! $RPC::XML::ALLOW_NIL && ! $flag)
658             {
659 1         6 $RPC::XML::ERROR = "${class}::new: \$RPC::XML::ALLOW_NIL must be set" .
660             ' for RPC::XML::nil objects to be supported';
661 1         3 return;
662             }
663              
664 5         25 return bless \$value, $class;
665             }
666              
667             # Stringification and serialsation are trivial..
668             sub as_string
669             {
670 9     9   1036 return '';
671             }
672              
673             sub serialize
674             {
675 1     1   2 my ($self, $fh) = @_;
676              
677 1         1 print {$fh} $self->as_string; # In case someone sub-classes this
  1         4  
678              
679 1         2 return;
680             }
681              
682             ###############################################################################
683             #
684             # Package: RPC::XML::array
685             #
686             # Description: This class encapsulates the array data type. Each element
687             # within the array should be one of the datatype classes.
688             #
689             ###############################################################################
690             package RPC::XML::array;
691              
692 18     18   126 use strict;
  18         310  
  18         569  
693 18     18   103 use base 'RPC::XML::datatype';
  18         39  
  18         10247  
694              
695 18     18   202 use Scalar::Util qw(blessed reftype);
  18         41  
  18         9018  
696              
697             # The constructor for this class mainly needs to sanity-check the value data
698             sub new
699             {
700 10     10   2183 my ($class, @args) = @_;
701              
702             # Special-case time: If the args-list has exactly two elements, and the
703             # first element is "from" and the second element is an array-ref (or a
704             # type derived from), then copy the ref's contents into @args.
705 10 50 66     122 if ((2 == @args) && ($args[0] eq 'from') && (reftype($args[1]) eq 'ARRAY'))
      66        
706             {
707 8         13 @args = @{$args[1]};
  8         24  
708             }
709              
710             # Ensure that each argument passed in is itself one of the data-type
711             # class instances.
712 10         31 return bless [ RPC::XML::smart_encode(@args) ], $class;
713             }
714              
715             # This became more complex once it was shown that there may be a need to fetch
716             # the value while preserving the underlying objects.
717             sub value
718             {
719 10     10   5214 my $self = shift;
720 10   100     56 my $no_recurse = shift || 0;
721 10         15 my $ret;
722              
723 10 100       26 if ($no_recurse)
724             {
725 2         6 $ret = [ @{$self} ];
  2         9  
726             }
727             else
728             {
729 8         14 $ret = [ map { $_->value } @{$self} ];
  30         81  
  8         38  
730             }
731              
732 10         83 return $ret;
733             }
734              
735             sub as_string
736             {
737 7     7   19 my $self = shift;
738              
739 49         115 return join q{},
740             '',
741 7         18 (map { ('', $_->as_string(), '') } (@{$self})),
  7         22  
742             '';
743             }
744              
745             # Serialization for arrays is not as straight-forward as it is for simple
746             # types. One or more of the elements may be a base64 object, which has a
747             # non-trivial serialize() method. Thus, rather than just sending the data from
748             # as_string down the pipe, instead call serialize() recursively on all of the
749             # elements.
750             sub serialize
751             {
752 1     1   3 my ($self, $fh) = @_;
753              
754 1         2 print {$fh} '';
  1         15  
755 1         2 for (@{$self})
  1         4  
756             {
757 3         6 print {$fh} '';
  3         35  
758 3         8 $_->serialize($fh);
759 3         4 print {$fh} '';
  3         33  
760             }
761 1         2 print {$fh} '';
  1         11  
762              
763 1         2 return;
764             }
765              
766             # Length calculation starts to get messy here, due to recursion
767             sub length ## no critic (ProhibitBuiltinHomonyms)
768             {
769 3     3   8 my $self = shift;
770              
771             # Start with the constant components in the text
772 3         7 my $len = 28; # That the part
773 3         6 for (@{$self}) { $len += (15 + $_->length) } # 15 is for
  3         10  
  23         48  
774              
775 3         24 return $len;
776             }
777              
778             ###############################################################################
779             #
780             # Package: RPC::XML::struct
781             #
782             # Description: This is the "struct" data class. The struct is like Perl's
783             # hash, with the constraint that all values are instances
784             # of the datatype classes.
785             #
786             ###############################################################################
787             package RPC::XML::struct;
788              
789 18     18   115 use strict;
  18         34  
  18         642  
790 18     18   90 use base 'RPC::XML::datatype';
  18         38  
  18         10991  
791              
792 18     18   121 use Scalar::Util qw(blessed reftype);
  18         48  
  18         19793  
793              
794             # The constructor for this class mainly needs to sanity-check the value data
795             sub new
796             {
797 20     20   2255 my ($class, @args) = @_;
798 14         64 my %args = (ref $args[0] and reftype($args[0]) eq 'HASH') ?
799 20 100 66     233 %{$args[0]} : @args;
800              
801             # RT 41063: If all the values are datatype objects, either they came in
802             # that way or we've already laundered them through smart_encode(). If there
803             # is even one that isn't, then we have to pass the whole mess to be
804             # encoded.
805 46   66     361 my $ref =
806 20 100       55 (grep { ! (blessed($_) && $_->isa('RPC::XML::datatype')) } values %args)
807             ? RPC::XML::smart_encode(\%args) : \%args;
808              
809 20         94 return bless $ref, $class;
810             }
811              
812             # This became more complex once it was shown that there may be a need to fetch
813             # the value while preserving the underlying objects.
814             sub value
815             {
816 12     12   7009 my $self = shift;
817 12   100     61 my $no_recurse = shift || 0;
818 12         19 my %value;
819              
820 12 100       33 if ($no_recurse)
821             {
822 4         7 %value = map { ($_, $self->{$_}) } (keys %{$self});
  8         32  
  4         13  
823             }
824             else
825             {
826 8         13 %value = map { ($_, $self->{$_}->value) } (keys %{$self});
  18         105  
  8         60  
827             }
828              
829 12         61 return \%value;
830             }
831              
832             sub as_string
833             {
834 12     12   858 my $self = shift;
835 12         16 my $key;
836              
837             # Clean the keys of $self, in case they have any HTML-special characters
838             my %clean;
839 12         21 for (keys %{$self})
  12         47  
840             {
841 24         112 ($key = $_) =~ s/$RPC::XML::XMLRE/$RPC::XML::XMLMAP{$1}/ge;
  7         23  
842 24         426 $clean{$key} = $self->{$_}->as_string;
843             }
844              
845 24         296 return join q{},
846             '',
847             (map {
848 12         39 ("$_",
849             $clean{$_},
850             '')
851             } (keys %clean)),
852             '';
853             }
854              
855             # As with the array type, serialization here isn't cut and dried, since one or
856             # more values may be base64.
857             sub serialize
858             {
859 2     2   4 my ($self, $fh) = @_;
860 2         12 my $key;
861              
862 2         3 print {$fh} '';
  2         21  
863 2         4 for (keys %{$self})
  2         6  
864             {
865 3         13 ($key = $_) =~ s/$RPC::XML::XMLRE/$RPC::XML::XMLMAP{$1}/ge;
  0         0  
866 3         7 utf8::encode($key);
867 3         4 print {$fh} "$key";
  3         32  
868 3         12 $self->{$_}->serialize($fh);
869 3         3 print {$fh} '';
  3         34  
870             }
871 2         3 print {$fh} '';
  2         20  
872              
873 2         4 return;
874             }
875              
876             # Length calculation is a real pain here. But not as bad as base64 promises
877             sub length ## no critic (ProhibitBuiltinHomonyms)
878             {
879 5     5   11 my $self = shift;
880              
881 5         14 my $len = 17; #
882 5         21 for my $key (keys %{$self})
  5         18  
883             {
884 9         12 $len += 45; # For all the constant XML presence
885 9         31 $len += $self->{$key}->length;
886 9         21 utf8::encode($key);
887 9         19 $len += length $key;
888             }
889              
890 5         23 return $len;
891             }
892              
893             ###############################################################################
894             #
895             # Package: RPC::XML::base64
896             #
897             # Description: This is the base64-encoding type. Plain data is passed in,
898             # plain data is returned. Plain is always returned. All the
899             # encoding/decoding is done behind the scenes.
900             #
901             ###############################################################################
902             package RPC::XML::base64;
903              
904 18     18   134 use strict;
  18         38  
  18         660  
905 18     18   97 use base 'RPC::XML::datatype';
  18         34  
  18         10162  
906              
907 18     18   164 use Scalar::Util 'reftype';
  18         37  
  18         25740  
908              
909             sub new
910             {
911 14     14   24499 my ($class, $value, $encoded) = @_;
912              
913 14         1109 require MIME::Base64;
914              
915 14         824 my $self = {};
916              
917 14         39 $RPC::XML::ERROR = q{};
918              
919 14 100       69 $self->{encoded} = $encoded ? 1 : 0; # Is this already Base-64?
920 14         34 $self->{inmem} = 0; # To signal in-memory vs. filehandle
921              
922             # First, determine if the call sent actual data, a reference to actual
923             # data, or an open filehandle.
924 14 100 100     123 if (ref $value and reftype($value) eq 'GLOB')
925             {
926             # This is a seekable filehandle (or acceptable substitute thereof).
927             # This assignment increments the ref-count, and prevents destruction
928             # in other scopes.
929 8         25 binmode $value;
930 8         18 $self->{value_fh} = $value;
931 8         22 $self->{fh_pos} = tell $value;
932             }
933             else
934             {
935             # Not a filehandle. Might be a scalar ref, but other than that it's
936             # in-memory data.
937 6         14 $self->{inmem}++;
938 6 100 100     38 $self->{value} = ref($value) ? ${$value} : ($value || q{});
  1         4  
939             # We want in-memory data to always be in the clear, to reduce the tests
940             # needed in value(), below.
941 6 100       28 if ($self->{encoded})
942             {
943 1         5 local $^W = 0; # Disable warnings in case the data is underpadded
944 1         7 $self->{value} = MIME::Base64::decode_base64($self->{value});
945 1         4 $self->{encoded} = 0;
946             }
947             }
948              
949 14         72 return bless $self, $class;
950             }
951              
952             sub value
953             {
954 26     26   5773 my ($self, $flag) = @_;
955 26 100 66     140 my $as_base64 = (defined $flag and $flag) ? 1 : 0;
956              
957             # There are six cases here, based on whether or not the data exists in
958             # Base-64 or clear form, and whether the data is in-memory or needs to be
959             # read from a filehandle.
960 26 100       104 if ($self->{inmem})
961             {
962             # This is simplified into two cases (rather than four) since we always
963             # keep in-memory data as cleartext
964 11 100       108 return $as_base64 ?
965             MIME::Base64::encode_base64($self->{value}, q{}) : $self->{value};
966             }
967             else
968             {
969             # This is trickier with filehandle-based data, since we chose not to
970             # change the state of the data. Thus, the behavior is dependant not
971             # only on $as_base64, but also on $self->{encoded}. This is why we
972             # took pains to explicitly set $as_base64 to either 0 or 1, rather than
973             # just accept whatever non-false value the caller sent. It makes this
974             # first test possible.
975 15         20 my ($accum, $pos, $res);
976 15         21 $accum = q{};
977              
978 15         38 $self->{fh_pos} = tell $self->{value_fh};
979 15         91 seek $self->{value_fh}, 0, 0;
980 15 100       37 if ($as_base64 == $self->{encoded})
981             {
982 7         11 $pos = 0;
983 7         193 while ($res = read $self->{value_fh}, $accum, 1024, $pos)
984             {
985 14         74 $pos += $res;
986             }
987             }
988             else
989             {
990 8 100       55 if ($as_base64)
991             {
992             # We're reading cleartext and converting it to Base-64. Read in
993             # multiples of 57 bytes for best Base-64 calculation. The
994             # choice of 60 for the multiple is purely arbitrary.
995 6         10 $res = q{};
996 6         148 while (read $self->{value_fh}, $res, 60*57)
997             {
998 6         185 $accum .= MIME::Base64::encode_base64($res, q{});
999             }
1000             }
1001             else
1002             {
1003             # Reading Base-64 and converting it back to cleartext. If the
1004             # Base-64 data doesn't have any line-breaks, no telling how
1005             # much memory this will eat up.
1006 2         7 local $^W = 0; # Disable padding-length warnings
1007 2         4 $pos = $self->{value_fh};
1008 2         32 while (defined($res = <$pos>))
1009             {
1010 2         15 $accum .= MIME::Base64::decode_base64($res);
1011             }
1012             }
1013             }
1014 15         82 seek $self->{value_fh}, $self->{fh_pos}, 0;
1015              
1016 15         218 return $accum;
1017             }
1018             }
1019              
1020             # The value needs to be encoded before being output
1021             sub as_string
1022             {
1023 18     18   2874 my $self = shift;
1024              
1025 18         48 return '' . $self->value('encoded') . '';
1026             }
1027              
1028             # If it weren't for Tellme and their damnable WAV files, and ViAir and their
1029             # half-baked XML-RPC server, I wouldn't have to do any of this...
1030             #
1031             # (On the plus side, at least here I don't have to worry about encodings...)
1032             sub serialize
1033             {
1034 3     3   5 my ($self, $fh) = @_;
1035              
1036             # If the data is in-memory, just call as_string and pass it down the pipe
1037 3 100       10 if ($self->{inmem})
1038             {
1039 1         3 print {$fh} $self->as_string;
  1         5  
1040             }
1041             else
1042             {
1043             # If it's a filehandle, at least we take comfort in knowing that we
1044             # always want Base-64 at this level.
1045 2         3 my $buf = q{};
1046 2         12 $self->{fh_pos} = tell $self->{value_fh};
1047 2         12 seek $self->{value_fh}, 0, 0;
1048 2         3 print {$fh} '';
  2         19  
1049 2 100       7 if ($self->{encoded})
1050             {
1051             # Easy-- just use read() to send it down in palatably-sized chunks
1052 1         19 while (read $self->{value_fh}, $buf, 4096)
1053             {
1054 1         2 print {$fh} $buf;
  1         12  
1055             }
1056             }
1057             else
1058             {
1059             # This actually requires work. As with value(), the 60*57 is based
1060             # on ideal Base-64 chunks, with the 60 part being arbitrary.
1061 1         21 while (read $self->{value_fh}, $buf, 60*57)
1062             {
1063 1         2 print {$fh} MIME::Base64::encode_base64($buf, q{});
  1         25  
1064             }
1065             }
1066 2         2 print {$fh} '';
  2         17  
1067 2         10 seek $self->{value_fh}, $self->{fh_pos}, 0;
1068             }
1069              
1070 3         6 return;
1071             }
1072              
1073             # This promises to be a big enough pain that I seriously considered opening
1074             # an anon-temp file (one that's unlinked for security, and survives only as
1075             # long as the FH is open) and passing that to serialize just to -s on the FH.
1076             # But I'll do this the "right" way instead...
1077             sub length ## no critic (ProhibitBuiltinHomonyms)
1078             {
1079 5     5   10 my $self = shift;
1080              
1081             # Start with the constant bits
1082 5         9 my $len = 17; #
1083              
1084 5 100       18 if ($self->{inmem})
1085             {
1086             # If it's in-memory, it's cleartext. Size the encoded version
1087 2         10 $len += length(MIME::Base64::encode_base64($self->{value}, q{}));
1088             }
1089             else
1090             {
1091 3 100       4924 if ($self->{encoded})
1092             {
1093             # We're lucky, it's already encoded in the file, and -s will do
1094 1         7 $len += -s $self->{value_fh};
1095             }
1096             else
1097             {
1098             # Oh bugger. We have to encode it.
1099 2         99 my $buf = q{};
1100 2         13 my $cnt = 0;
1101              
1102 2         13 $self->{fh_pos} = tell $self->{value_fh};
1103 2         34 seek $self->{value_fh}, 0, 0;
1104 2         63 while ($cnt = read $self->{value_fh}, $buf, 60*57)
1105             {
1106 2         42 $len += length(MIME::Base64::encode_base64($buf, q{}));
1107             }
1108 2         16 seek $self->{value_fh}, $self->{fh_pos}, 0;
1109             }
1110             }
1111              
1112 5         28 return $len;
1113             }
1114              
1115             # This allows writing the decoded data to an arbitrary file. It's useful when
1116             # an application has gotten a RPC::XML::base64 object back from a request, and
1117             # knows that it needs to go straight to a file without being completely read
1118             # into memory, first.
1119             sub to_file
1120             {
1121 5     5   6795 my ($self, $file) = @_;
1122              
1123 5         18 my ($fh, $buf, $do_close, $count) = (undef, q{}, 0, 0);
1124              
1125 5 100       18 if (ref $file)
1126             {
1127 2 100       17 if (reftype($file) eq 'GLOB')
1128             {
1129 1         4 $fh = $file;
1130             }
1131             else
1132             {
1133 1         4 $RPC::XML::ERROR = 'Unusable reference type passed to to_file';
1134 1         5 return -1;
1135             }
1136             }
1137             else
1138             {
1139 3 50       637 if (! open $fh, '>', $file) ## no critic (RequireBriefOpen)
1140             {
1141 0         0 $RPC::XML::ERROR = "Error opening $file for writing: $!";
1142 0         0 return -1;
1143             }
1144 3         122 binmode $fh;
1145 3         44 $do_close++;
1146             }
1147              
1148             # If all the data is in-memory, then we know that it's clear, and we
1149             # don't have to jump through hoops in moving it to the filehandle.
1150 4 100       18 if ($self->{inmem})
1151             {
1152 2         5 print {$fh} $self->{value};
  2         60  
1153 2         6 $count = CORE::length($self->{value});
1154             }
1155             else
1156             {
1157             # Filehandle-to-filehandle transfer.
1158              
1159             # Now determine if the data can be copied over directly, or if we have
1160             # to decode it along the way.
1161 2         6 $self->{fh_pos} = tell $self->{value_fh};
1162 2         16 seek $self->{value_fh}, 0, 0;
1163 2 100       9 if ($self->{encoded})
1164             {
1165             # As with the caveat in value(), if the base-64 data doesn't have
1166             # any line-breaks, no telling how much memory this will eat up.
1167 1         7 local $^W = 0; # Disable padding-length warnings
1168 1         4 my $tmp_fh = $self->{value_fh};
1169 1         26 while (defined($_ = <$tmp_fh>))
1170             {
1171 32         393 $buf = MIME::Base64::decode_base64($_);
1172 32         44 print {$fh} $buf;
  32         66  
1173 32         97 $count += CORE::length($buf);
1174             }
1175             }
1176             else
1177             {
1178             # If the data is already decoded in the filehandle, then just copy
1179             # it over.
1180 1         2 my $size;
1181 1         23 while ($size = read $self->{value_fh}, $buf, 4096)
1182             {
1183 1         3 print {$fh} $buf;
  1         21  
1184 1         7 $count += $size;
1185             }
1186             }
1187              
1188             # Restore the position of the file-pointer for the internal FH
1189 2         17 seek $self->{value_fh}, $self->{fh_pos}, 0;
1190             }
1191              
1192 4 100       15 if ($do_close)
1193             {
1194 3 50       207 if (! close $fh)
1195             {
1196 0         0 $RPC::XML::ERROR = "Error closing $file after writing: $!";
1197 0         0 return -1;
1198             }
1199             }
1200              
1201 4         29 return $count;
1202             }
1203              
1204             ###############################################################################
1205             #
1206             # Package: RPC::XML::fault
1207             #
1208             # Description: This is the class that encapsulates the data for a RPC
1209             # fault-response. Like the others, it takes the relevant
1210             # information and maintains it internally. This is put
1211             # at the end of the datum types, though it isn't really a
1212             # data type in the sense that it cannot be passed in to a
1213             # request. But it is separated so as to better generalize
1214             # responses.
1215             #
1216             ###############################################################################
1217             package RPC::XML::fault;
1218              
1219 18     18   127 use strict;
  18         57  
  18         727  
1220 18     18   98 use base 'RPC::XML::struct';
  18         51  
  18         10815  
1221              
1222 18     18   119 use Scalar::Util 'blessed';
  18         40  
  18         10181  
1223              
1224             # For our new(), we only need to ensure that we have the two required members
1225             sub new
1226             {
1227 6     6   3445 my ($class, @args) = @_;
1228              
1229 6         9 my %args;
1230              
1231 6         13 $RPC::XML::ERROR = q{};
1232 6 50 33     1111 if (blessed $args[0] and $args[0]->isa('RPC::XML::struct'))
    100 100        
      66        
1233             {
1234             # Take the keys and values from the struct object as our own
1235 0         0 %args = %{$args[0]->value('shallow')};
  0         0  
1236             }
1237             elsif ((@args == 2) && ($args[0] =~ /^-?\d+$/) && length $args[1])
1238             {
1239             # This is a special convenience-case to make simple new() calls clearer
1240 3         21 %args = (faultCode => RPC::XML::int->new($args[0]),
1241             faultString => RPC::XML::string->new($args[1]));
1242             }
1243             else
1244             {
1245 3         11 %args = @args;
1246             }
1247              
1248 6 100 66     42 if (! ($args{faultCode} and $args{faultString}))
1249             {
1250 1   33     6 $class = ref($class) || $class;
1251 1         3 $RPC::XML::ERROR = "${class}::new: Missing required struct fields";
1252 1         5 return;
1253             }
1254 5 100       18 if (scalar(keys %args) > 2)
1255             {
1256 1   33     7 $class = ref($class) || $class;
1257 1         4 $RPC::XML::ERROR = "${class}::new: Extra struct fields not allowed";
1258 1         5 return;
1259             }
1260              
1261 4         35 return $class->SUPER::new(%args);
1262             }
1263              
1264             # This only differs from the display of a struct in that it has some extra
1265             # wrapped around it. Let the superclass as_string method do most of the work.
1266             sub as_string
1267             {
1268 4     4   8 my $self = shift;
1269              
1270 4         24 return '' . $self->SUPER::as_string . '';
1271             }
1272              
1273             # Again, only differs from struct in that it has some extra wrapped around it.
1274             sub serialize
1275             {
1276 1     1   2 my ($self, $fh) = @_;
1277              
1278 1         2 print {$fh} '';
  1         12  
1279 1         14 $self->SUPER::serialize($fh);
1280 1         2 print {$fh} '';
  1         11  
1281              
1282 1         3 return;
1283             }
1284              
1285             # Because of the slight diff above, length() has to be different from struct
1286             sub length ## no critic (ProhibitBuiltinHomonyms)
1287             {
1288 2     2   4 my $self = shift;
1289              
1290 2         17 return $self->SUPER::length + 30; # For constant XML content
1291             }
1292              
1293             # Convenience methods:
1294 1     1   542 sub code { return shift->{faultCode}->value; }
1295 1     1   6 sub string { return shift->{faultString}->value; }
1296              
1297             # This is the only one to override this method, for obvious reasons
1298 1     1   4 sub is_fault { return 1; }
1299              
1300             ###############################################################################
1301             #
1302             # Package: RPC::XML::request
1303             #
1304             # Description: This is the class that encapsulates the data for a RPC
1305             # request. It takes the relevant information and maintains
1306             # it internally until asked to stringify. Only then is the
1307             # XML generated, encoding checked, etc. This allows for
1308             # late-selection of or as a
1309             # containing tag.
1310             #
1311             # This class really only needs a constructor and a method
1312             # to stringify.
1313             #
1314             ###############################################################################
1315             package RPC::XML::request;
1316              
1317 18     18   120 use strict;
  18         36  
  18         838  
1318              
1319 18     18   127 use Scalar::Util 'blessed';
  18         32  
  18         29359  
1320              
1321             ###############################################################################
1322             #
1323             # Sub Name: new
1324             #
1325             # Description: Creating a new request object, in this (reference) case,
1326             # means checking the list of arguments for sanity and
1327             # packaging it up for later use.
1328             #
1329             # Arguments: NAME IN/OUT TYPE DESCRIPTION
1330             # $class in scalar Class/ref to bless into
1331             # @argz in list The exact disposition of the
1332             # arguments is based on the
1333             # type of the various elements
1334             #
1335             # Returns: Success: object ref
1336             # Failure: undef, error in $RPC::XML::ERROR
1337             #
1338             ###############################################################################
1339             sub new
1340             {
1341 8     8   5110 my ($class, @argz) = @_;
1342              
1343 8         14 my $name;
1344              
1345 8   33     65 $class = ref($class) || $class;
1346 8         18 $RPC::XML::ERROR = q{};
1347              
1348 8 100       26 if (! @argz)
1349             {
1350 1         3 $RPC::XML::ERROR = 'RPC::XML::request::new: At least a method name ' .
1351             'must be specified';
1352 1         3 return;
1353             }
1354              
1355             # This is the method name to be called
1356 7         14 $name = shift @argz;
1357             # Is it valid?
1358 7 100       51 if ($name !~ m{^[\w.:/]+$})
1359             {
1360 1         3 $RPC::XML::ERROR =
1361             'RPC::XML::request::new: Invalid method name specified';
1362 1         4 return;
1363             }
1364              
1365             # All the remaining args must be data.
1366 6         28 @argz = RPC::XML::smart_encode(@argz);
1367              
1368 6         50 return bless { args => [ @argz ], name => $name }, $class;
1369             }
1370              
1371             # Accessor methods
1372 1     1   477 sub name { return shift->{name}; }
1373 6     6   46 sub args { return shift->{args}; }
1374              
1375             ###############################################################################
1376             #
1377             # Sub Name: as_string
1378             #
1379             # Description: This is a fair bit more complex than the simple as_string
1380             # methods for the datatypes. Express the invoking object as
1381             # a well-formed XML document.
1382             #
1383             # Arguments: NAME IN/OUT TYPE DESCRIPTION
1384             # $self in ref Invoking object
1385             # $indent in scalar Indention level for output
1386             #
1387             # Returns: Success: text
1388             # Failure: undef
1389             #
1390             ###############################################################################
1391             sub as_string
1392             {
1393 8     8   29 my $self = shift;
1394              
1395 8         13 my $text;
1396              
1397 8         17 $RPC::XML::ERROR = q{};
1398              
1399 8         26 $text = qq();
1400              
1401 8         49 $text .= "$self->{name}";
1402 8         21 for (@{$self->{args}})
  8         21  
1403             {
1404 55         158 $text .= '' . $_->as_string . '';
1405             }
1406 8         19 $text .= '';
1407              
1408 8         264 return $text;
1409             }
1410              
1411             # The difference between stringifying and serializing a request is much like
1412             # the difference was for structs and arrays. The boilerplate is the same, but
1413             # the destination is different in a sensitive way.
1414             sub serialize
1415             {
1416 1     1   3 my ($self, $fh) = @_;
1417 1         5 utf8::encode(my $name = $self->{name});
1418              
1419 1         1 print {$fh} qq();
  1         66  
1420              
1421 1         2 print {$fh} "$name";
  1         12  
1422 1         3 for (@{$self->{args}})
  1         5  
1423             {
1424 11         15 print {$fh} '';
  11         104  
1425 11         60 $_->serialize($fh);
1426 11         12 print {$fh} '';
  11         101  
1427             }
1428 1         2 print {$fh} '';
  1         9  
1429              
1430 1         3 return;
1431             }
1432              
1433             # Compared to base64, length-calculation here is pretty easy, much like struct
1434             sub length ## no critic (ProhibitBuiltinHomonyms)
1435             {
1436 2     2   4 my $self = shift;
1437              
1438 2         7 my $len = 100 + length $RPC::XML::ENCODING; # All the constant XML present
1439 2         10 utf8::encode(my $name = $self->{name});
1440 2         4 $len += length $name;
1441              
1442 2         4 for (@{$self->{args}})
  2         6  
1443             {
1444 21         23 $len += 30; # Constant XML
1445 21         81 $len += $_->length;
1446             }
1447              
1448 2         18 return $len;
1449             }
1450              
1451             ###############################################################################
1452             #
1453             # Package: RPC::XML::response
1454             #
1455             # Description: This is the class that encapsulates the data for a RPC
1456             # response. As above, it takes the information and maintains
1457             # it internally until asked to stringify. Only then is the
1458             # XML generated, encoding checked, etc. This allows for
1459             # late-selection of or
1460             # as above.
1461             #
1462             ###############################################################################
1463             package RPC::XML::response;
1464              
1465 18     18   143 use strict;
  18         39  
  18         658  
1466              
1467 18     18   114 use Scalar::Util 'blessed';
  18         46  
  18         19451  
1468              
1469             ###############################################################################
1470             #
1471             # Sub Name: new
1472             #
1473             # Description: Creating a new response object, in this (reference) case,
1474             # means checking the outgoing parameter(s) for sanity.
1475             #
1476             # Arguments: NAME IN/OUT TYPE DESCRIPTION
1477             # $class in scalar Class/ref to bless into
1478             # @argz in list The exact disposition of the
1479             # arguments is based on the
1480             # type of the various elements
1481             #
1482             # Returns: Success: object ref
1483             # Failure: undef, error in $RPC::XML::ERROR
1484             #
1485             ###############################################################################
1486             sub new
1487             {
1488 8     8   1047 my ($class, @argz) = @_;
1489              
1490 8   33     40 $class = ref($class) || $class;
1491              
1492 8         14 $RPC::XML::ERROR = q{};
1493 8 100       30 if (! @argz)
    100          
1494             {
1495 1         3 $RPC::XML::ERROR = 'RPC::XML::response::new: One of a datatype, ' .
1496             'value or a fault object must be specified';
1497 1         4 return;
1498             }
1499             elsif (@argz > 1)
1500             {
1501 1         2 $RPC::XML::ERROR = 'RPC::XML::response::new: Responses may take ' .
1502             'only one argument';
1503 1         4 return;
1504             }
1505              
1506 6         20 $argz[0] = RPC::XML::smart_encode($argz[0]);
1507              
1508 6         30 return bless { value => $argz[0] }, $class;
1509             }
1510              
1511             # Accessor/status methods
1512 2     2   480 sub value { return shift->{value}; }
1513 2     2   504 sub is_fault { return shift->{value}->is_fault; }
1514              
1515             ###############################################################################
1516             #
1517             # Sub Name: as_string
1518             #
1519             # Description: This is a fair bit more complex than the simple as_string
1520             # methods for the datatypes. Express the invoking object as
1521             # a well-formed XML document.
1522             #
1523             # Arguments: NAME IN/OUT TYPE DESCRIPTION
1524             # $self in ref Invoking object
1525             # $indent in scalar Indention level for output
1526             #
1527             # Returns: Success: text
1528             # Failure: undef
1529             #
1530             ###############################################################################
1531             sub as_string
1532             {
1533 13     13   70 my $self = shift;
1534              
1535 13         14 my $text;
1536              
1537 13         17 $RPC::XML::ERROR = q{};
1538              
1539 13         24 $text = qq();
1540              
1541 13         20 $text .= '';
1542 13 100       78 if ($self->{value}->isa('RPC::XML::fault'))
1543             {
1544 2         7 $text .= $self->{value}->as_string;
1545             }
1546             else
1547             {
1548 11         27 $text .= '' . $self->{value}->as_string .
1549             '';
1550             }
1551 13         21 $text .= '';
1552              
1553 13         60 return $text;
1554             }
1555              
1556             # See the comment for serialize() above in RPC::XML::request
1557             sub serialize
1558             {
1559 4     4   9 my ($self, $fh) = @_;
1560              
1561 4         6 print {$fh} qq();
  4         177  
1562              
1563 4         8 print {$fh} '';
  4         41  
1564 4 100       28 if ($self->{value}->isa('RPC::XML::fault'))
1565             {
1566             # A fault lacks the params-boilerplate
1567 1         4 $self->{value}->serialize($fh);
1568             }
1569             else
1570             {
1571 3         6 print {$fh} '';
  3         38  
1572 3         13 $self->{value}->serialize($fh);
1573 3         3 print {$fh} '';
  3         27  
1574             }
1575 4         5 print {$fh} '';
  4         39  
1576              
1577 4         9 return;
1578             }
1579              
1580             # Compared to base64, length-calculation here is pretty easy, much like struct
1581             sub length ## no critic (ProhibitBuiltinHomonyms)
1582             {
1583 5     5   8 my $self = shift;
1584              
1585 5         8 my $len = 66 + length $RPC::XML::ENCODING; # All the constant XML present
1586              
1587             # This boilerplate XML is only present when it is NOT a fault
1588 5 100       37 if (! $self->{value}->isa('RPC::XML::fault'))
1589             {
1590 4         5 $len += 47;
1591             }
1592              
1593 5         29 $len += $self->{value}->length;
1594              
1595 5         22 return $len;
1596             }
1597              
1598             1;
1599              
1600             __END__