File Coverage

blib/lib/WAP/wbxml/WbRules.pm
Criterion Covered Total %
statement 16 161 9.9
branch 0 66 0.0
condition 0 41 0.0
subroutine 6 17 35.2
pod n/a
total 22 285 7.7


line stmt bran cond sub pod time code
1            
2 1     1   5 use strict;
  1         2  
  1         31  
3 1     1   5 use warnings;
  1         2  
  1         124  
4            
5             package WAP::wbxml::Token;
6            
7             sub new {
8 0     0     my $proto = shift;
9 0   0       my $class = ref($proto) || $proto;
10 0           my $self = {};
11 0           bless $self, $class;
12 0           my ($token, $codepage) = @_;
13 0           $self->{ext_token} = 256 * hex($codepage) + hex($token);
14 0           return $self;
15             }
16            
17             package WAP::wbxml::TagToken;
18            
19 1     1   5 use base qw(WAP::wbxml::Token);
  1         2  
  1         687  
20            
21             sub new {
22 0     0     my $proto = shift;
23 0   0       my $class = ref($proto) || $proto;
24 0           my ($token, $name, $codepage, $encoding) = @_;
25 0           my $self = new WAP::wbxml::Token($token, $codepage);
26 0           bless $self, $class;
27 0           $self->{name} = $name;
28 0 0         $self->{encoding} = $encoding if ($encoding ne q{});
29 0           return $self;
30             }
31            
32             package WAP::wbxml::AttrStartToken;
33            
34 1     1   5 use base qw(WAP::wbxml::Token);
  1         2  
  1         691  
35            
36             sub new {
37 0     0     my $proto = shift;
38 0   0       my $class = ref($proto) || $proto;
39 0           my ($token, $name, $value, $codepage, $default, $fixed, $validate, $encoding) = @_;
40 0           my $self = new WAP::wbxml::Token($token, $codepage);
41 0           bless $self, $class;
42 0           $self->{name} = $name;
43 0 0         $self->{value} = $value if ($value ne q{});
44 0 0         $self->{default} = $default if ($default ne q{});
45 0 0         $self->{fixed} = $fixed if ($fixed ne q{});
46 0 0         $self->{validate} = $validate if ($validate ne q{});
47 0 0         $self->{encoding} = $encoding if ($encoding ne q{});
48 0           return $self;
49             }
50            
51             package WAP::wbxml::AttrValueToken;
52            
53 1     1   7 use base qw(WAP::wbxml::Token);
  1         1  
  1         1900  
54            
55             sub new {
56 0     0     my $proto = shift;
57 0   0       my $class = ref($proto) || $proto;
58 0           my ($token, $value, $codepage) = @_;
59 0           my $self = new WAP::wbxml::Token($token, $codepage);
60 0           bless $self, $class;
61 0           $self->{value} = $value;
62 0           return $self;
63             }
64            
65             package WAP::wbxml::ExtValue;
66            
67             sub new {
68 0     0     my $proto = shift;
69 0   0       my $class = ref($proto) || $proto;
70 0           my $self = {};
71 0           bless $self, $class;
72 0           my ($index, $value) = @_;
73 0           $self->{index} = hex($index);
74 0           $self->{value} = $value;
75 0           return $self;
76             }
77            
78             package WAP::wbxml::WbRulesApp;
79            
80             sub new {
81 0     0     my $proto = shift;
82 0   0       my $class = ref($proto) || $proto;
83 0           my $self = {};
84 0           bless $self, $class;
85 0           my ($publicid, $use_default, $variable_subs, $textual_ext, $tokenised_ext, $xml_space) = @_;
86 0           $self->{publicid} = $publicid;
87 0           $self->{skipDefault} = $use_default eq 'yes';
88 0           $self->{variableSubs} = $variable_subs eq 'yes';
89 0   0       $self->{textualExt} = $textual_ext || 'xml';
90 0   0       $self->{tokenisedExt} = $tokenised_ext || 'wbxml';
91 0   0       $self->{xmlSpace} = $xml_space || 'preserve';
92 0           $self->{TagTokens} = [];
93 0           $self->{AttrStartTokens} = [];
94 0           $self->{AttrValueTokens} = [];
95 0           return $self;
96             }
97            
98             sub getTag {
99 0     0     my $self = shift;
100 0           my ($tagname, $curr_page) = @_;
101 0 0         if ($tagname) {
102 0           my @found = ();
103 0           foreach (@{$self->{TagTokens}}) {
  0            
104 0 0         if ($tagname eq $_->{name}) {
105             # print "Tag $_->{name}.\n";
106 0 0         if ($_->{ext_token} / 256 == $curr_page) {
107 0           return $_;
108             }
109             else {
110 0           push @found, $_;
111             }
112             }
113             }
114 0 0         if (scalar @found) {
115 0           return shift @found;
116             }
117             }
118 0           return undef;
119             }
120            
121             sub getAttrStart {
122 0     0     my $self = shift;
123 0           my ($name, $value, $curr_page) = @_;
124 0           my $best = undef;
125 0           my $remain = $value;
126 0 0         if ($name) {
127 0           my $max_len = -1;
128 0           foreach (@{$self->{AttrStartTokens}}) {
  0            
129 0 0         if ($name eq $_->{name}) {
130 0 0         if (exists $_->{value}) {
131 0           my $attr_value = $_->{value};
132 0           my $len = length $attr_value;
133 0 0 0       if ( ($attr_value eq $value) or
      0        
134             ($len < length $value and $attr_value eq substr($value, 0, $len)) ) {
135 0 0         if ($len > $max_len) {
    0          
136 0           $max_len = $len;
137 0           $best = $_;
138             }
139             elsif ($len == $max_len) {
140 0 0         if ($_->{ext_token} / 256 == $curr_page) {
141 0           $best = $_;
142             }
143             }
144             }
145             }
146             else {
147 0 0         if ($max_len == -1) {
    0          
148 0           $max_len = 0;
149 0           $best = $_;
150             }
151             elsif ($max_len == 0) {
152 0 0         if ($_->{ext_token} / 256 == $curr_page) {
153 0           $best = $_;
154             }
155             }
156             }
157             }
158             }
159 0 0 0       if ($best and $max_len != -1) {
160 0           $remain = substr $remain, $max_len;
161             # if (exists $best->{value}) {
162             # print "AttrStart : $best->{name} $best->{value}.\n";
163             # }
164             # else {
165             # print "AttrStart : $best->{name}.\n";
166             # }
167             }
168             }
169 0           return ($best, $remain);
170             }
171            
172             sub getAttrValue {
173 0     0     my $self = shift;
174 0           my ($start, $curr_page) = @_;
175 0           my $best = undef;
176 0           my $end = q{};
177 0 0         if ($start ne q{}) {
178 0           my $max_len = 0;
179 0           my $best_found = length $start;
180 0           foreach (@{$self->{AttrValueTokens}}) {
  0            
181 0           my $value = $_->{value};
182 0 0         if ($value ne q{}) {
183 0           my $len = length $value;
184 0           my $found = index $start, $value;
185 0 0         if ($found >= 0) {
186 0 0         if ($found == $best_found) {
    0          
187 0 0         if ($len > $max_len) {
    0          
188 0           $max_len = $len;
189 0           $best = $_;
190             }
191             elsif ($len == $max_len) {
192 0 0         if ($_->{ext_token} / 256 == $curr_page) {
193 0           $best = $_;
194             }
195             }
196             }
197             elsif ($found < $best_found) {
198 0           $best = $_;
199 0           $best_found = $found;
200 0           $max_len = $len;
201             }
202             }
203             }
204             }
205 0 0         if ($best) {
206 0           $end = substr $start, $best_found+$max_len;
207 0           $start = substr $start, 0, $best_found;
208             # print "AttrValue : $best->{value} ($start, $end).\n";
209             }
210             }
211 0           return ($best, $start, $end);
212             }
213            
214             sub getExtValue {
215 0     0     my $self = shift;
216 0           my ($value, $ext) = @_;
217 0 0 0       if ($value and exists $self->{$ext} and scalar $self->{$ext}) {
      0        
218 0           foreach (@{$self->{$ext}}) {
  0            
219 0 0         if ($value eq $_->{value}) {
220             # print "ExtValue : $value\n";
221 0           return $_->{index} ;
222             }
223             }
224             }
225 0           return undef;
226             }
227            
228             package WAP::wbxml::WbRules;
229            
230             sub new {
231 0     0     my $proto = shift;
232 0   0       my $class = ref($proto) || $proto;
233 0           my $self = {};
234 0           bless $self, $class;
235 0           my ($version) = @_;
236 0 0         if ($version =~ /(\d+)\.(\d+)/) {
237 0           $self->{version} = 16 * ($1 - 1) + $2;
238             }
239             else {
240 0           $self->{version} = 0x03; # WBXML 1.3 : latest known version
241             }
242 0           $self->{PublicIdentifiers} = {};
243 0           $self->{App} = {};
244 0           $self->{DefaultApp} = new WAP::wbxml::WbRulesApp('DEFAULT', q{}, q{}, q{}, q{}, q{});
245 0           return $self;
246             }
247            
248             package WAP::wbxml::constructVisitor;
249 1     1   1702 use XML::DOM;
  0            
  0            
250            
251             sub new {
252             my $proto = shift;
253             my $class = ref($proto) || $proto;
254             my $self = {};
255             bless $self, $class;
256             my ($doc) = @_;
257             $self->{doc} = $doc;
258             return $self;
259             }
260            
261             sub visitwbxml {
262             my $self = shift;
263             my ($parent) = @_;
264             my $version = $parent->getAttribute('version');
265             $self->{wbrules} = new WAP::wbxml::WbRules($version);
266             for (my $node = $parent->getFirstChild();
267             $node;
268             $node = $node->getNextSibling() ) {
269             if ($node->getNodeType() == ELEMENT_NODE) {
270             $self->{doc}->visitElement($node, $self);
271             }
272             }
273             }
274            
275             sub visitCharacterSets {
276             # empty
277             }
278            
279             sub visitPublicIdentifiers {
280             my $self = shift;
281             my ($parent) = @_;
282             for (my $node = $parent->getFirstChild();
283             $node;
284             $node = $node->getNextSibling() ) {
285             if ($node->getNodeType() == ELEMENT_NODE) {
286             $self->{doc}->visitElement($node, $self);
287             }
288             }
289             }
290            
291             sub visitPublicIdentifier {
292             my $self = shift;
293             my ($node) = @_;
294             my $name = $node->getAttribute('name');
295             my $value = $node->getAttribute('value'); # hexadecimal
296             $self->{wbrules}->{PublicIdentifiers}->{$name} = hex $value;
297             }
298            
299             sub visitApp {
300             my $self = shift;
301             my ($parent) = @_;
302             my $publicid = $parent->getAttribute('publicid');
303             my $use_default = $parent->getAttribute('use-default');
304             my $variable_subs = $parent->getAttribute('variable-subs');
305             my $textual_ext = $parent->getAttribute('textual-ext');
306             my $tokenised_ext = $parent->getAttribute('tokenised-ext');
307             my $xml_space = $parent->getAttribute('xml-space');
308             my $app = new WAP::wbxml::WbRulesApp($publicid, $use_default, $variable_subs, $textual_ext, $tokenised_ext, $xml_space);
309             $self->{wbrules}->{App}->{$publicid} = $app;
310             $self->{wbrulesapp} = $app;
311             for (my $node = $parent->getFirstChild();
312             $node;
313             $node = $node->getNextSibling() ) {
314             if ($node->getNodeType() == ELEMENT_NODE) {
315             $self->{doc}->visitElement($node, $self);
316             }
317             }
318             }
319            
320             sub visitTagTokens {
321             my $self = shift;
322             my ($parent) = @_;
323             for (my $node = $parent->getFirstChild();
324             $node;
325             $node = $node->getNextSibling() ) {
326             if ($node->getNodeType() == ELEMENT_NODE) {
327             $self->{doc}->visitElement($node, $self);
328             }
329             }
330             }
331            
332             sub visitTAG {
333             my $self = shift;
334             my ($node) = @_;
335             my $token = $node->getAttribute('token');
336             my $name = $node->getAttribute('name');
337             my $codepage = $node->getAttribute('codepage');
338             my $encoding = $node->getAttribute('encoding');
339             my $tag = new WAP::wbxml::TagToken($token, $name, $codepage, $encoding);
340             push @{$self->{wbrulesapp}->{TagTokens}}, $tag;
341             }
342            
343             sub visitAttrStartTokens {
344             my $self = shift;
345             my ($parent) = @_;
346             for (my $node = $parent->getFirstChild();
347             $node;
348             $node = $node->getNextSibling() ) {
349             if ($node->getNodeType() == ELEMENT_NODE) {
350             $self->{doc}->visitElement($node, $self);
351             }
352             }
353             }
354            
355             sub visitATTRSTART {
356             my $self = shift;
357             my ($node) = @_;
358             my $token = $node->getAttribute('token');
359             my $name = $node->getAttribute('name');
360             my $value = $node->getAttribute('value');
361             my $codepage = $node->getAttribute('codepage');
362             my $default = $node->getAttribute('default');
363             my $fixed = $node->getAttribute('fixed');
364             my $validate = $node->getAttribute('validate');
365             my $encoding = $node->getAttribute('encoding');
366             my $tag = new WAP::wbxml::AttrStartToken($token, $name, $value, $codepage, $default, $fixed, $validate, $encoding);
367             push @{$self->{wbrulesapp}->{AttrStartTokens}}, $tag;
368             }
369            
370             sub visitAttrValueTokens {
371             my $self = shift;
372             my ($parent) = @_;
373             for (my $node = $parent->getFirstChild();
374             $node;
375             $node = $node->getNextSibling() ) {
376             if ($node->getNodeType() == ELEMENT_NODE) {
377             $self->{doc}->visitElement($node, $self);
378             }
379             }
380             }
381            
382             sub visitATTRVALUE {
383             my $self = shift;
384             my ($node) = @_;
385             my $token = $node->getAttribute('token');
386             my $value = $node->getAttribute('value');
387             my $codepage = $node->getAttribute('codepage');
388             my $tag = new WAP::wbxml::AttrValueToken($token, $value, $codepage);
389             push @{$self->{wbrulesapp}->{AttrValueTokens}}, $tag;
390             }
391            
392             sub visitExt0Values {
393             my $self = shift;
394             my ($parent) = @_;
395             for (my $node = $parent->getFirstChild();
396             $node;
397             $node = $node->getNextSibling() ) {
398             if ($node->getNodeType() == ELEMENT_NODE) {
399             $self->{doc}->visitElement($node, $self, 'Ext0Values');
400             }
401             }
402             }
403            
404             sub visitExt1Values {
405             my $self = shift;
406             my ($parent) = @_;
407             for (my $node = $parent->getFirstChild();
408             $node;
409             $node = $node->getNextSibling() ) {
410             if ($node->getNodeType() == ELEMENT_NODE) {
411             $self->{doc}->visitElement($node, $self, 'Ext1Values');
412             }
413             }
414             }
415            
416             sub visitExt2Values {
417             my $self = shift;
418             my ($parent) = @_;
419             for (my $node = $parent->getFirstChild();
420             $node;
421             $node = $node->getNextSibling() ) {
422             if ($node->getNodeType() == ELEMENT_NODE) {
423             $self->{doc}->visitElement($node, $self, 'Ext0Values');
424             }
425             }
426             }
427            
428             sub visitEXTVALUE {
429             my $self = shift;
430             my ($node, $ext) = @_;
431             my $index = $node->getAttribute('index');
432             my $value = $node->getAttribute('value');
433             my $tag = new WAP::wbxml::ExtValue($index, $value);
434             push @{$self->{wbrulesapp}->{$ext}}, $tag;
435             }
436            
437             sub visitCharacterEntities {
438             my $self = shift;
439             my ($parent) = @_;
440             for (my $node = $parent->getFirstChild();
441             $node;
442             $node = $node->getNextSibling() ) {
443             if ($node->getNodeType() == ELEMENT_NODE) {
444             $self->{doc}->visitElement($node, $self);
445             }
446             }
447             }
448            
449             sub visitCharacterEntity {
450             my $self = shift;
451             my ($node) = @_;
452             my $code = $node->getAttribute('code');
453             my $name = $node->getAttribute('name');
454             $self->{wbrulesapp}->{CharacterEntity}{$name} = $code;
455             }
456            
457             package WAP::wbxml::doc;
458            
459             use XML::DOM;
460            
461             sub new {
462             my $proto = shift;
463             my $class = ref($proto) || $proto;
464             my $self = {};
465             bless $self, $class;
466             my ($file) = @_;
467             my $parser = new XML::DOM::Parser;
468             eval { $self->{doc} = $parser->parsefile($file); };
469             die $@ if ($@);
470             return undef unless ($self->{doc});
471             $self->{root} = $self->{doc}->getDocumentElement();
472             return $self;
473             }
474            
475             sub visitElement {
476             my $self = shift;
477             my $node = shift;
478             my $visitor = shift;
479             my $name = $node->getNodeName();
480             $name =~ s/^wbxml://; # backward compat
481             my $func = 'visit' . $name;
482             if($visitor->can($func)) {
483             $visitor->$func($node, @_);
484             }
485             else {
486             warn "unknown element '$name'\n";
487             }
488             }
489            
490             package WAP::wbxml::WbRules;
491            
492             =head1 NAME
493            
494             WAP::wbxml::WbRules
495            
496             =head1 DESCRIPTION
497            
498             =over 4
499            
500             =item Load
501            
502             $rules = WbRules::Load( [PATH] );
503            
504             Loads rules from PATH.
505            
506             WAP/wap.wbrules.pl is a serialized version (Data::Dumper).
507            
508             WAP/wap.wbrules.xml supplies rules for WAP files, but it could extended to over XML applications.
509            
510             =back
511            
512             =cut
513            
514             sub Load {
515             my ($path) = @_;
516             my $config;
517             my $persistance;
518            
519             if ($path) {
520             $config = $path;
521             $persistance = $path;
522             $persistance =~ s/\.\w+$//;
523             $persistance .= '.pl';
524             }
525             else {
526             $path = $INC{'WAP/wbxml.pm'};
527             $path =~ s/\.pm$//i;
528             $persistance = $path . '/wap.wbrules.pl';
529             $config = $path . '/wap.wbrules.xml';
530             }
531            
532             my @st_config = stat($config);
533             die "can't found original rules ($config).\n" unless (@st_config);
534             my @st_persistance = stat($persistance);
535             if (@st_persistance) {
536             if ($st_config[9] > $st_persistance[9]) { # mtime
537             print "$persistance needs update\n";
538             die "can't unlink serialized rules ($persistance).\n"
539             unless (unlink $persistance);
540             }
541             }
542             use vars qw($rules);
543             do $persistance;
544             unless (ref $rules eq 'WAP::wbxml::WbRules') {
545             use Data::Dumper;
546             print "parse rules\n";
547             my $doc = new WAP::wbxml::doc($config);
548             if ($doc) {
549             use POSIX qw(ctime);
550             my $visitor = new WAP::wbxml::constructVisitor($doc);
551             $doc->visitElement($doc->{root}, $visitor);
552             $rules = $visitor->{wbrules};
553             $doc = undef;
554             my $d = Data::Dumper->new([$rules], [qw($rules)]);
555             # $d->Indent(1);
556             $d->Indent(0);
557             if (open my $PERSISTANCE, '>', $persistance) {
558             print $PERSISTANCE "# This file is generated. DO NOT modify it.\n";
559             print $PERSISTANCE "# From file : ",$config,"\n";
560             print $PERSISTANCE "# Generation date : ",POSIX::ctime(time());
561             print $PERSISTANCE $d->Dump();
562             close $PERSISTANCE;
563             }
564             else {
565             warn "cannot open '$persistance': $!\n";
566             }
567             }
568             else {
569             $WAP::wbxml::WbRules::rules = new WAP::wbxml::WbRules(q{});
570             }
571             }
572             return $WAP::wbxml::WbRules::rules;
573             }
574            
575             1;
576