File Coverage

blib/lib/Data/Sofu/Binary/Bin0200.pm
Criterion Covered Total %
statement 457 509 89.7
branch 139 200 69.5
condition 30 57 52.6
subroutine 47 49 95.9
pod 39 43 90.7
total 712 858 82.9


line stmt bran cond sub pod time code
1             ###############################################################################
2             #List.pm
3             #Last Change: 2008-02-07
4             #Copyright (c) 2008 Marc-Seabstian "Maluku" Lucksch
5             #Version 0.28
6             ####################
7             #This file is part of the sofu.pm project, a parser library for an all-purpose
8             #ASCII file format. More information can be found on the project web site
9             #at http://sofu.sourceforge.net/ .
10             #
11             #sofu.pm is published under the terms of the MIT license, which basically means
12             #"Do with it whatever you want". For more information, see the license.txt
13             #file that should be enclosed with libsofu distributions. A copy of the license
14             #is (at the time of this writing) also available at
15             #http://www.opensource.org/licenses/mit-license.php .
16             ###############################################################################
17              
18              
19             =head1 NAME
20              
21             Data::Sofu::Binary::Bin0200 - Driver for Sofu Binary version 0.2.0.0
22              
23             =head1 DESCRIPTION
24              
25             Driver for C and C
26              
27             =head1 Synopsis
28              
29             See C
30              
31             =head1 SYNTAX
32              
33             This Module is pure OO, exports nothing
34              
35             =cut
36              
37              
38             package Data::Sofu::Binary::Bin0200;
39 1     1   6 use strict;
  1         3  
  1         38  
40 1     1   6 use warnings;
  1         2  
  1         33  
41 1     1   7 use bytes;
  1         3  
  1         8  
42              
43             our $VERSION="0.29";
44             #We are really going to need these modules:
45 1     1   45 use Encode;
  1         2  
  1         107  
46 1     1   7 use Carp qw/confess/;
  1         3  
  1         52  
47             require Data::Sofu;
48 1     1   6 use base qw/Data::Sofu::Binary/;
  1         2  
  1         6422  
49              
50             #$SIG{__WARN__}=sub { confess @_;};
51              
52             =head1 METHODS
53              
54             See also C for public methods.
55              
56             All these methods are INTERNAL, not for use outside of this module...
57              
58             Except pack().
59              
60             =head2 new()
61              
62             Creates a new Binary Driver using DRIVER or the latest one available.
63              
64             require Data::Sofu::Binary;
65             $bsofu = Data::Sofu::Binary->new("000_002_000_000"); Taking this driver;
66             #You can call it directly:
67             require Data::Sofu::Binary::Bin0200;
68             $bsofu = Data::Sofu::Binary::Bin0200->new(); #The same
69              
70             =cut
71              
72             sub new {
73 7     7 1 15 my $class=shift;
74 7         19 my $self={};
75 7         24 bless $self,$class;
76 7         35 $self->{OBJECT}=0;
77 7         21 $self->{COMMENTS}=[];
78 7         31 $self->{SUPPORTED}={"000_002_000_000"=>1};
79 7         453 return $self;
80             }
81              
82             =head2 encoding(ID)
83              
84             Switches and/or detetect the encoding.
85              
86             See pack() for more on encodings.
87              
88             =cut
89              
90             sub encoding { #Switches the Encoding
91 135     135 1 553 my $self=shift;
92 135         226 my $id=shift;
93 135         686 my @encoding = qw/UTF-8 UTF-7 UTF-16 UTF-16BE UTF-16LE UTF-32 UTF-32BE UTF-32LE null null ascii cp1252 latin1 Latin9 Latin10/;
94 135         207 my %encoding;
95 135         383 @encoding{map {lc $_} @encoding} = (0 .. 12);
  2025         6637  
96 135 100       2780 if (exists $encoding{lc $id}) {
97 31         108 $self->{EncID}=$encoding{lc $id};
98 31         250 return $self->{Encoding}=$encoding[$self->{EncID}];
99             }
100 104 50       356 if ($encoding[int $id]) {
101 104         251 $self->{EncID}=$id;
102 104         860 return $self->{Encoding}=$encoding[$id];
103             }
104 0         0 $self->die("Unknown Encoding");
105            
106             }
107              
108             =head2 byteorder(BOM)
109              
110             Internal method.
111              
112             Switches the byteorder.
113              
114             See pack() for more on byteorders.
115              
116             =cut
117              
118              
119             sub byteorder {
120 58     58 1 111 my $self=shift;
121 58         88 my $bo=shift;
122 58 100       302 if ($bo =~ m/le/i) { #little Endian
123 9         28 $self->{SHORT}="v";
124 9         29 $self->{LONG}="V";
125 9         59 return 0;
126             }
127 49 100       169 if ($bo =~ m/be/i) { #BIG Endian
128 10         37 $self->{SHORT}="n";
129 10         29 $self->{LONG}="N";
130 10         80 return 0;
131             }
132 39 100       173 if ($bo=~m/7/) { #7-Bit Mode
133 19         58 $self->{SHORT}=undef;
134 19         58 $self->{LONG}=undef;
135 19         93 $self->encoding(1);
136 19         90 return 1;
137             }
138 20 50       59 if ($bo=~m/Force/i) { #7-Bit Mode without UTF-7 encoding
139 0         0 $self->{SHORT}=undef;
140 0         0 $self->{LONG}=undef;
141             #$self->encoding(1);
142 0         0 return 0;
143             }
144 20         57 $self->{SHORT}="S";
145 20         40 $self->{LONG}="L";
146 20         136 return 0;
147              
148             }
149              
150              
151             =head2 bom(BOM)
152              
153             Internal method.
154              
155             Detects the byteorder.
156              
157             See pack() for more on byteorders.
158              
159             =cut
160              
161             sub bom {
162 58     58 1 103 my $self=shift;
163 58         98 my $bo=shift;
164 58 100       195 if ($bo==1) { #Machine Order
165 29         75 $self->{SHORT}="S";
166 29         124 $self->{LONG}="L";
167 29         57 return 0;
168             }
169 29 100       144 if ($bo==256) { #Wrong Order
170 10 50       55 if (1 == CORE::unpack('S',pack('v',1))) {# We are little Endian
171 10         34 $self->{SHORT}="n";
172 10         26 $self->{LONG}="N";
173             }
174             else {
175 0         0 $self->{SHORT}="v";
176 0         0 $self->{LONG}="V";
177             }
178 10         25 return 0;
179             }
180 19 50       79 if ($bo==0) { #7-Bit Mode
181 19         51 $self->{SHORT}=undef;
182 19         59 $self->{LONG}=undef;
183 19         73 $self->encoding(1);
184 19         36 return 1;
185             }
186 0         0 $self->die("Unknown Byteorder: $bo, can't continue");
187 0         0 return 0;
188              
189             }
190              
191             =head2 packShort(INT)
192              
193             Packs one int-16 to binary using the set byteorder
194              
195             =cut
196              
197             sub packShort {
198 39     39 1 66 my $self=shift;
199 39         68 my $i=shift;
200 39 50       121 $self->die("Short too large: $i") if $i > 65535;
201 39 50       415 return pack $self->{SHORT},$i if $self->{SHORT};
202 0 0       0 $self->die("Can't pack that Short in 7-Bit, too large: $i") if $i > 16383;
203 0         0 return pack ("CC",($i&0x7F),($i&0x3F80));
204             }
205              
206             =head2 packLong(INT)
207              
208             Packs one int-32 to binary using the set byteorder
209              
210             =cut
211              
212             sub packLong {
213 4350     4350 1 5453 my $self=shift;
214 4350         7197 my $i=shift;
215 4350 50       15883 $self->die("Long too large: $i") if $i > 4294967295;
216 4350 100       27831 return pack $self->{LONG},$i if $self->{LONG};
217 1425 50       12407 $self->die("Can't pack that Long in 7-Bit, too large: $i") if $i > 268435455;
218 1425         36163 return pack ("CCCC",($i&0x7F),(($i&0x3F80) >> 7),(($i&0x1FC000) >> 14),(($i&0xFE00000) >> 21));
219             }
220              
221             =head2 packendian()
222              
223             Returns the byte order mark for this file.
224              
225             =cut
226              
227             sub packendian {
228 58     58 1 92 my $self=shift;
229 58 100       187 if ($self->{SHORT}) {
230 39         161 return $self->packShort(1);
231             }
232 19         60 return pack("S",0);
233             }
234              
235             =head2 packversion()
236              
237             Returns the version of this driver to put in the file.
238              
239             =cut
240              
241             sub packversion {
242 58     58 1 92 my $self=shift;
243 58         8766 return pack("CCCC",0,2,0,0);
244             }
245              
246             =head2 packencoding()
247              
248             Returns the current encoding to put in the output file.
249              
250             =cut
251              
252             sub packencoding {
253 58     58 1 133 my $self=shift;
254 58         284 return pack("C",$self->{EncID});
255             }
256              
257             =head2 getType()
258              
259             Tries to find out what SofuObject to deserialise next
260              
261             Returns:
262              
263             0 for Undefined / undef
264              
265             1 for Value / Scalar
266              
267             2 for List / Array
268              
269             3 for Map / Hash
270              
271             4 for Reference / Ref
272              
273             =cut
274              
275             sub getType {
276 1914     1914 1 3891 my $self=shift;
277 1914         8822 my $type = $self->get(1);
278 1914 50       4557 $self->die ("Unexpected End of File") unless $type;
279 1914 100       4924 if ($type eq "S") {
280 537         6086 my $str = $self->get(3);
281 537 50 33     3679 $self->die("Incomplete Sofu-Mark") if not $str or $str ne "ofu";
282 537         1459 $type = $self->get(1);
283             }
284 1914 50       5585 $self->die("No Type found") unless defined $type;
285 1914         3704 $type=CORE::unpack("C",$type);
286 1914 50       3743 $self->die("Unknown Type: $type") if $type > 4;
287 1914         6278 return $type;
288             }
289              
290             =head2 objectprocess()
291              
292             Postprocess the SofuObjects, sets References to their targets.
293              
294             =cut
295              
296             sub objectprocess {
297 32     32 1 41 my $self=shift;
298 32         147 $self->{Ref}->{""} = $self->{Ref}->{"->"} = $self->{Ref}->{"="};
299 32         58 foreach my $e (@{$$self{References}}) {
  32         115  
300 160 50       5518 next if $e->valid();
301 160         470 my $target = $e->follow()."";
302 160         1664 $target=~s/^@//;
303 160 50 33     2189 $target="->".$target if $target and $target !~ m/^->/;
304 160 50       1254 $e->dangle($self->{Ref}->{$target}) if $self->{Ref}->{$target};
305             }
306             }
307              
308             =head2 postprocess()
309              
310             Postprocess perl datastructures , sets References to their targets.
311              
312             =cut
313              
314             sub postprocess {
315 26     26 1 48 my $self=shift;
316 26         118 $self->{Ref}->{""} = $self->{Ref}->{"->"} = $self->{Ref}->{"="};
317 26         64 foreach my $e (@{$$self{References}}) {
  26         77  
318             #next;
319             #print $$e;
320 52         92 my $target = $$$e;
321 52         211 $target=~s/^@//;
322 52 50 33     356 $target="->".$target if $target and $target !~ m/^->/;
323 52         83 $$e = undef;
324 52 50       278 $$e = $self->{Ref}->{$target} if $self->{Ref}->{$target};
325             }
326             }
327              
328             =head2 getLong()
329              
330             Decodes one Int-32 from the input stream according to the byteorder and returns it.
331              
332             =cut
333              
334             sub getLong {
335 4408     4408 1 17789 my $self=shift;
336 4408         9606 my $i=shift;
337 4408 100       19322 return undef unless defined $i;
338 4350 100       18517 return CORE::unpack($self->{LONG},$i) if $self->{LONG};
339 1425         4706 my @i = CORE::unpack("CCCC",$i);
340             #print join(", ",@i),"\n";
341 1425         5587 return( (($i[0] & 0x7F) | (($i[1] & 0x7F) << 7) | (($i[2] & 0x7F) << 14) | (($i[3] & 0x7F) << 21)) );
342             }
343              
344              
345             =head2 getText()
346              
347             Decodes one String according to encoding from the inputstream and returns it
348              
349             =cut
350              
351             sub getText {
352 3886     3886 1 7236 my $self=shift;
353 3886         11502 my $len=$self->getLong($self->get(4));
354 3886 100       8507 return undef unless defined $len;
355 3828 100       10751 return "" if $len == 0;
356 2030         7415 my $text = $self->get($len);
357 2030         50819 return Encode::decode($self->{Encoding},$text,Encode::FB_CROAK);
358            
359             }
360              
361             =head2 getComment(TREE)
362              
363             decodes one comment and sets it to TREE
364              
365             TREE can be a string describing the tree or a Data::Sofu::Object.
366              
367             =cut
368              
369             sub getComment {
370 1972     1972 1 6246 my $self=shift;
371 1972         2323 my $tree=shift;
372 1972         3920 my $t = $self->getText();
373 1972 50       15672 $self->die("Can't get Comment, EOF!") unless defined $t;
374 1972 100       4697 return if $t eq "";
375 232 100       597 if (ref $tree) {
376 128         8268 $tree->setComment([split /\n/,$t]);
377             }
378             else {
379 104         592 $self->{COMMENTS}->{$tree}=[split /\n/,$t];
380             }
381            
382             }
383              
384             =head2 unpackUndef(TREE)
385              
386             Returns undef and packs it comment
387              
388             =cut
389              
390             sub unpackUndef {
391 26     26 1 34 my $self=shift;
392 26         53 my $tree=shift;
393 26         56 $self->getComment($tree);
394 26         65 return undef;
395              
396             }
397              
398             =head2 unpackScalar(TREE)
399              
400             Decodes one scalar and its comment.
401              
402             =cut
403              
404              
405             sub unpackScalar {
406 546     546 1 556 my $self=shift;
407 546         575 my $tree=shift;
408 546         943 $self->getComment($tree);
409 546         1017 return $self->getText();
410              
411             }
412              
413             =head2 unpackRef(TREE)
414              
415             Decodes one ref and its comment.
416              
417             =cut
418              
419              
420             sub unpackRef {
421 52     52 1 71 my $self=shift;
422 52         4195 my $tree=shift;
423 52         265 $self->getComment($tree);
424 52         106 my $x = $self->getText();
425 52         1668 return \$x;
426              
427             }
428              
429              
430             =head2 unpackHash(TREE)
431              
432             Decodes a hash, its comment and its content
433              
434             =cut
435              
436             sub unpackHash {
437 78     78 1 99 my $self=shift;
438 78         94 my $tree=shift;
439 78         139 my %result=();
440 78         176 $self->getComment($tree);
441 78         227 my $len=$self->getLong($self->get(4));
442 78 50       206 $self->die("Error while reading maplength, maybe EOF") unless defined $len;
443 78 50       187 return {} if $len == 0;
444 78         223 keys(%result) = $len; #Presetting the Hashsize
445 78         241 for (my $i = 0;$i < $len;$i++) {
446 104         212 my $key = $self->getText();
447 104 50       3094 $self->die("Error while reading key, maybe EOF") unless defined $key;
448 104         266 my $kkey = Data::Sofu::Sofukeyescape($key);
449 104         222 my $type = $self->getType();
450 104         339 $result{$key} = $self->unpackType($type,"$tree->$kkey");
451 104         1409 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
452 104 100       349 push @{$self->{References}},\$result{$key} if ($type == 4);
  26         131  
453             }
454 78         289 return \%result;
455            
456             }
457              
458              
459             =head2 unpackHash(TREE)
460              
461             Decodes an array, its comment and its content
462              
463             =cut
464              
465              
466             sub unpackArray {
467 156     156 0 210 my $self=shift;
468 156         175 my $tree=shift;
469 156         199 my @result=();
470 156         324 $self->getComment($tree);
471 156         383 my $len=$self->getLong($self->get(4));
472 156 50       372 $self->die("Error while reading listlength, maybe EOF") unless defined $len;
473 156 50       306 return {} if $len == 0;
474             #die $len,"\n";
475 156         464 $#result = $len-1; #Grow the Array :)
476 156         382 for (my $i = 0;$i < $len;$i++) {
477 624         1158 my $type = $self->getType();
478 624         1981 $result[$i] = $self->unpackType($type,"$tree->$i");
479 624         24476 $self->{Ref}->{"$tree->$i"}=$result[$i];
480 624 100       2074 push @{$self->{References}},\$result[$i] if ($type == 4);
  26         107  
481             }
482 156         637 return \@result;
483            
484             }
485              
486              
487             =head2 C
488              
489             Decodes a datastructure of TYPE.
490              
491             =cut
492              
493              
494             sub unpackType {
495 858     858 1 1078 my $self=shift;
496 858         921 my $type=shift;
497 858         894 my $tree=shift;
498 858 100       2359 if ($type == 0) {
    100          
    100          
    100          
    50          
499 26         77 return $self->unpackUndef($tree);
500             }
501             elsif ($type == 1) {
502 546         1057 return $self->unpackScalar($tree);
503             }
504             elsif ($type == 2) {
505 156         349 return $self->unpackArray($tree);
506             }
507             elsif ($type == 3) {
508 78         186 return $self->unpackHash($tree);
509             }
510             elsif ($type == 4) {
511 52         207 return $self->unpackRef($tree);
512             }
513             }
514              
515              
516             =head2 unpack(BOM)
517              
518             Starts unpacking using BOM, gets encoding and the contents
519              
520             =cut
521              
522              
523             sub unpack {
524 26     26 1 53 my $self=shift;
525 26         46 my $bom=shift;
526 26         65 $self->{COMMENTS}={};
527 26         66 $self->{References}=[];
528 26         84 $self->{Ref}={};
529 26         540 $self->bom($bom);
530 26         87 my $encoding = $self->get(1);
531 26 50       63 $self->die("No Encoding!") unless defined $encoding;
532 26         96 $self->encoding(CORE::unpack("C",$encoding));
533 26         47 my $tree="";
534 26         65 my %result=();
535 26         185 $self->getComment("=");
536 26         144 while (defined (my $key = $self->getText())) {
537 130         7958 my $kkey = Data::Sofu::Sofukeyescape($key);
538 130         471 my $type = $self->getType();
539 130         420 $result{$key} = $self->unpackType($type,"$tree->$kkey");
540 130         1228 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
541 130 50       475 push @{$self->{References}},\$result{$key} if ($type == 4);
  0         0  
542             }
543 26         103 $self->{Ref}->{"="}=\%result;
544 26         116 $self->postprocess(); #Setting References right.
545 26         165 return (\%result,$self->{COMMENTS});
546            
547             }
548              
549              
550             =head2 unpackUndefined(TREE)
551              
552             Unpacks a Data::Sofu::Undefined and its comment.
553              
554             =cut
555              
556             sub unpackUndefined {
557 32     32 1 59 my $self=shift;
558 32         62 my $tree=shift;
559 32         330 my $und = Data::Sofu::Undefined->new();
560 32         109 $self->getComment($und);
561 32         86 return $und;
562              
563             }
564              
565              
566             =head2 unpackValue(TREE)
567              
568             Unpacks a Data::Sofu::Value, its content and its comment.
569              
570             =cut
571              
572             sub unpackValue {
573 576     576 1 681 my $self=shift;
574 576         674 my $tree=shift;
575 576         3505 my $value = Data::Sofu::Value->new("");
576 576         3683 $self->getComment($value);
577 576         1408 $value->set($self->getText());
578 576         15620 return $value;
579              
580             }
581              
582              
583             =head2 unpackReference(TREE)
584              
585             Unpacks a Data::Sofu::Reference, its content and its comment.
586              
587             =cut
588              
589             sub unpackReference {
590 160     160 1 335 my $self=shift;
591 160         356 my $tree=shift;
592 160         780 my $ref = Data::Sofu::Reference->new();
593 160         530 $self->getComment($ref);
594 160         767 $ref->dangle($self->getText());
595 160         2152 return $ref;
596              
597             }
598              
599              
600             =head2 unpackMap(TREE)
601              
602             Unpacks a Data::Sofu::Map, its content and its comment.
603              
604             =cut
605              
606             sub unpackMap {
607 0     0 1 0 my $self=shift;
608 0         0 my $tree=shift;
609 0         0 my $map=Data::Sofu::Map->new();
610 0         0 $self->getComment($map);
611 0         0 my $len=$self->getLong($self->get(4));
612 0 0       0 $self->die("Error while reading maplength, maybe EOF") unless defined $len;
613 0 0       0 return $map if $len == 0;
614 0         0 for (my $i = 0;$i < $len;$i++) {
615 0         0 my $key = $self->getText();
616 0 0       0 $self->die("Error while reading key, maybe EOF") unless defined $key;
617 0         0 my $kkey = Data::Sofu::Sofukeyescape($key);
618 0         0 my $type = $self->getType();
619 0         0 my $res = $self->unpackObjectType($type,"$tree->$kkey");
620 0         0 $self->{Ref}->{"$tree->$kkey"}=$res;
621 0 0       0 push @{$self->{References}},$res if ($type == 4);
  0         0  
622 0         0 $map->setAttribute($key,$res);
623             }
624 0         0 return $map;
625            
626             }
627              
628              
629             =head2 unpackMap2(TREE)
630              
631             Unpacks a Data::Sofu::Map, its content and its comment.
632              
633             (Speed optimized, but uses dirty tricks)
634              
635             =cut
636              
637             sub unpackMap2 { #faster version, using the perlinterface
638 96     96 1 119 my $self=shift;
639 96         153 my $tree=shift;
640 96         195 my %result=();
641 96         175 my @order=();
642 96         607 my $map=Data::Sofu::Map->new();
643 96         287 $self->getComment($map);
644 96         423 my $len=$self->getLong($self->get(4));
645 96 50       275 $self->die("Error while reading maplength, maybe EOF") unless defined $len;
646 96 50       204 return $map if $len == 0;
647 96         500 keys(%result) = $len; #Presetting the Hashsize
648 96         472 $#order=($len-1);
649 96         342 for (my $i = 0;$i < $len;$i++) {
650 128         443 my $key = $self->getText();
651 128 50       5155 $self->die("Error while reading key, maybe EOF") unless defined $key;
652 128         481 my $kkey = Data::Sofu::Sofukeyescape($key);
653 128         346 my $type = $self->getType();
654 128         544 $result{$key} = $self->unpackObjectType($type,"$tree->$kkey");
655             #push @order,$key;
656 128         307 $order[$i] = $key;
657 128         865 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
658 128 100       1930 push @{$self->{References}},$result{$key} if ($type == 4);
  32         171  
659             }
660 96         317 $map->{Order}=\@order;
661 96         212 $map->{Map}=\%result;
662 96         429 return $map;
663            
664             }
665              
666             =head2 unpackList(TREE)
667              
668             Unpacks a Data::Sofu::List, its content and its comment.
669              
670             =cut
671              
672             sub unpackList {
673 0     0 1 0 my $self=shift;
674 0         0 my $tree=shift;
675 0         0 my $list=Data::Sofu::List->new();
676 0         0 $self->getComment($list);
677 0         0 my $len=$self->getLong($self->get(4));
678 0 0       0 $self->die("Error while reading listlength, maybe EOF") unless defined $len;
679 0 0       0 return $list if $len == 0;
680 0         0 for (my $i = 0;$i < $len;$i++) {
681 0         0 my $type = $self->getType();
682 0         0 my $res = $self->unpackObjectType($type,"$tree->$i");
683 0         0 $self->{Ref}->{"$tree->$i"}=$res;
684 0 0       0 push @{$self->{References}},$res if ($type == 4);
  0         0  
685 0         0 $list->appendElement($res);
686             }
687 0         0 return $list;
688            
689             }
690              
691              
692             =head2 unpackList2(TREE)
693              
694             Unpacks a Data::Sofu::List, its content and its comment.
695              
696             (Speed optimized, but uses dirty tricks)
697              
698             =cut
699              
700              
701             sub unpackList2 { #faster version, using the perlinterface
702 192     192 1 324 my $self=shift;
703 192         251 my $tree=shift;
704 192         1078 my $list=Data::Sofu::List->new();
705 192         878 $self->getComment($list);
706 192         291 my @result;
707 192         553 my $len=$self->getLong($self->get(4));
708 192 50       456 $self->die("Error while reading listlength, maybe EOF") unless defined $len;
709 192 50       400 return $list if $len == 0;
710             #die $len,"\n";
711 192         2408 $#result = $len-1; #Grow the Array :)
712 192         1214 for (my $i = 0;$i < $len;$i++) {
713 768         1923 my $type = $self->getType();
714 768         7340 $result[$i] = $self->unpackObjectType($type,"$tree->$i");
715 768         6412 $self->{Ref}->{"$tree->$i"}=$result[$i];
716 768 100       4092 push @{$self->{References}},$result[$i] if ($type == 4);
  128         650  
717             }
718 192         437 $list->{List}=\@result;
719 192         792 return $list;
720            
721             }
722              
723             =head2 C
724              
725             Unpacks a datastructure defined by TYPE
726              
727             =cut
728              
729             sub unpackObjectType {
730 1056     1056 1 1489 my $self=shift;
731 1056         1456 my $type=shift;
732 1056         3764 my $tree=shift;
733 1056 100       7122 if ($type == 0) {
    100          
    100          
    100          
    50          
734 32         206 return $self->unpackUndefined($tree);
735             }
736             elsif ($type == 1) {
737 576         2127 return $self->unpackValue($tree);
738             }
739             elsif ($type == 2) {
740 192         723 return $self->unpackList2($tree);
741             }
742             elsif ($type == 3) {
743 96         272 return $self->unpackMap2($tree);
744             }
745             elsif ($type == 4) {
746 160         8864 return $self->unpackReference($tree);
747             }
748             }
749              
750              
751             =head2 unpack(BOM)
752              
753             Starts unpacking into a Data::Sofu::Object structure using BOM, gets encoding and the contents
754              
755             =cut
756              
757              
758             sub unpackObject {
759 32     32 0 61 my $self=shift;
760 32         52 my $bom=shift;
761 32         104 $self->{References}=[];
762 32         135 $self->{Ref}={};
763 32         932 $self->bom($bom);
764 32         121 my $encoding = $self->get(1);
765 32 50       138 $self->die("No Encoding!") unless defined $encoding;
766 32         178 $self->encoding(CORE::unpack("C",$encoding));
767 32         94 my $tree="";
768 32         375 my $map = Data::Sofu::Map->new();
769 32         151 $self->getComment($map);
770 32         113 while (defined (my $key = $self->getText())) {
771 160         6922 my $kkey = Data::Sofu::Sofukeyescape($key);
772 160         957 my $type = $self->getType();
773 160         655 my $res = $self->unpackObjectType($type,"$tree->$kkey");
774 160         676 $self->{Ref}->{"$tree->$kkey"}=$res;
775 160 50       381 push @{$self->{References}},$res if ($type == 4);
  0         0  
776 160         1165 $map->setAttribute($key,$res);
777              
778             }
779 32         106 $self->{Ref}->{"="}=$map;
780 32         700 $self->objectprocess(); #Setting References right.
781 32         201 return $map;
782            
783             }
784              
785              
786             =head2 packType(TYPE)
787              
788             Encodes Type information and returns it.
789              
790             =cut
791              
792             sub packType {
793 1914     1914 1 2450 my $self=shift;
794 1914         2216 my $type=shift;
795 1914         12528 my $str="";
796 1914 100       4412 if ($self->{Mark}) {
797 759 100       2191 $str="Sofu" if rand() < $self->{Mark};
798             }
799 1914         10997 return $str.pack("C",$type);
800             }
801              
802             =head2 packText(STRING)
803              
804             Encodes a STRING using Encoding and returns it.
805              
806             =cut
807              
808             sub packText {
809 2268     2268 1 3952 my $self=shift;
810 2268         3000 my $text=shift;
811 2268 100 66     14538 return $self->packLong(0) if not defined $text or $text eq "";
812 2030         10737 $text = Encode::encode($self->{Encoding},$text,Encode::FB_CROAK);
813 2030         119137 return $self->packLong(length($text)).$text;
814             }
815              
816             =head2 C
817              
818             Encodes one perl datastructure and its contents and returns it.
819              
820             =cut
821              
822             sub packData {
823 858     858 1 1047 my $self=shift;
824 858         1066 my $data=shift;
825 858         900 my $tree=shift;
826 858         905 my $type=1;
827 858 100       1402 if (ref $data) {
828 286         372 my $r=ref $data;
829 286 100       632 if ($r eq "ARRAY") {
    50          
830 156         242 $type=2;
831             }
832             elsif ($r eq "HASH") {
833 130         167 $type=3;
834             }
835             else {
836 0         0 $self->die("Unknown Datastructure, can only work with Arrays and Hashes but not $r");
837             }
838 286 100       961 if ($self->{SEEN}->{$data}) {
839 52         123 return $self->packType(4).$self->packComment($tree).$self->packText("@".$self->{SEEN}->{$data});
840             }
841             }
842             else {
843 572 100       887 if (defined ($data)) {
844 546         1341 return $self->packType(1).$self->packComment($tree).$self->packText($data);
845             }
846             else {
847 26         68 return $self->packType(0).$self->packComment($tree);
848             }
849             }
850 234         630 $self->{SEEN}->{$data}=$tree;
851 234 100       457 if ($type==3) {
852 78         210 return $self->packType(3).$self->packComment($tree).$self->packHash($data,$tree);
853             }
854 156         351 return $self->packType(2).$self->packComment($tree).$self->packArray($data,$tree);
855             }
856              
857             =head2 C
858              
859             Encodes one perl array and its contents and returns it.
860              
861             =cut
862              
863             sub packArray {
864 156     156 1 189 my $self=shift;
865 156         170 my $data=shift;
866 156         176 my $tree=shift;
867 156         179 my $str=$self->packLong(scalar @{$data});
  156         364  
868 156         233 my $i=0;
869 156         156 foreach my $element (@{$data}) {
  156         319  
870 624         2064 $str.=$self->packData($element,"$tree->".$i++);
871             }
872 156         994 return $str;
873             }
874              
875             =head2 C
876              
877             Encodes one perl hash and its contents and returns it.
878              
879             =cut
880              
881             sub packHash {
882 78     78 0 107 my $self=shift;
883 78         91 my $data=shift;
884 78         100 my $tree=shift;
885 78         91 my $str=$self->packLong(scalar keys %{$data});
  78         216  
886 78         125 foreach my $key (keys %{$data}) {
  78         223  
887 104         291 my $kkey = Data::Sofu::Sofukeyescape($key);
888 104         328 $str.=$self->packText($key);
889 104         479 $str.=$self->packData($data->{$key},"$tree->$kkey");
890             }
891 78         467 return $str;
892             }
893              
894             =head2 C
895              
896             Packs a structure (TREE) into a string using the Sofu binary file format.
897              
898             Returns a string representing TREE.
899              
900             =over
901              
902             =item TREE
903              
904             Perl datastructure to pack. Can be a hash, array or scalar (or array of hashes of hashes of arrays or whatever). Anything NOT a hash will be converted to TREE={Value=>TREE};
905              
906             It can also be a Data::Sofu::Object or derived (Data::Sofu::Map, Data::Sofu::List, Data::Sofu::Value, Data::Sofu::...).
907             Anything not a Data::Sofu::Map will be converted to one (A Map with one attribute called "Value" that holds TREE).
908              
909             =item COMMENTS
910              
911             Comment hash (as returned by Data::Sofu::getSofucomments() or Data::Sofu->new()->comments() after any file was read).
912              
913             Can be undef or {}.
914              
915             =item ENCODING
916              
917             Specifies the encoding of the strings in the binary sofu file, which can be:
918              
919             =over
920              
921             =item C<"0"> or C<"UTF-8">
922              
923             This is default.
924              
925             Normal UTF-8 encoding (supports almost all chars)
926              
927             =item C<"1"> or C<"UTF-7">
928              
929             This is default for byteorder = 7Bit (See below)
930              
931             7Bit encoding (if your transport stream isn't 8-Bit safe
932              
933             =item C<"2"> or C<"UTF-16">
934              
935             UTF 16 with byte order mark in EVERY string.
936              
937             Byteoder depends on your machine
938              
939             =item C<"3"> or C<"UTF-16BE">
940              
941             No BOM, always BigEndian
942              
943             =item C<"4"> or C<"UTF-16LE">
944              
945             No BOM, always LittleEndian
946              
947             =item C<"5"> or C<"UTF-32">
948              
949             UTF-32 with byte order mark in EVERY string.
950              
951             Byteoder depends on your machine
952              
953             =item C<"6"> or C<"UTF-32BE">
954              
955             No BOM, always BigEndian
956              
957             =item C<"7"> or C<"UTF-32LE">
958              
959             No BOM, always LittleEndian
960              
961             =item C<"8","9">
962              
963             Reserved for future use
964              
965             =item C<"10"> or C<"ascii">
966              
967             Normal ASCII encoding
968              
969             Might not support all characters and will warn about that.
970              
971             =item C<"11"> or C<"cp1252">
972              
973             Windows Codepage 1252
974              
975             Might not support all characters and will warn about that.
976              
977             =item C<"12"> or C<"latin1">
978              
979             ISO Latin 1
980              
981             Might not support all characters and will warn about that.
982              
983             =item C<"13"> or C<"latin9">
984              
985             ISO Latin 9
986              
987             Might not support all characters and will warn about that.
988              
989             =item C<"14"> or C<"latin10">
990              
991             ISO Latin 10
992              
993             Might not support all characters and will warn about that.
994              
995             =back
996              
997             =item BYTEORDER
998              
999             Defines how the integers of the binary file are encoded.
1000              
1001             =over
1002              
1003             =item C
1004              
1005             Maschine order
1006              
1007             This is Default.
1008              
1009             BOM is placed to detect the order used.
1010              
1011             =item C<"LE">
1012              
1013             Little Endian
1014              
1015             BOM is placed to detect the order used.
1016              
1017             Use this to give it to machines which are using Little Endian and have to read the file alot
1018              
1019             =item C<"BE">
1020              
1021             Big Endian
1022              
1023             BOM is placed to detect the order used.
1024              
1025             Use this to give it to machines which are using Big Endian and have to read the file alot
1026              
1027             =item C<"7Bit">
1028              
1029             Use this byteorder if you can't trust your transport stream to be 8-Bit save.
1030              
1031             Encoding is forced to be UTF-7. No byte in the file will be > 127.
1032              
1033             BOM is set to 00 00.
1034              
1035             =item C<"NOFORCE7Bit">
1036              
1037             Use this byteorder if you can't trust your transport stream to be 8-Bit save but you want another enconding than UTF-7
1038              
1039             Encoding is NOT forced to be UTF-7.
1040              
1041             BOM is set to 00 00.
1042              
1043             =back
1044              
1045             =item SOFUMARK
1046              
1047             Defines how often the string "Sofu" is placed in the file (to tell any user with a text-editor what type of file this one is).
1048              
1049             =over
1050              
1051             =item C
1052              
1053             Only place one "Sofu" at the beginning of the file.
1054              
1055             This is default.
1056              
1057             =item C<"0" or "">
1058              
1059             Place no string anywhere.
1060              
1061             =item C<< "1" or >1 >>
1062              
1063             Place a string on every place it is possible
1064              
1065             Warning, the file might get big.
1066              
1067             =item C<"0.000001" - "0.99999">
1068              
1069             Place strings randomly.
1070              
1071             =back
1072              
1073             =back
1074              
1075             B
1076              
1077             Encoding, Byteorder and encoding driver (and Sofumark of course) are saved in the binary file. So you don't need to specify them for reading files, in fact just give them the Data::Sofu's readSofu() and all will be fine.
1078              
1079             =cut
1080              
1081             sub pack { #Built tree into b-stream
1082 52     52 1 124 my $self=shift;
1083 52         199 $self->{OFFSET}="while packing";
1084 52         215 $self->{SEEN}={};
1085 52         951 my $data=shift;
1086 52         184 my $r = ref $data;
1087 52 100 66     1050 return $self->packObject($data,@_) if $r and $r =~ m/Data::Sofu::/ and $data->isa("Data::Sofu::Object");
      66        
1088 26 50 33     185 $data = {Value=>$data} unless ref $data and ref $data eq "HASH";
1089             #$self->die("Data format wrong, must be hashref") unless (ref $data and ref $data eq "HASH");
1090 26         101 $self->{SEEN}->{$data}="->";
1091 26         50 my $comments=shift;
1092 26 50       105 $comments = {} unless defined $comments;
1093 26 50 33     178 $self->die("Comment format wrong, must be hashref") unless (ref $comments and ref $comments eq "HASH");
1094 26         50 $self->{Comments}=$comments;
1095 26         41 my $tree;
1096             #my $encoding=shift;
1097             #my $byteorder=shift;
1098             #$encoding=0 unless $encoding;
1099             #$byteorder=0 unless $byteorder;
1100             #$self->encoding($encoding) unless $self->byteorder($byteorder);
1101             #my $mark=shift;
1102             #$mark = undef unless $mark;
1103             #$self->{Mark} = $mark;
1104             #my $str = "";
1105             #$str.="Sofu" if $mark or not defined $mark;
1106             #$str.=$self->packendian();
1107             #$str.=$self->packversion()
1108             #$comments = {} unless defined $comments;;
1109             #$str.=$self->packencoding();
1110 26         168 my $str=$self->packHeader(@_);
1111 26         97 $str.=$self->packComment("=");
1112 26         60 foreach my $key (keys %{$data}) {
  26         139  
1113 130         261 $str.=$self->packText($key);
1114 130         541 $str.=$self->packData($data->{$key},"->".Data::Sofu::Sofukeyescape($key));
1115             }
1116              
1117 26         1767 return $str;
1118             }
1119              
1120             =head2 C
1121              
1122             Same as pack() but for C's only
1123              
1124             Will be called by pack().
1125              
1126             Comments are taken from COMMENTS and from the Objects itself.
1127              
1128             =cut
1129              
1130             sub packObject { # Use the Object implemented Packer for now.
1131 26     26 1 69 my $self=shift;
1132 26         55 my $data=shift;
1133 26         64 my $r = ref $data;
1134 26         78 $self->{OFFSET}="while packing";
1135 26         64 $self->{SEEN}={};
1136 26 50 33     5581 $self->die("Need an Object") unless $r and $r =~ m/Data::Sofu::/ and $data->isa("Data::Sofu::Object");
      33        
1137             #return $data->binaryPack(@_);
1138             #die "Not implemented for now";
1139 26 50       333 unless ($data->isMap()) {
1140 0         0 require Data::Sofu::Map;
1141 0         0 my $x = Data::Sofu::Map->new();
1142 0         0 $x->setAttribute("Value",$data);
1143 0         0 $data=$x;
1144             }
1145 26         138 $self->{SEEN}->{$data}="->";
1146 26         552 my $comments=shift;
1147 26 50       110 $comments = {} unless defined $comments;
1148 26 50 33     233 $self->die("Comment format wrong, must be hashref") unless (ref $comments and ref $comments eq "HASH");
1149 26         75 $self->{Comments}=$comments;
1150 26         142 my $str=$self->packHeader(@_);
1151 26         281 $str.=$self->packComment("=",$data->getComment());
1152 26         188 foreach my $key ($data->orderedKeys()) {
1153             #print $key,"\n";
1154 130         1065 my $kkey = Data::Sofu::Sofukeyescape($key);
1155 130         525 $str.=$self->packText($key);
1156 130         727 $str.=$self->packObjectData($data->object($key),"->$kkey");
1157             }
1158             #die $str;
1159 26         6702 return $str;
1160             }
1161              
1162              
1163             =head2 C
1164              
1165             Encodes one Data::Sofu::Object and its contents and returns it.
1166              
1167             =cut
1168              
1169             sub packObjectData {
1170 858     858 0 3427 my $self=shift;
1171 858         1009 my $data=shift;
1172 858         952 my $tree=shift;
1173 858         1066 my $type=1;
1174 858         1759 my $r = ref $data;
1175             #Maybe call packData on unknown Datastructures..... :)
1176 858 50 33     19627 die ("Unknown Datastructure, can only work with Arrays and Hashes but not $r") unless $r and $r =~ m/Data::Sofu/ and $r->isa("Data::Sofu::Object");
      33        
1177 858         1111 my $odata=$data;
1178 858 100 66     3418 if ($data->isReference() and $data->valid()) {
1179 130         397 $data=$data->follow();
1180             }
1181 858 50       2462 if ($data->isReference()) { #Reference to a Reference not yet allowed!
1182 0         0 confess("No Reference to a Reference allowed for now!");
1183 0         0 return $self->packType(4).$self->packComment($tree,$odata->getComment()).$self->packText("@".$data->follow());
1184             }
1185 858 100       4257 if ($self->{SEEN}->{$data}) {
1186             #Carp::cluck();
1187             #print "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
1188 130         300 return $self->packType(4).$self->packComment($tree,$odata->getComment()).$self->packText("@".$self->{SEEN}->{$data});
1189             }
1190 728         2922 $self->{SEEN}->{$data}=$tree;
1191 728         2499 $self->{SEEN}->{$odata}=$tree;
1192 728 100       2559 if ($data->isValue()) {
1193 468         1153 return $self->packType(1).$self->packComment($tree,$odata->getComment()).$self->packText($data->toString());
1194             }
1195 260 100       773 if ($data->isMap()) {
1196 78         575 return $self->packType(3).$self->packComment($tree,$odata->getComment()).$self->packMap($data,$tree);
1197             }
1198 182 100       15679 if ($data->isList()) {
1199 156         413 return $self->packType(2).$self->packComment($tree,$odata->getComment()).$self->packList($data,$tree);
1200             }
1201 26         77 return $self->packType(0).$self->packComment($tree,$odata->getComment());
1202             }
1203              
1204             =head2 C
1205              
1206             Encodes one Data::Sofu::List and its contents and returns it.
1207              
1208             =cut
1209              
1210              
1211             sub packList {
1212 156     156 1 218 my $self=shift;
1213 156         203 my $data=shift;
1214 156         190 my $tree=shift;
1215 156         519 my $str=$self->packLong($data->length());
1216 156         255 my $i=0;
1217 156         1594 while (my $element = $data->next()) {
1218 624         23665 $str.=$self->packObjectData($element,"$tree->".$i++);
1219             }
1220 156         1482 return $str;
1221             }
1222              
1223             =head2 C
1224              
1225             Encodes one Data::Sofu::Map and its contents and returns it.
1226              
1227             =cut
1228              
1229             sub packMap {
1230 78     78 1 134 my $self=shift;
1231 78         1114 my $data=shift;
1232 78         102 my $tree=shift;
1233 78         335 my $str=$self->packLong($data->length());
1234             #foreach my $key (keys %{$data}) {
1235             #while (my ($key,$value) = $data->each()) {
1236 78         427 foreach my $key ($data->orderedKeys()) {
1237             #print $key,"\n";
1238 104         701 my $kkey = Data::Sofu::Sofukeyescape($key);
1239 104         248 $str.=$self->packText($key);
1240 104         958 $str.=$self->packObjectData($data->object($key),"$tree->$kkey");
1241             }
1242 78         3044 return $str;
1243             }
1244              
1245              
1246             =head2 C
1247              
1248             Packs the comment for (TREE) + ADD and returns it.
1249              
1250             =cut
1251              
1252             sub packComment {
1253 1768     1768 1 2414 my $self=shift;
1254 1768         2119 my $tree=shift;
1255 1768         2260 local $_;
1256 1768         2529 my $add=shift;
1257 1768 100 100     10152 if ($self->{Comments}->{$tree} or $add) {
1258             #$self->die("Comment format wrong for $tree, must be Arrayref");
1259 208         368 my @comments = ();
1260 208 100 66     956 @comments = @{$self->{Comments}->{$tree}} if (ref $self->{Comments}->{$tree} and ref $self->{Comments}->{$tree} eq "ARRAY");
  104         301  
1261 208 50 66     1142 push @comments,@{$add} if $add and ref $add and ref $add eq "ARRAY";
  104   66     290  
1262 208         770 return $self->packText(join("\n",@comments));
1263             }
1264             else {
1265 1560         3125 return $self->packLong(0);
1266             }
1267            
1268             }
1269              
1270             =head2 C
1271              
1272             Packs the header of the file and sets encoding and byteorder
1273              
1274             =cut
1275              
1276             sub packHeader {
1277 58     58 1 122 my $self=shift;
1278 58         136 $self->{OFFSET}="while object packing";
1279 58         84 my $encoding=shift;
1280 58         98 my $byteorder=shift;
1281 58 100       187 $encoding=0 unless $encoding;
1282 58 100       138 $byteorder=0 unless $byteorder;
1283 58 100       283 $self->encoding($encoding) unless $self->byteorder($byteorder);
1284 58         144 my $mark=shift;
1285             #$mark = undef unless defined $mark;
1286 58         185 $self->{Mark} = $mark;
1287             #die $mark;
1288 58         97 my $str = "";
1289 58 100 100     428 $str.="Sofu" if $mark or not defined $mark;
1290 58         250 $str.=$self->packendian();
1291 58         199 $str.=$self->packversion();
1292 58         219 $str.=$self->packencoding();
1293 58         174 return $str;
1294             }
1295              
1296              
1297             =head1 BUGS
1298              
1299             n/c
1300              
1301             =head1 SEE ALSO
1302              
1303             perl(1),L
1304              
1305             Data::Sofu::Object, Data::Sofu, Data::Sofu::Binary::*
1306              
1307              
1308             =cut
1309              
1310             1;