File Coverage

blib/lib/XML/Parsepp.pm
Criterion Covered Total %
statement 829 897 92.4
branch 507 608 83.3
condition 66 72 91.6
subroutine 35 38 92.1
pod 0 5 0.0
total 1437 1620 88.7


line stmt bran cond sub pod time code
1             package XML::Parsepp;
2             $XML::Parsepp::VERSION = '0.08';
3 3     3   4432 use 5.014;
  3         9  
  3         95  
4              
5 3     3   13 use strict;
  3         4  
  3         87  
6 3     3   16 use warnings;
  3         4  
  3         75  
7              
8 3     3   10 use Carp;
  3         5  
  3         1744  
9              
10             require Exporter;
11             our @ISA = qw(Exporter);
12             our @EXPORT = qw();
13             our @EXPORT_OK = qw();
14              
15             sub new {
16 6     6 0 2191 my $class = shift;
17              
18 6         12 my %HParam = @_;
19              
20 6         18 my $self = { _Setters => {}, _Dupatt => '' };
21 6 50       23 if ($HParam{Handlers}) {
22 0         0 $self->{_Setters} = $HParam{Handlers};
23             }
24 6 100       14 if (defined $HParam{dupatt}) {
25 2         3 my $cstr = $HParam{dupatt};
26              
27 2 100       10 unless ($cstr =~ m{\A [\x{21}-\x{bf}]* \z}xms) {
28 1         226 croak("Error-0005: invalid dupatt");
29             }
30 1 50       3 if ($cstr =~ m{[0-9A-Za-z"']}xms) {
31 0         0 croak("Error-0006: invalid dupatt");
32             }
33              
34 1         2 $self->{_Dupatt} = $cstr;
35             }
36              
37 5         16 bless $self, $class;
38             }
39              
40             sub setHandlers {
41 5     5 0 799 my $self = shift;
42              
43 5         7 %{$self->{_Setters}} = (%{$self->{_Setters}}, @_);
  5         42  
  5         11  
44             }
45              
46             sub parsefile {
47 0     0 0 0 my $self = shift;
48              
49 0         0 my ($inpname) = @_;
50              
51 0 0       0 open my $ifh, '<', $inpname or croak("Error-0010: Can't open < '$inpname' because $!");
52 0         0 $self->_process_handle($ifh);
53 0         0 close $ifh;
54             }
55              
56             sub parse {
57 0     0 0 0 my $self = shift;
58              
59 0         0 my ($pitem) = @_;
60              
61 0 0       0 if (ref($pitem) eq 'GLOB') {
62 0         0 $self->_process_handle($pitem);
63             }
64             else {
65 0 0       0 open my $ifh, '<', \$pitem or croak("Error-0020: Can't open < \\'...' because $!");
66 0         0 $self->_process_handle($ifh);
67 0         0 close $ifh;
68             }
69             }
70              
71             sub _process_handle {
72 0     0   0 my $self = shift;
73              
74 0         0 my ($fh) = @_;
75              
76 0 0       0 my $ExpatNB = $self->parse_start
77             or croak("Error-0030: Can't XML::Parsepp->parse_start");
78            
79 0         0 while (1) {
80             # Here is the all important reading of a chunk of XML-data from the filehandle...
81 0         0 read($fh, my $buf, 4096);
82            
83             # We leave immediately as soon as there is no more data left (EOF)
84 0 0       0 last if $buf eq '';
85            
86             # and here is the all important parsing of that chunk:
87             # and we could get exceptions thrown here if the XML is invalid...
88 0         0 $ExpatNB->parse_more($buf);
89             }
90              
91 0         0 $ExpatNB->parse_done;
92             }
93              
94             sub parse_start {
95 782     782 0 2098723 my $self = shift;
96              
97 782         12531 my $ExpatNB = {
98             _Setters => $self->{_Setters},
99             _Dupatt => $self->{_Dupatt},
100             _Text => '',
101             _Action => 'C', # DEFACT: 'C' = character data
102             _Stage => 1, # DEFSTA: 1 = XMLDecl, 2 = DTD, 3 = StartTag/EndTag, 4 = Rest
103             _QChar => '',
104             _ItemCount => 0,
105             _DoctCount => 0,
106             _Stack => [],
107             _Scount => 0,
108             _Seen => {},
109             _DocOpen => 0,
110             _Read_Bytes => 2,
111             _Read_Lines => 1,
112             _Read_Cols => 2,
113              
114             # Structure of '_Var':
115             # ====================
116             # L => a simple replacement character
117             # F => $system is a file name, the content of which will be processed
118             # T => $value is a replacement text
119              
120             _Var => {
121             'amp' => [L => q{&}],
122             'lt' => [L => q{<}],
123             'gt' => [L => q{>}],
124             'quot' => [L => q{"}],
125             'apos' => [L => q{'}],
126             },
127             };
128              
129 782         7963 %$ExpatNB = (%$ExpatNB, @_);
130              
131 782         3288 bless $ExpatNB, 'XML::Parsepp::ExpatNB';
132              
133 782         1621 $ExpatNB->_emit_Init;
134              
135 782         3717 return $ExpatNB;
136             }
137              
138             package XML::Parsepp::ExpatNB;
139             $XML::Parsepp::ExpatNB::VERSION = '0.08';
140             our $version = '0.06';
141              
142 3     3   16 use Carp;
  3         5  
  3         166  
143 3     3   15 use File::Spec;
  3         5  
  3         27665  
144              
145             sub regexp_pattern {
146 15 50   15   93 my ($fl, $pn) = $_[0] =~ m{\A \( \? ([\w\^\-]*) : (.*?) \) \z}xms
147             or die "Error-0040: Internal Error - Can't disassemble quoted regexp = '$_[0]'";
148 15         27 return ($pn, $fl);
149             }
150              
151             sub negated {
152 15     15   34 my ($pattern, $flags) = regexp_pattern($_[0]);
153 15 50       60 my ($caret, $class) =
154             $pattern =~ m{\A \[ (\^?) (.*?) \] \z}xms
155             or die "Error-0050: Internal Error - Can't parse regexp: $_[0] ==> (pattern = '$pattern', flags = '$flags')";
156              
157 15 50       29 my $neg_caret = $caret eq '^' ? '' : '^';
158 15         186 my $neg_regexp = qr{[$neg_caret$class]}xms;
159              
160 15         25 return $neg_regexp;
161             }
162              
163             my $rx_unc_tok = qr/["']/xms;
164             my $rx_tok_tok = qr/[!\$&\/;<=\@\\\^`\{\}~\x7f]/xms;
165             my $rx_syn_tok = qr/[\#\(\]]/xms;
166             my $rx_tok_syn = qr/[%)*+?]/xms;
167             my $rx_syn_syn = qr/[,\-.\w:\[|]/xms;
168              
169             my $ng_unc_tok = negated($rx_unc_tok);
170             my $ng_tok_tok = negated($rx_tok_tok);
171             my $ng_syn_tok = negated($rx_syn_tok);
172             my $ng_tok_syn = negated($rx_tok_syn);
173             my $ng_syn_syn = negated($rx_syn_syn);
174              
175             sub parse_more {
176 1190     1190   5364 my $self = shift;
177              
178 1190         2316 $self->_more(0, '', $_[0]);
179             }
180              
181             sub _more {
182 1230     1230   1218 my $self = shift;
183 1230         1179 my $level = shift;
184 1230         1253 my $hist = shift;
185              
186 1230         2354 my $buffer_text = $self->{_Text}.$_[0]; # Take whatever there was before and add the new parse_more parameter
187 1230         1493 $self->{_Text} = '';
188              
189 1230         1206 my @buffer_stack = @{$self->{_Stack}};
  1230         2152  
190 1230         1814 $self->{_Stack} = [];
191              
192 1230 50       3081 if (length($buffer_text) > 100_000) {
193 0         0 $self->crknum("Error-0060: Internal Error - Buffer overflow");
194             }
195              
196 1230         1394 my $buffer_action = $self->{_Action};
197              
198 1230         1242 my $buffer_breakout = 0;
199 1230   100     5015 until ($buffer_breakout or $buffer_text eq '') {
200 4660 100       15119 if ($buffer_action eq 'C') { # DEFACT: 'C' = character data
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
201 2005 100       3046 if ($self->{_Stage} <= 2) {
202              
203 1689         1512 my ($emit, $ch, $remainder);
204 1689 100       8004 if ($buffer_text =~ m{\A (\s*) (\S) (.*) \z}xms) {
    50          
205 1408         3993 ($emit, $ch, $remainder) = ($1, $2, $3);
206             }
207             elsif ($buffer_text =~ m{\A \s* \z}xms) {
208 281         561 ($emit, $ch, $remainder) = ($buffer_text, '', '');
209             }
210             else {
211 0         0 $self->crknum("Error-0070: Internal Error - Can't parse buffer_text = '$buffer_text'");
212             }
213              
214 1689         3300 $self->_emit_Char($emit);
215 1689 50       12062 $self->_update_ctr($emit) if $level == 0;
216              
217 1689 100 100     9046 if ($ch eq '') {
    100 100        
    100          
    100          
    100          
    100          
    100          
218 281         362 $buffer_text = '';
219 281         715 $buffer_breakout = 1;
220             }
221             elsif ($ch eq '<') {
222 777         1235 $buffer_text = $ch.$remainder;
223 777         829 $buffer_action = '<'; # DEFACT: '<' = anything that starts with '<'
224 777         2929 next;
225             }
226             elsif ($ch eq ']' and $self->{_DocOpen} > 0) {
227 49         139 $buffer_text = $ch.$remainder;
228 49         68 $buffer_action = ']'; # DEFACT: ']' = anything that starts with ']'
229 49         194 next;
230             }
231             elsif ($ch eq q{'} or $ch eq q{"}) {
232 5 50       21 $self->_update_ctr($ch) if $level == 0;
233 5         7 $buffer_text = $remainder;
234 5         8 $self->{_QChar} = $ch;
235 5         6 $buffer_action = 'F'; # DEFACT: 'F' = find quote character $self->{_QChar}
236 5         20 next;
237             }
238             elsif ($ch eq '>') {
239 2         5 $self->crknum("Error-0080: syntax error");
240             }
241             elsif ($ch =~ $rx_syn_syn) {
242 529 50       1314 $self->_update_ctr($ch) if $level == 0;
243 529         633 $buffer_text = $remainder;
244 529         515 $buffer_action = 'G'; # DEFACT: 'G' = find word delimited by white-space
245 529         2044 next;
246             }
247             elsif ($ch =~ $rx_syn_tok) {
248 8         21 $self->crknum("Error-0090: syntax error");
249             }
250             else {
251 38         77 $self->crknum("Error-0100: not well-formed (invalid token)");
252             }
253             }
254             else {
255 316 100       1405 if ($buffer_text =~ m{\A ([^<&]*) ([<&]) (.*) \z}xms) {
256 245         640 my ($emit, $ch, $remainder) = ($1, $2, $3);
257              
258 245         471 $self->_emit_Char($emit);
259 245 100       642 $self->_update_ctr($emit) if $level == 0;
260 245         368 $buffer_text = $ch.$remainder;
261 245         254 $buffer_action = $ch; # DEFACT: '<' = anything that starts with '<' or '&' = anything that starts with '&'
262 245         946 next;
263             }
264              
265 71         152 $self->_emit_Char($buffer_text);
266 69 100       429 $self->_update_ctr($buffer_text) if $level == 0;
267 69         82 $buffer_text = '';
268 69         79 $buffer_breakout = 1;
269 69         172 next;
270             }
271             }
272             elsif ($buffer_action eq 'F') {
273 7         9 my ($emit, $ch, $remainder);
274              
275 7 100       24 if ($self->{_QChar} eq q{'}) {
    50          
276 2 50       7 if ($buffer_text =~ m{\A ([^']*) (') (.*) \z}xms) {
277 0         0 ($emit, $ch, $remainder) = ($1, $2, $3);
278             }
279             else {
280 2         5 ($emit, $ch, $remainder) = ($buffer_text, '', '');
281             }
282             }
283             elsif ($self->{_QChar} eq q{"}) {
284 5 100       16 if ($buffer_text =~ m{\A ([^"]*) (") (.*) \z}xms) {
285 1         9 ($emit, $ch, $remainder) = ($1, $2, $3);
286             }
287             else {
288 4         12 ($emit, $ch, $remainder) = ($buffer_text, '', '');
289             }
290             }
291             else {
292 0         0 $self->crknum("Error-0110: Internal Error - invalid QChar = '".$self->{_QChar}."'");
293             }
294              
295 7 50       19 $self->_update_ctr($emit) if $level == 0;
296              
297 7 100       13 if ($ch eq '') {
298 6         9 $buffer_text = '';
299 6         7 $buffer_breakout = 1;
300 6         16 next;
301             }
302             else {
303 1         3 $self->crknum("Error-0120: not well-formed (invalid token)");
304             }
305             }
306             elsif ($buffer_action eq 'G') {
307 529         530 my ($emit, $ch, $remainder);
308              
309 529 100       1859 if ($buffer_text =~ m{\A (\S*) (\s) (.*) \z}xms) {
310 525         1290 ($emit, $ch, $remainder) = ($1, $2, $3);
311             }
312             else {
313 4         10 ($emit, $ch, $remainder) = ($buffer_text, '', '');
314             }
315              
316 529 50       1274 $self->_update_ctr($emit) if $level == 0;
317              
318 529 100       2489 if ($emit =~ m{($ng_syn_syn)}xms) {
319 156         287 my $out = $1;
320 156 100 100     1025 if ($out =~ $rx_tok_syn or $out eq '>') {
321 13         31 $self->crknum("Error-0130: syntax error");
322             }
323             else {
324 143         301 $self->crknum("Error-0140: not well-formed (invalid token)");
325             }
326             }
327             else {
328 373 100       619 if ($ch eq '') {
329 1         2 $buffer_text = '';
330 1         2 $buffer_breakout = 1;
331 1         3 next;
332             }
333             else {
334 372         618 $self->crknum("Error-0150: syntax error");
335             }
336             }
337             }
338             elsif ($buffer_action eq '&') { # DEFACT: '&' = anything that starts with '&'
339 73 100       303 if ($buffer_text =~ m{\A . ([^<;]*) ([<;]) (.*) \z}xms) {
340 64         164 my ($emit, $ch, $remainder) = ($1, $2, $3);
341 64 100       162 unless ($ch eq ';') {
342 3         7 $self->crknum("Error-0160: not well-formed (invalid token)");
343             }
344 61         287 $self->_emit_Amp($level, $hist, '&'.$emit.';');
345 29 100       193 $self->_update_ctr('&'.$emit.';') if $level == 0;
346 29         42 $buffer_text = $remainder;
347 29         36 $buffer_action = 'C'; # DEFACT: 'C' = character data
348 29         107 next;
349             }
350 9         8 $buffer_breakout = 1;
351 9         19 next;
352             }
353             elsif ($buffer_action eq '<') { # DEFACT: '<' = anything that starts with '<'
354 960 100       1825 if (length($buffer_text) < 3) {
355 2         3 $buffer_breakout = 1;
356 2         4 next;
357             }
358 958         1520 my $c1 = substr($buffer_text, 0, 1);
359 958         1103 my $c2 = substr($buffer_text, 1, 1);
360 958         1169 my $c3 = substr($buffer_text, 2, 1);
361              
362 958 100 100     2624 if ($c2 eq '!' and $c3 eq '-') {
363 10         12 $buffer_action = '!'; # DEFACT: '' a comment
364 10         35 next;
365             }
366 948 100 100     2439 if ($c2 eq '!' and $c3 eq '[') {
367 3         5 $buffer_action = 'A'; # DEFACT: '' a CDATA section
368 3         12 next;
369             }
370 945 100 66     3349 if ($c2 eq '!' and $c3 =~ m{\w}xms) {
371 396         496 $buffer_action = 'D'; # DEFACT: '' a DTD section (DOCTYPE, ELEMENT, ATTLIST, etc...)
372 396         1401 next;
373             }
374 549 100       1914 if ($c2 =~ m{[,\-.\w:\[|]}xms) {
375 174         226 $buffer_action = 'S'; # DEFACT: 'S' = start tag
376 174         656 next;
377             }
378 375 100       785 if ($c2 eq '/') {
379 102         138 $buffer_action = 'E'; # DEFACT: 'E' = end tag
380 102         361 next;
381             }
382 273 100       614 if ($c2 eq '?') {
383 270         402 $buffer_action = '?'; # DEFACT: '?' = processing instruction
384 270         993 next;
385             }
386 3         10 $self->crknum("Error-0170: not well-formed (invalid token)");
387             }
388             elsif ($buffer_action eq '!') { # DEFACT: '' a comment
389 26 50       46 if (length($buffer_text) < 4) {
390 0         0 $buffer_breakout = 1;
391 0         0 next;
392             }
393 26         38 my $prefix = substr($buffer_text, 0, 4);
394 26 100       50 unless ($prefix eq ') (.*) \z}xms) {
398 9         31 my ($emit, $remainder) = ($1, $2);
399 9         28 $self->_emit_Comment($emit);
400 9 50       125 $self->_update_ctr($emit) if $level == 0;
401 9         17 $buffer_text = $remainder;
402 9         14 $buffer_action = 'C'; # DEFACT: 'C' = character data
403 9         37 next;
404             }
405 16         16 $buffer_breakout = 1;
406 16         30 next;
407             }
408             elsif ($buffer_action eq 'A') { # DEFACT: '' beginning of a CDATA section
409 3 50       13 if (length($buffer_text) < 9) {
410 0         0 $buffer_breakout = 1;
411 0         0 next;
412             }
413 3         7 my $prefix = substr($buffer_text, 0, 9);
414 3         7 my $remainder = substr($buffer_text, 9);
415 3 100       10 unless ($prefix eq '
416 1         7 $self->crknum("Error-0190: not well-formed (invalid token)");
417             }
418 2         10 $self->_emit_Cdatastart;
419 2 50       23 $self->_update_ctr($prefix) if $level == 0;
420              
421 2         4 $buffer_text = $remainder;
422 2         2 $buffer_action = 'B'; # DEFACT: 'B' = '' text of a CDATA section
423 2         10 next;
424             }
425             elsif ($buffer_action eq 'B') { # DEFACT: 'B' = '' text of a CDATA section
426 3 100       19 if ($buffer_text =~ m{\A (.*?) (\]\]>) (.*) \z}xms) {
427 2         9 my ($emit, $suffix, $remainder) = ($1, $2, $3);
428 2         7 $self->_emit_Char($emit);
429 2 50       10 $self->_update_ctr($emit) if $level == 0;
430              
431 2         8 $self->_emit_Cdataend;
432 2 50       23 $self->_update_ctr($suffix) if $level == 0;
433              
434 2         3 $buffer_text = $remainder;
435 2         4 $buffer_action = 'C'; # DEFACT: 'C' = character data
436 2         9 next;
437             }
438 1         5 $self->_emit_Char($buffer_text);
439 1 50       7 $self->_update_ctr($buffer_text) if $level == 0;
440 1         2 $buffer_text = '';
441 1         3 $buffer_breakout = 1;
442 1         5 next;
443             }
444             # pour identifier les differents possibilites de DTD (DOCTYPE, ELEMENT, ATTLIST, etc...), voir: http://www.u-picardie.fr/~ferment/xml/xml02.html
445             elsif ($buffer_action eq 'D') { # DEFACT: '' a DTD section (DOCTYPE, ELEMENT, ATTLIST, etc...)
446 448         581 my $finpos = -1;
447 448         849 pos($buffer_text) = 0;
448 448         1890 while ($buffer_text =~ m{\G \s* (?: ([^'"\s]+) | ' [^']* ' | " [^"]* " ) }xmsgc) {
449 1963 100       3858 if (defined $1) {
450 1589         2381 my $mp = $-[1];
451 1589         2058 my $fragment = $1;
452 1589 100       5410 if ($fragment =~ m{[>\[]}xms) {
453 395         787 $finpos = $mp + $-[0];
454 395         645 last;
455             }
456             }
457             }
458              
459 448 100       912 if ($finpos != -1) {
460 395         560 my $terminal = substr $buffer_text, $finpos, 1;
461 395 50 66     1259 unless ($terminal eq '>' or $terminal eq '[') {
462 0         0 $self->crknum("Error-0200: Internal Error - found terminal char ('$terminal') not equal to ('>', '[')");
463             }
464 395         692 my $emit = substr($buffer_text, 0, $finpos + 1);
465 395         962 $self->_emit_Dtd($emit);
466 332 50       972 $self->_update_ctr($emit) if $level == 0;
467 332         812 $buffer_text = substr($buffer_text, $finpos + 1);
468 332         409 $buffer_action = 'C'; # DEFACT: 'C' = character data
469 332         1405 next;
470             }
471 53         72 $buffer_breakout = 1;
472 53         123 next;
473             }
474             elsif ($buffer_action eq ']') { # DEFACT: ']' = closing doctype parenthesis ']>'
475 49 50       150 if (length($buffer_text) < 2) {
476 0         0 $buffer_breakout = 1;
477 0         0 next;
478             }
479              
480 49 50       138 unless ($self->{_DocOpen}) {
481 0         0 $self->crknum("Error-0210: Internal Error - Can't close a closed Doctype");
482             }
483              
484 49 100       262 unless ($buffer_text =~ m{\A (\] \s* >) (.*) \z}xms) {
485 2         4 $self->crknum("Error-0220: not well-formed (invalid token)");
486             }
487 47         141 my ($emit, $remainder) = ($1, $2);
488              
489 47         155 $self->_emit_CloseDoc($emit);
490 47 50       418 $self->_update_ctr($emit) if $level == 0;
491 47         71 $buffer_text = $remainder;
492 47         78 $buffer_action = 'C'; # DEFACT: 'C' = character data
493 47         192 next;
494             }
495             elsif ($buffer_action eq 'S') { # DEFACT: 'S' = start tag
496 183         205 my $finpos = -1;
497 183         405 pos($buffer_text) = 0;
498 183         781 while ($buffer_text =~ m{\G \s* (?: ([^'"\s]+) | ' [^']* ' | " [^"]* " ) }xmsgc) {
499 354 100       814 if (defined $1) {
500 290         498 my $mp = $-[1];
501 290         430 my $fragment = $1;
502 290 100       946 if ($fragment =~ m{>}xms) {
503 174         330 $finpos = $mp + $-[0];
504 174         302 last;
505             }
506             }
507             }
508              
509 183 100       379 if ($finpos != -1) {
510 174         316 my $emit = substr($buffer_text, 0, $finpos + 1);
511 174         523 $self->_emit_Start($emit, \@buffer_stack, $level);
512 162 100       605 $self->_update_ctr($emit) if $level == 0;
513 162         328 $buffer_text = substr($buffer_text, $finpos + 1);
514 162         203 $buffer_action = 'C'; # DEFACT: 'C' = character data
515 162         686 next;
516             }
517 9         7 $buffer_breakout = 1;
518 9         19 next;
519             }
520             elsif ($buffer_action eq 'E') { # DEFACT: 'E' = end tag
521 104 100       481 if ($buffer_text =~ m{\A ([^>]* [>]) (.*) \z}xms) {
522 99         261 my ($emit, $remainder) = ($1, $2);
523 99         361 $self->_emit_End($emit, \@buffer_stack, $hist);
524 92 100       1051 $self->_update_ctr($emit) if $level == 0;
525 92         137 $buffer_text = $remainder;
526 92         130 $buffer_action = 'C'; # DEFACT: 'C' = character data
527 92         376 next;
528             }
529 5         8 $buffer_breakout = 1;
530 5         13 next;
531             }
532             elsif ($buffer_action eq '?') { # DEFACT: '?' = processing instruction
533 270 50       1480 if ($buffer_text =~ m{\A ([^>]* [>]) (.*) \z}xms) {
534 270         802 my ($emit, $remainder) = ($1, $2);
535 270         868 $self->_emit_Proc($emit);
536 254 50       4548 $self->_update_ctr($emit) if $level == 0;
537 254         363 $buffer_text = $remainder;
538 254         305 $buffer_action = 'C'; # DEFACT: 'C' = character data
539 254         1059 next;
540             }
541 0         0 $buffer_breakout = 1;
542 0         0 next;
543             }
544             else {
545 0         0 $self->crknum("Error-0230: Internal Error - invalid buffer_action = '$buffer_action'");
546             }
547             }
548              
549 511         775 $self->{_Text} = $buffer_text;
550 511         894 $self->{_Stack} = [@buffer_stack];
551 511         1401 $self->{_Action} = $buffer_action;
552             }
553              
554             sub _emit_Init {
555 782     782   880 my $self = shift;
556              
557 782         1341 my $cb_Init = $self->{_Setters}{Init};
558 782 50       1918 if ($cb_Init) {
559 782         1605 $cb_Init->($self);
560             }
561             }
562              
563             sub _emit_Final {
564 74     74   96 my $self = shift;
565              
566 74         151 my $cb_Final = $self->{_Setters}{Final};
567 74 50       146 if ($cb_Final) {
568 74         174 $cb_Final->($self);
569             }
570             }
571              
572             sub _emit_Amp {
573 61     61   72 my $self = shift;
574 61         64 my $level = shift;
575 61         75 my $hist = shift;
576              
577 61         72 my ($ampersand) = @_;
578              
579 61 50       309 my ($var) = $ampersand =~ m{\A & ([^&;]+) ; \z}xms
580             or $self->crknum("Error-0240: Internal Error - Can't parse ampersand = '$ampersand'");
581              
582 61 100       136 if ($var =~ m{\A \# (\d+) \z}xms) {
583 2         10 my $value = chr($1);
584              
585 2         6 $self->_plausi('C'); # PLAUSI ==> 'C' = Character Data
586              
587 2         5 $self->{_ItemCount}++;
588              
589 2         3 my $cb_Char = $self->{_Setters}{Char};
590 2 50       6 if ($cb_Char) {
591 2         5 $cb_Char->($self, $value);
592             }
593             }
594             else {
595 59         134 my $rhs = $self->{_Var}{$var};
596              
597 59 100       121 unless (defined $rhs) {
598 5 100       16 if ($level == 0) {
599 4         12 $self->crknum("Error-0250: undefined entity");
600             }
601             else {
602 1         7 $self->crknum("Error-0260: error in processing external entity reference");
603             }
604             }
605              
606 54         99 my ($code, $value) = @$rhs;
607              
608             # Structure of ($code, $value):
609             # =============================
610             # L => a simple replacement character
611             # F => $system is a file name, the content of which will be processed
612             # T => $value is a replacement text
613              
614 54 100       195 if ($code eq 'L') {
    100          
    50          
615 11         21 $self->_plausi('C'); # PLAUSI ==> 'C' = Character Data
616              
617 11         12 $self->{_ItemCount}++;
618              
619 11         20 my $cb_Char = $self->{_Setters}{Char};
620 11 50       20 if ($cb_Char) {
621 11         28 $cb_Char->($self, $value);
622             }
623             }
624             elsif ($code eq 'F') {
625 23 100       73 if ($self->{_Seen}{$var}) {
626 1         4 $self->crknum("Error-0270: error in processing external entity reference");
627             }
628 22         52 $self->{_Seen}{$var} = 1;
629              
630 22         38 my $cb_Exen = $self->{_Setters}{ExternEnt};
631 22 100       48 if ($cb_Exen) {
632             # ExternEnt (Expat, Base, Sysid, Pubid)
633 3         10 my $buf = $cb_Exen->($self, undef, $value, undef);
634              
635 3         71 $self->_more($level + 1, $hist.'X', $buf);
636              
637 3         9 my $cb_Exef = $self->{_Setters}{ExternEntFin};
638 3 50       9 if ($cb_Exef) {
639             # ExternEntFin (Expat)
640 3         17 my $buf = $cb_Exef->($self);
641             }
642              
643 3 100       29 unless ($self->{_Text} eq '') {
644 1         4 $self->crknum("Error-0280: error in processing external entity reference");
645             }
646 2 100       2 if (@{$self->{_Stack}}) {
  2         8  
647 1         5 $self->crknum("Error-0290: error in processing external entity reference");
648             }
649             }
650             else {
651 19         655 my $filepath = File::Spec->rel2abs($value);
652 19 100       648 open my $ifh, '<', $value
653             or $self->crknum("Error-0300: Handler couldn't resolve external entity\n"."404 File `$filepath' does not exist");
654              
655 18         21 while (1) {
656 30         222 read($ifh, my $buf, 4096);
657 30 100       68 last if $buf eq '';
658              
659 18         115 $self->_more($level + 1, $hist.'F', $buf);
660             }
661              
662 12         94 close $ifh;
663              
664 12 100       33 unless ($self->{_Text} eq '') {
665 1         6 $self->crknum("Error-0310: error in processing external entity reference");
666             }
667 11 100       10 if (@{$self->{_Stack}}) {
  11         81  
668 1         4 $self->crknum("Error-0320: error in processing external entity reference");
669             }
670             }
671              
672 11         35 $self->{_Seen}{$var} = 0;
673             }
674             elsif ($code eq 'T') {
675 20 100       57 if ($self->{_Seen}{$var}) {
676 1         3 $self->crknum("Error-0330: recursive entity reference");
677             }
678 19         49 $self->{_Seen}{$var} = 1;
679              
680 19         120 $self->_more($level + 1, $hist.'T', $value);
681              
682 7 100       22 unless ($self->{_Text} eq '') {
683 1         3 $self->crknum("Error-0340: unclosed token");
684             }
685 6 100       7 if (@{$self->{_Stack}}) {
  6         16  
686 1         4 $self->crknum("Error-0350: asynchronous entity");
687             }
688              
689 5         13 $self->{_Seen}{$var} = 0;
690             }
691             else {
692 0         0 $self->crknum("Error-0360: Internal Error - Found invalid code '$code' not equal to ('F', 'L', 'T')");
693             }
694             }
695             }
696              
697             sub _emit_Char {
698 2008     2008   1996 my $self = shift;
699 2008         2001 my ($emit) = @_;
700              
701 2008         3096 $self->_plausi('C'); # PLAUSI ==> 'C' = Character Data
702              
703 2008         1930 my $default = 0;
704              
705 2008 100       3792 unless ($self->{_Stage} == 3) {
706 1716         2066 $default = 1;
707 1716 100       3468 if ($emit =~ m{\S}xms) {
708 2 50       6 if ($self->{_Stage} == 4) {
709 2         7 $self->crknum("Error-0370: junk after document element");
710             }
711             else {
712 0         0 $self->crknum("Error-0380: Internal Error - non-space data");
713             }
714             }
715             }
716              
717 2006 100       2545 if ($default) {
718 1714 100       3304 unless ($emit eq '') {
719              
720 985         993 $self->{_ItemCount}++;
721              
722 985         1328 my $cb_Default = $self->{_Setters}{Default};
723 985 50       1653 if ($cb_Default) {
724             # Default (Expat, String)
725 985         1923 $cb_Default->($self, $emit);
726             }
727             }
728             }
729             else {
730 292         622 pos($emit) = 0;
731 292         1023 while ($emit =~ m{\G (?: ([^\n]+) | ([\n]) ) }xmsgc) {
732 187         342 my $fragment;
733 187 100       403 if (defined $1) {
    50          
734 158         216 $fragment = $1;
735             }
736             elsif (defined $2) {
737 29         41 $fragment = $2;
738             }
739             else {
740 0         0 $self->crknum("Error-0390: Internal Error - inconsistent result from regexp");
741             }
742              
743 187 50       388 unless ($fragment eq '') {
744 187         274 $self->{_ItemCount}++;
745              
746 187         284 my $cb_Char = $self->{_Setters}{Char};
747 187 50       333 if ($cb_Char) {
748 187         435 $cb_Char->($self, $fragment);
749             }
750             }
751             }
752 292 50       2451 unless ($emit =~ m{\G (.*) \z}xms) {
753 0         0 $self->crknum("Error-0400: Internal Error - Can't find regexp rest in CHAR");
754             }
755 292         429 my $rest = $1;
756 292 50       800 if ($rest ne '') {
757 0         0 $self->crknum("Error-0410: Internal Error - Invalid rest ($rest) in CHAR regexp");
758             }
759             }
760             }
761              
762             sub _emit_Start {
763 174     174   228 my $self = shift;
764 174         411 my ($emit, $bstack, $level) = @_;
765              
766 174 50       1320 my ($elem, $param, $term) = $emit =~ m{\A < \s* ([,\-.\w:\[|]+) (.*?) (/?) > \z}xms
767             or $self->crknum("Error-0420: Internal Error - Can't decompose start = '$emit'");
768              
769 174         242 my @attr;
770             my %att_hash;
771              
772 174         373 pos($param) = 0;
773 174         574 while ($param =~ m{\G \s* ([,\-.\w:\[|]+) \s* = \s* (?: ' ([^']*) ' | " ([^"]*) " ) }xmsgc) {
774 45         72 my $def_var = $1;
775 45         43 my $def_txt;
776 45 100       116 if (defined $2) {
    50          
777 10         12 $def_txt = $2;
778             }
779             elsif (defined $3) {
780 35         59 $def_txt = $3;
781             }
782             else {
783 0         0 $self->crknum("Error-0430: Internal Error - Can't match any param");
784             }
785              
786 45 100       120 if ($def_txt =~ m{<}xms) {
787 1         3 $self->crknum("Error-0440: not well-formed (invalid token)");
788             }
789              
790 44         65 $def_txt =~ s{\n}' 'xmsg;
791 44         50 my $def_res = '';
792              
793 44         67 pos($def_txt) = 0;
794 44         140 while ($def_txt =~ m{\G ([^&]*) & ([^&;]+) ; }xmsgc) {
795 9         22 $def_res .= $1;
796 9         18 my $var = $2;
797 9         21 my $rhs = $self->{_Var}{$var};
798              
799 9 100       22 unless (defined $rhs) {
800 1         4 $self->crknum("Error-0450: undefined entity");
801             }
802              
803 8         18 my ($code, $value) = @$rhs;
804              
805             # Structure of ($code, $value):
806             # =============================
807             # L => a simple replacement character
808             # F => $system is a file name, the content of which will be processed
809             # T => $value is a replacement text
810              
811 8 100       21 unless ($code eq 'L') {
812 1         3 $self->crknum("Error-0460: reference to external entity in attribute");
813             }
814              
815 7         24 $def_res .= $value;
816             }
817 42 50       137 unless ($def_txt =~ m{\G (.*) \z}xms) {
818 0         0 $self->crknum("Error-0470: Internal Error - Can't find regexp rest in ELEMENT");
819             }
820              
821 42         63 my $rest = $1;
822 42 100       94 if ($rest =~ m{&}xms) {
823 2         12 $self->crknum("Error-0480: not well-formed (invalid token)");
824             }
825              
826 40         46 $def_res .= $rest;
827              
828 40 100       109 if (defined $att_hash{$def_var}) {
829 3 100       12 if ($self->{_Dupatt} eq '') {
830 2         7 $self->crknum("Error-0485: duplicate attribute");
831             }
832 1         2 $att_hash{$def_var} .= $self->{_Dupatt}.$def_res;
833             }
834             else {
835 37         79 $att_hash{$def_var} = $def_res;
836             }
837              
838 38         148 push @attr, $def_var, $def_res;
839             }
840 167 50       607 unless ($param =~ m{\G (.*) \z}xms) {
841 0         0 $self->crknum("Error-0490: Internal Error - Can't find regexp rest in START");
842             }
843              
844 167         269 my $rest = $1;
845 167 100       382 if ($rest =~ m{\S}xms) {
846 4 100       15 if ($level == 0) {
847 3         8 $self->crknum("Error-0500: not well-formed (invalid token)");
848             }
849             else {
850 1         6 $self->crknum("Error-0510: error in processing external entity reference");
851             }
852             }
853              
854 163 100       463 unless ($self->{_Dupatt} eq '') {
855 2         7 @attr = map { $_ => $att_hash{$_} } sort(keys %att_hash);
  2         6  
856             }
857              
858 163         368 $self->_plausi('S'); # PLAUSI ==> 'S' = Start Tag
859              
860 162         208 $self->{_Scount}++;
861 162         299 push @$bstack, $elem;
862              
863 162         223 $self->{_ItemCount}++;
864              
865 162         272 my $cb_Start = $self->{_Setters}{Start};
866 162 50       304 if ($cb_Start) {
867             # Start (Expat, Element [, Attr, Val [,...]])
868 162         467 $cb_Start->($self, $elem, @attr);
869             }
870              
871 162 100       2816 if ($term eq '/') {
    50          
872 14 50       41 if ($self->{_Scount} < 1) {
873 0         0 $self->crknum("Error-0520: Internal Error - Underflow in Scount");
874             }
875 14         21 $self->{_Scount}--;
876              
877 14         28 my $ele_from_stack = pop @$bstack;
878 14 50       32 unless (defined $ele_from_stack) {
879 0         0 $self->crknum("Error-0530: Internal Error - Underflow in stack");
880             }
881              
882 14 50       34 unless ($elem eq $ele_from_stack) {
883 0         0 $self->crknum("Error-0540: Internal Error - Mismatch of Start- and End-tag, start = '$ele_from_stack', end = '$elem'");
884             }
885              
886 14         32 $self->_plausi('E'); # PLAUSI ==> 'E' = End Tag
887              
888 14         19 $self->{_ItemCount}++;
889              
890 14         20 my $cb_End = $self->{_Setters}{End};
891 14 50       27 if ($cb_End) {
892             # End (Expat, Element)
893 14         32 $cb_End->($self, $elem);
894             }
895             }
896             elsif ($term ne '') {
897 0         0 $self->crknum("Error-0550: Internal Error - in START found closing tag '$term'");
898             }
899             }
900              
901             sub _emit_End {
902 99     99   126 my $self = shift;
903 99         203 my ($emit, $bstack, $hist) = @_;
904              
905 99 100       527 my ($elem) = $emit =~ m{\A < \s* / \s* ([,\-.\w:\[|]+) \s* > \z}xms
906             or $self->crknum("Error-0560: not well-formed (invalid token)");
907              
908 98 100       313 if ($self->{_Scount} < 1) {
909 1         5 $self->crknum("Error-0570: not well-formed (invalid token)");
910             }
911 97         160 $self->{_Scount}--;
912              
913 97         167 my $ele_from_stack = pop @$bstack;
914 97 100       228 unless (defined $ele_from_stack) {
915 3 100       9 if ($hist =~ m{F}xms) {
916 1         4 $self->crknum("Error-0580: error in processing external entity reference");
917             }
918             else {
919 2         6 $self->crknum("Error-0590: asynchronous entity");
920             }
921             }
922              
923 94 100       210 unless ($elem eq $ele_from_stack) {
924 2         8 $self->crknum("Error-0600: mismatched tag");
925             }
926              
927 92         206 $self->_plausi('E'); # PLAUSI ==> 'E' = End Tag
928              
929 92         121 $self->{_ItemCount}++;
930              
931 92         169 my $cb_End = $self->{_Setters}{End};
932 92 50       186 if ($cb_End) {
933             # End (Expat, Element)
934 92         268 $cb_End->($self, $elem);
935             }
936             }
937              
938             sub _emit_Proc {
939 270     270   346 my $self = shift;
940 270         384 my ($emit) = @_;
941              
942 270 100       1772 my ($target, $data) = $emit =~ m{\A <\? ([,\-.\w:\[|]+) \s* (.*) \?> \z}xms
943             or $self->crknum("Error-0610: not well-formed (invalid token)");
944              
945 266 100       885 if ($target =~ m{\A xml}xmsi) {
946 255 100       775 unless ($self->{_ItemCount} == 0) {
947 2         5 $self->crknum("Error-0620: XML or text declaration not at start of entity");
948             }
949              
950 253         308 my @attr;
951 253         759 pos($data) = 0;
952              
953 253         1749 while ($data =~ m{\G \s* ([,\-.\w:\[|]+) \s* = \s* (?: ' ([^']*) ' | " ([^"]*) " ) }xmsgc) {
954 419 100       1155 if (defined $2) {
    50          
955 9         30 push @attr, [$1, $2];
956             }
957             elsif (defined $3) {
958 410         1915 push @attr, [$1, $3];
959             }
960             else {
961 0         0 $self->crknum("Error-0630: Internal Error - Can't match any param");
962             }
963             }
964              
965 253 50       957 unless ($data =~ m{\G (.*) \z}xms) {
966 0         0 $self->crknum("Error-0640: Internal Error - Can't find regexp rest in PROC");
967             }
968              
969 253         426 my $rest = $1;
970 253 100       582 if ($rest =~ m{\S}xms) {
971 1         3 $self->crknum("Error-0650: XML declaration not well-formed");
972             }
973              
974             #
975 252         294 my ($ver, $enc, $stand);
976              
977 252         439 for my $at (@attr) {
978 414 100       961 if ($at->[0] eq 'version') {
    100          
    100          
979 252 100       524 if (defined $ver) {
980 1         3 $self->crknum("Error-0660: XML declaration not well-formed");
981             }
982 251         579 $ver = $at->[1];
983             }
984             elsif ($at->[0] eq 'encoding') {
985 146 100       296 if (defined $enc) {
986 1         3 $self->crknum("Error-0670: XML declaration not well-formed");
987             }
988 145         320 $enc = $at->[1];
989             }
990             elsif ($at->[0] eq 'standalone') {
991 14 100       28 if (defined $stand) {
992 1         2 $self->crknum("Error-0680: XML declaration not well-formed");
993             }
994 13 100       39 if ($at->[1] eq 'yes') {
    100          
995 8         19 $stand = '1';
996             }
997             elsif ($at->[1] eq 'no') {
998 2         5 $stand = '';
999             }
1000             else {
1001 3         11 $self->crknum("Error-0690: XML declaration not well-formed");
1002             }
1003             }
1004             else {
1005 2         4 $self->crknum("Error-0700: XML declaration not well-formed");
1006             }
1007             }
1008 244 100       632 unless (defined $ver) {
1009 1         3 $self->crknum("Error-0710: XML declaration not well-formed");
1010             }
1011              
1012 243         559 $self->_plausi('X'); # PLAUSI ==> 'X' = XML Declaration
1013              
1014 243         342 $self->{_ItemCount}++;
1015              
1016 243         545 my $cb_Decl = $self->{_Setters}{XMLDecl};
1017 243 50       530 if ($cb_Decl) {
1018             # XMLDecl (Expat, Version, Encoding, Standalone)
1019 243         749 $cb_Decl->($self, $ver, $enc, $stand);
1020             }
1021             }
1022             else {
1023 11         31 $self->_plausi('P'); # PLAUSI ==> 'P' = Processing Instruction
1024              
1025 11         16 $self->{_ItemCount}++;
1026              
1027 11         23 my $cb_Proc = $self->{_Setters}{Proc};
1028 11 50       23 if ($cb_Proc) {
1029             # Proc (Expat, Target, Data)
1030 11         29 $cb_Proc->($self, $target, $data);
1031             }
1032             }
1033             }
1034              
1035             sub _emit_Comment {
1036 9     9   12 my $self = shift;
1037 9         13 my ($emit) = @_;
1038              
1039 9 50       52 my ($comment) = $emit =~ m{\A \z}xms or
1040             $self->crknum("Error-0720: Internal Error - Can't decompose comment '$emit'");
1041              
1042 9         25 $self->_plausi('!'); # PLAUSI ==> '!' = comment
1043              
1044 9         13 $self->{_ItemCount}++;
1045              
1046 9         22 my $cb_Comment = $self->{_Setters}{Comment};
1047 9 50       22 if ($cb_Comment) {
1048 9         29 $cb_Comment->($self, $comment);
1049             }
1050             }
1051              
1052             sub _emit_Cdatastart {
1053 2     2   3 my $self = shift;
1054              
1055 2         7 $self->_plausi('A'); # PLAUSI ==> 'A' = CData
1056              
1057 2         4 my $cb_CdataStart = $self->{_Setters}{CdataStart};
1058 2 50       7 if ($cb_CdataStart) {
1059 2         8 $cb_CdataStart->($self);
1060             }
1061             }
1062              
1063             sub _emit_Cdataend {
1064 2     2   4 my $self = shift;
1065              
1066 2         5 $self->_plausi('A'); # PLAUSI ==> 'A' = CData
1067              
1068 2         4 my $cb_CdataEnd = $self->{_Setters}{CdataEnd};
1069 2 50       6 if ($cb_CdataEnd) {
1070 2         10 $cb_CdataEnd->($self);
1071             }
1072             }
1073              
1074             sub _emit_CloseDoc {
1075 47     47   79 my $self = shift;
1076 47         72 my ($emit) = @_;
1077              
1078 47 50       203 $emit =~ m{\A \] \s* > \z}xms
1079             or $self->crknum("Error-0730: Internal Error - Invalid closedoc: '$emit'");
1080              
1081 47 50       116 unless ($self->{_DocOpen}) {
1082 0         0 $self->crknum("Error-0740: Internal Error - closedoc found without DocOpen");
1083             }
1084              
1085 47         108 $self->_plausi('F'); # PLAUSI ==> 'F' = DocTypeFin
1086              
1087 47         74 $self->{_DocOpen} = 0;
1088              
1089 47         93 my $cb_DoctypeFin = $self->{_Setters}{DoctypeFin};
1090 47 50       115 if ($cb_DoctypeFin) {
1091             # DoctypeFin (Expat)
1092 47         142 $cb_DoctypeFin->($self);
1093             }
1094             }
1095              
1096             sub _emit_Dtd {
1097 395     395   498 my $self = shift;
1098 395         482 my ($emit) = @_;
1099              
1100 395 100       946 if ($self->{_Stage} > 2) {
1101 1         2 $self->crknum("Error-0750: not well-formed (invalid token)");
1102             }
1103              
1104 394 100       2236 my ($type, $data, $term) = $emit =~ m{\A ]) \z}xms
1105             or $self->crknum("Error-0760: not well-formed (invalid token)");
1106              
1107 390         496 my @elist;
1108 390         734 pos($data) = 0;
1109 390         1429 while ($data =~ m{\G \s* (?: ([^'"\(\s]+) | ' ([^']*) ' | " ([^"]*) " | \( ([^\)]*) \) ) }xmsgc) {
1110 1113 100       2559 if (defined $1) {
    100          
    100          
    50          
1111 713         3121 push @elist, ['B' => $1];
1112             }
1113             elsif (defined $2) {
1114 4         16 push @elist, ['Q' => $2, q{'}];
1115             }
1116             elsif (defined $3) {
1117 370         1495 push @elist, ['Q' => $3, q{"}];
1118             }
1119             elsif (defined $4) {
1120 26         39 my $paran = $4;
1121 26         95 $paran =~ s{\s}''xmsg;
1122 26         106 push @elist, ['P' => $paran];
1123             }
1124             else {
1125 0         0 $self->crknum("Error-0770: Internal Error - regexp undefined");
1126             }
1127             }
1128              
1129 390 50       1246 unless ($data =~ m{\G (.*) \z}xms) {
1130 0         0 $self->crknum("Error-0780: Internal Error - Can't find regexp rest");
1131             }
1132              
1133 390         697 my $rest = $1;
1134 390 100       763 if ($rest =~ m{\S}xms) {
1135 1         3 $self->crknum("Error-0790: syntax error");
1136             }
1137              
1138 389 100       1021 if ($type eq 'DOCTYPE') {
    100          
    100          
    100          
    100          
1139 210         655 $self->_parse_Doctype(\@elist, $term);
1140             }
1141             elsif ($type eq 'ENTITY') {
1142 109         303 $self->_parse_Entity(\@elist);
1143             }
1144             elsif ($type eq 'ELEMENT') {
1145 16         44 $self->_parse_Element(\@elist);
1146             }
1147             elsif ($type eq 'ATTLIST') {
1148 36         86 $self->_parse_Attlist(\@elist);
1149             }
1150             elsif ($type eq 'NOTATION') {
1151 16         48 $self->_parse_Notation(\@elist);
1152             }
1153             else {
1154 2         6 $self->crknum("Error-0800: syntax error");
1155             }
1156              
1157 333 100 100     4516 unless ($type eq 'DOCTYPE' or $term eq '>') {
1158 1         3 $self->crknum("Error-0810: syntax error");
1159             }
1160             }
1161              
1162             sub _parse_Doctype {
1163 210     210   300 my $self = shift;
1164 210         306 my ($plist, $terminal) = @_;
1165              
1166 210         331 $self->{_DoctCount}++;
1167 210 100       534 unless ($self->{_DoctCount} == 1) {
1168 3         12 $self->crknum("Error-0820: syntax error");
1169             }
1170              
1171             #
1172             # 'DOCT nam=[racine], sys=[URI-de-la-dtd], pub=[*undef*], int=[]'
1173             # 'DOCF'
1174              
1175             #
1176             # 'DOCT nam=[svg], sys=[http://www.w3.org/Graphics/SVG/SVG-19991203.dtd], pub=[-//W3C//DTD SVG December 1999//EN], int=[]'
1177             # 'DOCF'
1178              
1179             # int=1
1180             # 'DOCT nam=[dialogue], sys=[*undef*], pub=[*undef*], int=[1]'
1181              
1182 207         326 my $param0 = shift(@$plist);
1183              
1184 207 50       460 unless (defined $param0) {
1185 0         0 $self->crknum("Error-0830: Internal Error - Not enough elements in DOCTYPE");
1186             }
1187              
1188 207 100       538 unless ($param0->[0] eq 'B') {
1189 2         5 $self->crknum("Error-0840: syntax error");
1190             }
1191              
1192 205         284 my $name = $param0->[1];
1193 205 100       459 my $intern = $terminal eq '[' ? '1' : '';
1194              
1195 205         191 my ($system, $public);
1196              
1197 205         242 my $param1 = shift(@$plist);
1198 205 100       428 if (defined $param1) {
1199 115 100       258 unless ($param1->[0] eq 'B') {
1200 4         13 $self->crknum("Error-0850: syntax error");
1201             }
1202 111         131 my $syspub;
1203 111 100       367 if ($param1->[1] eq 'SYSTEM') {
    100          
1204 10         15 $syspub = 'S';
1205             }
1206             elsif ($param1->[1] eq 'PUBLIC') {
1207 99         146 $syspub = 'P';
1208             }
1209             else {
1210 2         7 $self->crknum("Error-0860: syntax error");
1211             }
1212              
1213 109         145 my $param2 = shift(@$plist);
1214 109 100       238 unless (defined $param2) {
1215 1         3 $self->crknum("Error-0870: syntax error");
1216             }
1217 108 100       269 unless ($param2->[0] eq 'Q') {
1218 1         2 $self->crknum("Error-0880: syntax error");
1219             }
1220              
1221 107 100       222 if ($syspub eq 'S') {
1222 8         20 $system = $param2->[1];
1223             }
1224             else {
1225 99         220 $public = $param2->[1];
1226             }
1227              
1228 107         161 my $param3 = shift(@$plist);
1229 107 100       239 if (defined $param3) {
1230 101 100       271 unless ($param3->[0] eq 'Q') {
1231 1         2 $self->crknum("Error-0890: syntax error");
1232             }
1233              
1234 100 100       183 if ($syspub eq 'S') {
1235 1         3 $public = $param3->[1];
1236             }
1237             else {
1238 99         272 $system = $param3->[1];
1239             }
1240             }
1241             }
1242              
1243 196 100       379 if (defined $public) {
1244 100 100       257 if ($public =~ m{[\]\[\\]}xms) {
1245 1         4 $self->crknum("Error-0900: illegal character(s) in public id");
1246             }
1247             }
1248              
1249 195 100       473 if (@$plist) {
1250 1         3 $self->crknum("Error-0910: syntax error");
1251             }
1252              
1253 194 50       424 if ($self->{_DocOpen}) {
1254 0         0 $self->crknum("Error-0920: Internal Error - DOC is open");
1255             }
1256              
1257 194         467 $self->_plausi('D'); # PLAUSI ==> 'D' = DocType
1258              
1259 194         239 $self->{_DocOpen} = 1;
1260              
1261 194         277 $self->{_ItemCount}++;
1262              
1263 194         467 my $cb_Doctype = $self->{_Setters}{Doctype};
1264 194 50       387 if ($cb_Doctype) {
1265             # Doctype (Expat, Name, Sysid, Pubid, Internal)
1266 194         669 $cb_Doctype->($self, $name, $system, $public, $intern);
1267             }
1268              
1269 194 100       3703 unless ($intern eq '1') {
1270 103         189 $self->_plausi('F'); # PLAUSI ==> 'F' = DocTypeFin
1271              
1272 103         128 $self->{_DocOpen} = 0;
1273              
1274 103         160 my $cb_DoctypeFin = $self->{_Setters}{DoctypeFin};
1275 103 50       209 if ($cb_DoctypeFin) {
1276             # DoctypeFin (Expat)
1277 103         228 $cb_DoctypeFin->($self);
1278             }
1279             }
1280             }
1281              
1282             sub _parse_Entity {
1283 109     109   129 my $self = shift;
1284 109         134 my ($plist) = @_;
1285              
1286             #
1287             # 'ENTT nam=[prl], val=[madame pernelle], sys=[*undef*], pub=[*undef*], nda=[*undef*], isp=[*undef*]'
1288              
1289             #
1290             # 'ENTT nam=[dialogue_b], val=[*undef*], sys=[dialogue5b.xml], pub=[*undef*], nda=[*undef*], isp=[*undef*]'
1291              
1292             #
1293             # 'UNPS ent=[animation], base=[*undef*], sys=[../anim.fla], pub=[*undef*], not=[flash]',
1294              
1295             #
1296             # 'ENTT nam=[nom3], val=[chaine3], sys=[*undef*], pub=[*undef*], nda=[*undef*], isp=[1]',
1297              
1298             #
1299             # 'ENTT nam=[nom4], val=[*undef*], sys=[uri3], pub=[*undef*], nda=[*undef*], isp=[1]',
1300              
1301 109         99 my $isparam;
1302              
1303 109 100 66     830 if (@$plist and $plist->[0][0] eq 'B' and $plist->[0][1] eq '%') {
      100        
1304 10         14 $isparam = '1';
1305 10         18 shift @$plist;
1306             }
1307              
1308 109         182 my $param0 = shift(@$plist);
1309              
1310 109 50       233 unless (defined $param0) {
1311 0         0 $self->crknum("Error-0930: Internal Error - Not enough elements in ENTITY");
1312             }
1313              
1314 109 100       260 unless ($param0->[0] eq 'B') {
1315 1         4 $self->crknum("Error-0940: syntax error");
1316             }
1317              
1318 108         145 my $name = $param0->[1];
1319              
1320 108         122 my ($value, $val_quote, $base, $system, $sys_quote, $public, $ndata);
1321              
1322 108         163 my $param1 = shift(@$plist);
1323            
1324 108 100       215 unless (defined $param1) {
1325 1         6 $self->crknum("Error-0950: syntax error");
1326             }
1327              
1328 107 100       221 if ($param1->[0] eq 'Q') {
1329 46         75 $value = $param1->[1];
1330 46         69 $val_quote = $param1->[2];
1331             }
1332             else {
1333 61 100       140 unless ($param1->[1] eq 'SYSTEM') {
1334 3 100       11 if ($param1->[1] eq 'PUBLIC') {
1335 2         4 $self->crknum("Error-0960: syntax error");
1336             }
1337             else {
1338 1         7 $self->crknum("Error-0970: not well-formed (invalid token)");
1339             }
1340             }
1341              
1342 58         75 my $param2 = shift(@$plist);
1343              
1344 58 100       114 unless (defined $param2) {
1345 1         3 $self->crknum("Error-0980: syntax error");
1346             }
1347              
1348 57 100       129 unless ($param2->[0] eq 'Q') {
1349 1         4 $self->crknum("Error-0990: syntax error");
1350             }
1351              
1352 56         77 $system = $param2->[1];
1353 56         92 $sys_quote = $param2->[2];
1354              
1355 56         66 my $param3 = shift(@$plist);
1356 56 100       146 if (defined $param3) {
1357 17 100       40 unless ($param3->[0] eq 'B') {
1358 1         4 $self->crknum("Error-1000: syntax error");
1359             }
1360              
1361 16 100       33 unless ($param3->[1] eq 'NDATA') {
1362 1         4 $self->crknum("Error-1010: syntax error");
1363             }
1364              
1365 15         21 my $param4 = shift(@$plist);
1366 15 100       27 unless (defined $param4) {
1367 1         3 $self->crknum("Error-1020: syntax error");
1368             }
1369              
1370 14 100 100     68 unless ($param4->[0] eq 'Q' or $param4->[0] eq 'B') {
1371 1         12 $self->crknum("Error-1030: syntax error");
1372             }
1373              
1374 13         37 $ndata = $param4->[1];
1375             }
1376             }
1377              
1378 98 100       230 if (@$plist) {
1379 1         3 $self->crknum("Error-1040: syntax error");
1380             }
1381              
1382 97 100       238 unless ($self->{_DocOpen}) {
1383 1         4 $self->crknum("Error-1050: syntax error");
1384             }
1385              
1386 96 100       161 if (defined $ndata) {
1387 12         24 $self->_plausi('U'); # PLAUSI ==> 'U' = Unparsed
1388              
1389 12         15 $self->{_ItemCount}++;
1390              
1391 12         25 my $cb_Unparsed = $self->{_Setters}{Unparsed};
1392 12 50       32 if ($cb_Unparsed) {
1393             # Unparsed (Expat, Entity, Base, Sysid, Pubid, Notation)
1394 12         41 $cb_Unparsed->($self, $name, $base, $system, $public, $ndata);
1395             }
1396             }
1397             else {
1398 84 100       265 if (defined $self->{_Var}{$name}) {
1399             #~ Redefinition of '$name' --> emit 2 or 3 Default lines
1400              
1401 3 100       14 my $object = defined($value) ? $val_quote.$value.$val_quote : $sys_quote.$system.$sys_quote;
1402              
1403 3         7 $self->_plausi('T'); # PLAUSI ==> 'T' = Entity
1404              
1405 3         5 $self->{_ItemCount}++;
1406              
1407 3         9 my $cb_Default = $self->{_Setters}{Default};
1408 3 50       9 if ($cb_Default) {
1409             # Default (Expat, String)
1410 3         12 $cb_Default->($self, $name);
1411 3         34 $cb_Default->($self, $object);
1412 3 100       25 unless (defined $value) {
1413 2         5 $cb_Default->($self, '>');
1414             }
1415             }
1416             }
1417             else {
1418 81 100       187 unless (defined $isparam) {
1419 71 100       133 if (defined $value) {
1420 38         168 $self->{_Var}{$name} = [T => $value]; # T => $value is a replacement text
1421             }
1422             else {
1423 33         131 $self->{_Var}{$name} = [F => $system]; # F => $system is a file name, the content of which will be processed
1424             }
1425             }
1426              
1427 81         170 $self->_plausi('T'); # PLAUSI ==> 'T' = Entity
1428              
1429 81         119 $self->{_ItemCount}++;
1430              
1431 81         132 my $cb_Entity = $self->{_Setters}{Entity};
1432 81 50       184 if ($cb_Entity) {
1433             # Entity (Expat, Name, Val, Sysid, Pubid, Ndata, IsParam)
1434 81         293 $cb_Entity->($self, $name, $value, $system, $public, $ndata, $isparam);
1435             }
1436             }
1437             }
1438             }
1439              
1440             sub _parse_Element {
1441 16     16   15 my $self = shift;
1442 16         18 my ($plist) = @_;
1443              
1444             #
1445             # 'ELEM nam=[replique], mod=[(personnage,texte)]',
1446              
1447             #
1448             # 'ELEM nam=[personnage], mod=[(#PCDATA)]',
1449              
1450 16         21 my $param0 = shift(@$plist);
1451              
1452 16 50       31 unless (defined $param0) {
1453 0         0 $self->crknum("Error-1060: Internal Error - Not enough elements in ELEMENT");
1454             }
1455              
1456 16 100       30 unless ($param0->[0] eq 'B') {
1457 1         6 $self->crknum("Error-1070: syntax error");
1458             }
1459              
1460 15         21 my $name = $param0->[1];
1461              
1462 15         18 my $param1 = shift(@$plist);
1463            
1464 15 100       28 unless (defined $param1) {
1465 1         3 $self->crknum("Error-1080: syntax error");
1466             }
1467              
1468 14 100       30 unless ($param1->[0] eq 'P') {
1469 1         3 $self->crknum("Error-1090: syntax error");
1470             }
1471              
1472 13         15 my $model = $param1->[1];
1473              
1474 13 100       35 unless ($self->{_DocOpen}) {
1475 1         3 $self->crknum("Error-1100: syntax error");
1476             }
1477              
1478 12         23 $self->_plausi('L'); # PLAUSI ==> 'L' = Element
1479              
1480 12         17 $self->{_ItemCount}++;
1481              
1482 12         21 my $cb_Element = $self->{_Setters}{Element};
1483 12 50       24 if ($cb_Element) {
1484             # Element (Expat, Name, Model)
1485 12         46 $cb_Element->($self, $name, "($model)");
1486             }
1487              
1488 12 100       152 if (@$plist) {
1489 1         4 $self->crknum("Error-1110: syntax error");
1490             }
1491             }
1492              
1493             sub _parse_Attlist {
1494 36     36   42 my $self = shift;
1495 36         40 my ($plist) = @_;
1496              
1497             #
1498             # 'ATTL eln=[task], atn=[status], typ=[(important|normal)], def=[\'normal\'], fix=[*undef*]',
1499              
1500             #
1501             # 'ATTL eln=[task], atn=[status], typ=[NMTOKEN], def=[\'monthly\'], fix=[1]',
1502              
1503             #
1504             # 'ATTL eln=[description], atn=[xml:lang], typ=[NMTOKEN], def=[\'en\'], fix=[1]',
1505              
1506             #
1507             # 'ATTL eln=[code], atn=[xml:space], typ=[(default|preserve)], def=[\'preserve\'], fix=[*undef*]',
1508            
1509             #
1510             # 'ATTL eln=[personnage], atn=[attitude], typ=[CDATA], def=[#REQUIRED], fix=[*undef*]',
1511             # 'ATTL eln=[personnage], atn=[geste], typ=[CDATA], def=[#IMPLIED], fix=[*undef*]',
1512              
1513             #
1514             # 'ATTL eln=[texte], atn=[ton], typ=[(normal|fort|faible)], def=[\'normal\'], fix=[*undef*]',
1515              
1516 36         49 my $param0 = shift(@$plist);
1517              
1518 36 50       67 unless (defined $param0) {
1519 0         0 $self->crknum("Error-1120: Internal Error - Not enough elements in ATTLIST");
1520             }
1521              
1522 36 100       71 unless ($param0->[0] eq 'B') {
1523 1         4 $self->crknum("Error-1130: syntax error");
1524             }
1525              
1526 35         59 my $name = $param0->[1];
1527              
1528 35         79 while (@$plist) {
1529 38         130 my $param1 = shift(@$plist);
1530              
1531 38 50       67 unless (defined $param1) {
1532 0         0 $self->crknum("Error-1140: Internal Error - Not enough elements in ATTLIST-PARAM1");
1533             }
1534              
1535 38 100       72 unless ($param1->[0] eq 'B') {
1536 1         3 $self->crknum("Error-1150: syntax error");
1537             }
1538              
1539 37         45 my $attrib = $param1->[1];
1540              
1541 37         38 my $param2 = shift(@$plist);
1542              
1543 37 100       64 unless (defined $param2) {
1544 2         8 $self->crknum("Error-1160: syntax error");
1545             }
1546              
1547 35         33 my $atype;
1548              
1549 35 100 100     132 if ($param2->[0] eq 'B' and $param2->[1] eq 'NOTATION') {
1550 4         10 my $pm2b = shift(@$plist);
1551              
1552 4 100       13 unless (defined $pm2b) {
1553 1         3 $self->crknum("Error-1170: syntax error");
1554             }
1555              
1556 3 100       11 unless ($pm2b->[0] eq 'P') {
1557 1         3 $self->crknum("Error-1180: syntax error");
1558             }
1559 2         11 $atype = $param2->[1]."($pm2b->[1])";
1560             }
1561             else {
1562 31 100       70 if ($param2->[0] eq 'B') {
    100          
1563 23         33 $atype = $param2->[1];
1564             }
1565             elsif ($param2->[0] eq 'P') {
1566 7         22 $atype = "($param2->[1])";
1567             }
1568             else {
1569 1         3 $self->crknum("Error-1190: syntax error");
1570             }
1571             }
1572              
1573 32         41 my $param3 = shift(@$plist);
1574              
1575 32 100       59 unless (defined $param3) {
1576 1         3 $self->crknum("Error-1200: syntax error");
1577             }
1578              
1579 31         28 my ($default, $fixed);
1580              
1581 31 100 100     112 if ($param3->[0] eq 'B' and $param3->[1] eq '#FIXED') {
1582 7         15 my $pm3b = shift(@$plist);
1583              
1584 7 100       19 unless (defined $pm3b) {
1585 1         2 $self->crknum("Error-1210: syntax error");
1586             }
1587              
1588 6 100       27 unless ($pm3b->[0] eq 'Q') {
1589 1         4 $self->crknum("Error-1220: syntax error");
1590             }
1591              
1592 5         10 $default = "'$pm3b->[1]'";
1593 5         12 $fixed = '1';
1594             }
1595             else {
1596 24 100       50 if ($param3->[0] eq 'B') {
    100          
1597 16         18 $default = $param3->[1];
1598             }
1599             elsif ($param3->[0] eq 'Q') {
1600 7         17 $default = "'$param3->[1]'";
1601             }
1602             else {
1603 1         5 $self->crknum("Error-1230: syntax error");
1604             }
1605             }
1606              
1607 28 100       85 unless ($self->{_DocOpen}) {
1608 1         6 $self->crknum("Error-1240: syntax error");
1609             }
1610              
1611 27         46 $self->_plausi('I'); # PLAUSI ==> 'I' = Attlist
1612              
1613 27         34 $self->{_ItemCount}++;
1614              
1615 27         42 my $cb_Attlist = $self->{_Setters}{Attlist};
1616 27 50       51 if ($cb_Attlist) {
1617             # Attlist (Expat, Elname, Attname, Type, Default, Fixed)
1618 27         64 $cb_Attlist->($self, $name, $attrib, $atype, $default, $fixed);
1619             }
1620             }
1621             }
1622              
1623             sub _parse_Notation {
1624 16     16   22 my $self = shift;
1625 16         20 my ($plist) = @_;
1626              
1627             #
1628             # 'NOTA not=[name1], base=[*undef*], sys=[URI1], pub=[*undef*]',
1629              
1630             #
1631             # 'NOTA not=[name2], base=[*undef*], sys=[*undef*], pub=[public_ID2]',
1632              
1633             #
1634             # 'NOTA not=[name3], base=[*undef*], sys=[URI3], pub=[public_ID3]',
1635              
1636 16         28 my $param0 = shift(@$plist);
1637              
1638 16 50       46 unless (defined $param0) {
1639 0         0 $self->crknum("Error-1250: Internal Error - Not enough elements in NOTATION");
1640             }
1641              
1642 16 100       39 unless ($param0->[0] eq 'B') {
1643 1         4 $self->crknum("Error-1260: syntax error");
1644             }
1645              
1646 15         23 my $name = $param0->[1];
1647              
1648 15         16 my ($base, $system, $public);
1649              
1650 15         24 my $param1 = shift(@$plist);
1651 15 50       29 if (defined $param1) {
1652 15 100       83 unless ($param1->[0] eq 'B') {
1653 1         17 $self->crknum("Error-1270: syntax error");
1654             }
1655 14         14 my $syspub;
1656 14 100       46 if ($param1->[1] eq 'SYSTEM') {
    100          
1657 4         7 $syspub = 'S';
1658             }
1659             elsif ($param1->[1] eq 'PUBLIC') {
1660 9         16 $syspub = 'P';
1661             }
1662             else {
1663 1         4 $self->crknum("Error-1280: syntax error");
1664             }
1665              
1666 13         19 my $param2 = shift(@$plist);
1667 13 100       32 unless (defined $param2) {
1668 1         3 $self->crknum("Error-1290: syntax error");
1669             }
1670 12 100       30 unless ($param2->[0] eq 'Q') {
1671 1         3 $self->crknum("Error-1300: syntax error");
1672             }
1673              
1674 11 100       27 if ($syspub eq 'S') {
1675 4         6 $system = $param2->[1];
1676             }
1677             else {
1678 7         9 $public = $param2->[1];
1679             }
1680              
1681 11         18 my $param3 = shift(@$plist);
1682 11 100       28 if (defined $param3) {
1683 6 100       18 unless ($param3->[0] eq 'Q') {
1684 1         2 $self->crknum("Error-1310: syntax error");
1685             }
1686              
1687 5 50       12 if ($syspub eq 'S') {
1688 0         0 $public = $param3->[1];
1689             }
1690             else {
1691 5         14 $system = $param3->[1];
1692             }
1693             }
1694             }
1695              
1696 10 100       27 unless ($self->{_DocOpen}) {
1697 1         5 $self->crknum("Error-1320: syntax error");
1698             }
1699              
1700 9         18 $self->_plausi('O'); # PLAUSI ==> 'O' = Notation
1701              
1702 9         13 $self->{_ItemCount}++;
1703              
1704 9         20 my $cb_Notation = $self->{_Setters}{Notation};
1705 9 50       21 if ($cb_Notation) {
1706             # Notation (Expat, Notation, Base, Sysid, Pubid)
1707 9         32 $cb_Notation->($self, $name, $base, $system, $public);
1708             }
1709              
1710 9 100       188 if (@$plist) {
1711 1         6 $self->crknum("Error-1330: syntax error");
1712             }
1713             }
1714              
1715             sub _plausi {
1716 3045     3045   2742 my $self = shift;
1717 3045         2928 my ($pl) = @_;
1718 3045 50 100     40741 my $tp = $pl eq 'D' || $pl eq 'F' || $pl eq 'U' || $pl eq 'I' || $pl eq 'L' || $pl eq 'O' || $pl eq 'T' ? 'DTD'
    100 100        
    100 100        
    100          
    100          
1719             : $pl eq 'A' || $pl eq 'C' || $pl eq '!' ? 'TXT'
1720             : $pl eq 'S' || $pl eq 'E' ? 'TAG'
1721             : $pl eq 'P' ? 'PRC'
1722             : $pl eq 'X' ? 'XML'
1723             : $self->crknum("Error-1340: Internal Error - encountered plausi code = '$pl'");
1724              
1725 3045         3639 my $stage = $self->{_Stage};
1726              
1727             # PLAUSI ==> TXT - 'A' = CData
1728             # PLAUSI ==> TXT - 'C' = Character Data
1729             # PLAUSI ==> DTD - 'D' = DocType
1730             # PLAUSI ==> TAG - 'E' = End Tag
1731             # PLAUSI ==> DTD - 'F' = DocTypeFin
1732             # PLAUSI ==> DTD - 'I' = Attlist
1733             # PLAUSI ==> DTD - 'L' = Element
1734             # PLAUSI ==> DTD - 'O' = Notation
1735             # PLAUSI ==> PRC - 'P' = Processing Instruction
1736             # PLAUSI ==> TAG - 'S' = Start Tag
1737             # PLAUSI ==> DTD - 'T' = Entity
1738             # PLAUSI ==> DTD - 'U' = Unparsed
1739             # PLAUSI ==> PRC - 'X' = XML Declaration
1740             # PLAUSI ==> TXT - '!' = comment
1741              
1742             # Stage = 1 -->
1743             # Stage = 2 --> DTD
1744             # Stage = 3 --> , Character, CData,
1745             # Stage = 4 --> after...
1746              
1747 3045 100       5503 if ($stage == 1) {
    100          
1748 1163 50       2837 if ($tp eq 'DTD') {
    100          
1749 0         0 $stage = 2;
1750             }
1751             elsif ($pl eq 'S') {
1752 40         62 $stage = 3;
1753             }
1754             }
1755             elsif ($stage == 2) {
1756 1378 100       2247 if ($pl eq 'S') {
1757 77         107 $stage = 3;
1758             }
1759             }
1760              
1761 3045 100       5634 if ($stage == 1) {
    100          
    100          
    50          
1762 1123 50 100     4210 unless ($pl eq 'X' or $pl eq 'C' or $pl eq '!') {
      66        
1763 0         0 $self->crknum("Error-1350: Internal Error - Found invalid callback, plausi = '$pl' at stage 1");
1764             }
1765 1123 100       1852 if ($pl eq 'X') {
1766 243         313 $stage = 2;
1767             }
1768             }
1769             elsif ($stage == 2) {
1770 1301 50 100     4257 unless ($tp eq 'DTD' or $pl eq 'C' or $pl eq '!') {
      66        
1771 0         0 $self->crknum("Error-1360: Internal Error - Expected 'DTD', but found '$tp', plausi = '$pl' at stage 2");
1772             }
1773             }
1774             elsif ($stage == 3) {
1775 593 50 100     2334 unless ($tp eq 'TAG' or $tp eq 'PRC' or $tp eq 'TXT') {
      66        
1776 0         0 $self->crknum("Error-1370: Internal Error - Expected 'TAG', 'PRC' or 'TXT', but found '$tp', plausi = '$pl' at stage 3");
1777             }
1778 593 100 100     1402 if ($pl eq 'E' and $self->{_Scount} == 0) {
1779 78         109 $stage = 4;
1780             }
1781             }
1782             elsif ($stage == 4) {
1783 28 100       61 unless ($pl eq 'C') {
1784 1         2 $self->crknum("Error-1380: junk after document element");
1785             }
1786             }
1787             else {
1788 0         0 $self->crknum("Error-1390: Internal Error - invalid stage = $stage");
1789             }
1790              
1791 3044         5513 $self->{_Stage} = $stage;
1792             }
1793              
1794             sub _update_ctr {
1795 3873     3873   3400 my $self = shift;
1796 3873         3915 my ($emit) = @_;
1797              
1798 3873         4804 $self->{_Read_Bytes} += length($emit);
1799 3873         4983 $self->{_Read_Lines} += $emit =~ tr{\n}{};
1800            
1801 3873 100       7396 if($emit =~ m{\n ([^\n]*) \z}xms) {
1802 421         881 $self->{_Read_Cols} = length($1) + 2;
1803             }
1804             else {
1805 3452         4493 $self->{_Read_Cols} += length($emit);
1806             }
1807             }
1808              
1809             sub parse_done {
1810 81     81   588 my $self = shift;
1811              
1812 81 100       228 if ($self->{_Action} eq 'F') {
1813 4         11 $self->crknum("Error-1400: unclosed token");
1814             }
1815              
1816 77 100       207 if ($self->{_Action} eq 'G') {
1817 1         5 $self->crknum("Error-1410: syntax error");
1818             }
1819              
1820 76 100       73 if (@{$self->{_Stack}}) {
  76         207  
1821 1         6 $self->crknum("Error-1420: no element found");
1822             }
1823              
1824 75 50       208 unless ($self->{_Scount} == 0) {
1825 0         0 $self->crknum("Error-1430: Internal Error - no element found");
1826             }
1827              
1828 75 100       192 unless ($self->{_Text} eq '') {
1829 1         5 $self->crknum("Error-1440: unclosed token");
1830             }
1831              
1832 74         195 $self->_emit_Final;
1833              
1834             # $self->release; # nothing needs to be released, everything is reference counted
1835             }
1836              
1837 701     701   35421 sub release { # dummy subroutine, nothing needs to be released, everything is reference counted
1838             }
1839              
1840             sub crknum {
1841 708     708   825 my $self = shift;
1842              
1843 708         2502 my $pos = 'at line '.$self->{_Read_Lines}.', column '.$self->{_Read_Cols}.', byte '.$self->{_Read_Bytes};
1844              
1845 708         78568 croak($_[0].' '.$pos);
1846             }
1847              
1848             1;
1849              
1850             __END__