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