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 43 43 100.0
total 716 858 83.4


line stmt bran cond sub pod time code
1             ###############################################################################
2             #List.pm
3             #Last Change: 2009-28-01
4             #Copyright (c) 2009 Marc-Seabstian "Maluku" Lucksch
5             #Version 0.3
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         50  
40 1     1   6 use warnings;
  1         2  
  1         38  
41 1     1   6 use bytes;
  1         2  
  1         8  
42              
43             our $VERSION="0.3";
44             #We are really going to need these modules:
45 1     1   40 use Encode;
  1         3  
  1         113  
46 1     1   7 use Carp qw/confess/;
  1         2  
  1         55  
47             require Data::Sofu;
48 1     1   6 use base qw/Data::Sofu::Binary/;
  1         2  
  1         13742  
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         17 my $self={};
75 7         30 bless $self,$class;
76 7         36 $self->{OBJECT}=0;
77 7         24 $self->{COMMENTS}=[];
78 7         29 $self->{SUPPORTED}={"000_002_000_000"=>1};
79 7         52 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 257 my $self=shift;
92 135         363 my $id=shift;
93 135         808 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         198 my %encoding;
95 135         598 @encoding{map {lc $_} @encoding} = (0 .. 12);
  2025         5709  
96 135 100       763 if (exists $encoding{lc $id}) {
97 31         129 $self->{EncID}=$encoding{lc $id};
98 31         235 return $self->{Encoding}=$encoding[$self->{EncID}];
99             }
100 104 50       352 if ($encoding[int $id]) {
101 104         218 $self->{EncID}=$id;
102 104         747 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 91 my $self=shift;
121 58         99 my $bo=shift;
122 58 100       283 if ($bo =~ m/le/i) { #little Endian
123 9         34 $self->{SHORT}="v";
124 9         28 $self->{LONG}="V";
125 9         65 return 0;
126             }
127 49 100       174 if ($bo =~ m/be/i) { #BIG Endian
128 10         38 $self->{SHORT}="n";
129 10         26 $self->{LONG}="N";
130 10         71 return 0;
131             }
132 39 100       178 if ($bo=~m/7/) { #7-Bit Mode
133 19         64 $self->{SHORT}=undef;
134 19         187 $self->{LONG}=undef;
135 19         86 $self->encoding(1);
136 19         74 return 1;
137             }
138 20 50       57 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         51 $self->{SHORT}="S";
145 20         54 $self->{LONG}="L";
146 20         129 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 112 my $self=shift;
163 58         109 my $bo=shift;
164 58 100       176 if ($bo==1) { #Machine Order
165 29         123 $self->{SHORT}="S";
166 29         73 $self->{LONG}="L";
167 29         67 return 0;
168             }
169 29 100       134 if ($bo==256) { #Wrong Order
170 10 50       161 if (1 == CORE::unpack('S',pack('v',1))) {# We are little Endian
171 10         34 $self->{SHORT}="n";
172 10         25 $self->{LONG}="N";
173             }
174             else {
175 0         0 $self->{SHORT}="v";
176 0         0 $self->{LONG}="V";
177             }
178 10         31 return 0;
179             }
180 19 50       83 if ($bo==0) { #7-Bit Mode
181 19         58 $self->{SHORT}=undef;
182 19         40 $self->{LONG}=undef;
183 19         87 $self->encoding(1);
184 19         63 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 58 my $self=shift;
199 39         89 my $i=shift;
200 39 50       116 $self->die("Short too large: $i") if $i > 65535;
201 39 50       356 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 7927 my $self=shift;
214 4350         13224 my $i=shift;
215 4350 50       10689 $self->die("Long too large: $i") if $i > 4294967295;
216 4350 100       38257 return pack $self->{LONG},$i if $self->{LONG};
217 1425 50       4822 $self->die("Can't pack that Long in 7-Bit, too large: $i") if $i > 268435455;
218 1425         14625 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 98 my $self=shift;
229 58 100       182 if ($self->{SHORT}) {
230 39         166 return $self->packShort(1);
231             }
232 19         67 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 117 my $self=shift;
243 58         148 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 89 my $self=shift;
254 58         290 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 2599 my $self=shift;
277 1914         5567 my $type = $self->get(1);
278 1914 50       4977 $self->die ("Unexpected End of File") unless $type;
279 1914 100       7194 if ($type eq "S") {
280 547         2123 my $str = $self->get(3);
281 547 50 33     3497 $self->die("Incomplete Sofu-Mark") if not $str or $str ne "ofu";
282 547         1601 $type = $self->get(1);
283             }
284 1914 50       3478 $self->die("No Type found") unless defined $type;
285 1914         3630 $type=CORE::unpack("C",$type);
286 1914 50       4605 $self->die("Unknown Type: $type") if $type > 4;
287 1914         3402 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 49 my $self=shift;
298 32         162 $self->{Ref}->{""} = $self->{Ref}->{"->"} = $self->{Ref}->{"="};
299 32         122 foreach my $e (@{$$self{References}}) {
  32         154  
300 160 50       455 next if $e->valid();
301 160         435 my $target = $e->follow()."";
302 160         733 $target=~s/^@//;
303 160 50 33     9242 $target="->".$target if $target and $target !~ m/^->/;
304 160 50       846 $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 49 my $self=shift;
316 26         516 $self->{Ref}->{""} = $self->{Ref}->{"->"} = $self->{Ref}->{"="};
317 26         45 foreach my $e (@{$$self{References}}) {
  26         124  
318             #next;
319             #print $$e;
320 52         110 my $target = $$$e;
321 52         279 $target=~s/^@//;
322 52 50 33     487 $target="->".$target if $target and $target !~ m/^->/;
323 52         94 $$e = undef;
324 52 50       326 $$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 7625 my $self=shift;
336 4408         6107 my $i=shift;
337 4408 100       9527 return undef unless defined $i;
338 4350 100       31271 return CORE::unpack($self->{LONG},$i) if $self->{LONG};
339 1425         4335 my @i = CORE::unpack("CCCC",$i);
340             #print join(", ",@i),"\n";
341 1425         5400 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 8289 my $self=shift;
353 3886         11308 my $len=$self->getLong($self->get(4));
354 3886 100       53307 return undef unless defined $len;
355 3828 100       12172 return "" if $len == 0;
356 2030         11877 my $text = $self->get($len);
357 2030         18428 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 4873 my $self=shift;
371 1972         2284 my $tree=shift;
372 1972         12706 my $t = $self->getText();
373 1972 50       18007 $self->die("Can't get Comment, EOF!") unless defined $t;
374 1972 100       6495 return if $t eq "";
375 232 100       648 if (ref $tree) {
376 128         898 $tree->setComment([split /\n/,$t]);
377             }
378             else {
379 104         1011 $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 41 my $self=shift;
392 26         47 my $tree=shift;
393 26         58 $self->getComment($tree);
394 26         81 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 710 my $self=shift;
407 546         611 my $tree=shift;
408 546         1623 $self->getComment($tree);
409 546         4746 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 13463 my $self=shift;
422 52         73 my $tree=shift;
423 52         142 $self->getComment($tree);
424 52         137 my $x = $self->getText();
425 52         6128 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 156 my $self=shift;
438 78         111 my $tree=shift;
439 78         289 my %result=();
440 78         209 $self->getComment($tree);
441 78         280 my $len=$self->getLong($self->get(4));
442 78 50       627 $self->die("Error while reading maplength, maybe EOF") unless defined $len;
443 78 50       187 return {} if $len == 0;
444 78         398 keys(%result) = $len; #Presetting the Hashsize
445 78         283 for (my $i = 0;$i < $len;$i++) {
446 104         256 my $key = $self->getText();
447 104 50       5172 $self->die("Error while reading key, maybe EOF") unless defined $key;
448 104         3654 my $kkey = Data::Sofu::Sofukeyescape($key);
449 104         293 my $type = $self->getType();
450 104         389 $result{$key} = $self->unpackType($type,"$tree->$kkey");
451 104         2300 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
452 104 100       409 push @{$self->{References}},\$result{$key} if ($type == 4);
  26         148  
453             }
454 78         336 return \%result;
455            
456             }
457              
458              
459             =head2 unpackArray(TREE)
460              
461             Decodes an array, its comment and its content
462              
463             =cut
464              
465              
466             sub unpackArray {
467 156     156 1 221 my $self=shift;
468 156         240 my $tree=shift;
469 156         273 my @result=();
470 156         403 $self->getComment($tree);
471 156         435 my $len=$self->getLong($self->get(4));
472 156 50       450 $self->die("Error while reading listlength, maybe EOF") unless defined $len;
473 156 50       524 return {} if $len == 0;
474             #die $len,"\n";
475 156         904 $#result = $len-1; #Grow the Array :)
476 156         666 for (my $i = 0;$i < $len;$i++) {
477 624         1439 my $type = $self->getType();
478 624         3710 $result[$i] = $self->unpackType($type,"$tree->$i");
479 624         37068 $self->{Ref}->{"$tree->$i"}=$result[$i];
480 624 100       3607 push @{$self->{References}},\$result[$i] if ($type == 4);
  26         138  
481             }
482 156         841 return \@result;
483            
484             }
485              
486              
487             =head2 unpackType(TYPE,TREE)
488              
489             Decodes a datastructure of TYPE.
490              
491             =cut
492              
493              
494             sub unpackType {
495 858     858 1 1954 my $self=shift;
496 858         1156 my $type=shift;
497 858         1242 my $tree=shift;
498 858 100       4983 if ($type == 0) {
    100          
    100          
    100          
    50          
499 26         95 return $self->unpackUndef($tree);
500             }
501             elsif ($type == 1) {
502 546         3348 return $self->unpackScalar($tree);
503             }
504             elsif ($type == 2) {
505 156         414 return $self->unpackArray($tree);
506             }
507             elsif ($type == 3) {
508 78         324 return $self->unpackHash($tree);
509             }
510             elsif ($type == 4) {
511 52         152 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 70 my $self=shift;
525 26         42 my $bom=shift;
526 26         79 $self->{COMMENTS}={};
527 26         89 $self->{References}=[];
528 26         251 $self->{Ref}={};
529 26         674 $self->bom($bom);
530 26         92 my $encoding = $self->get(1);
531 26 50       77 $self->die("No Encoding!") unless defined $encoding;
532 26         128 $self->encoding(CORE::unpack("C",$encoding));
533 26         70 my $tree="";
534 26         54 my %result=();
535 26         108 $self->getComment("=");
536 26         92 while (defined (my $key = $self->getText())) {
537 130         4912 my $kkey = Data::Sofu::Sofukeyescape($key);
538 130         705 my $type = $self->getType();
539 130         588 $result{$key} = $self->unpackType($type,"$tree->$kkey");
540 130         1847 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
541 130 50       537 push @{$self->{References}},\$result{$key} if ($type == 4);
  0         0  
542             }
543 26         107 $self->{Ref}->{"="}=\%result;
544 26         136 $self->postprocess(); #Setting References right.
545 26         215 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 76 my $self=shift;
558 32         53 my $tree=shift;
559 32         504 my $und = Data::Sofu::Undefined->new();
560 32         96 $self->getComment($und);
561 32         115 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 808 my $self=shift;
574 576         664 my $tree=shift;
575 576         2556 my $value = Data::Sofu::Value->new("");
576 576         1340 $self->getComment($value);
577 576         1151 $value->set($self->getText());
578 576         2114 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 234 my $self=shift;
591 160         203 my $tree=shift;
592 160         703 my $ref = Data::Sofu::Reference->new();
593 160         364 $self->getComment($ref);
594 160         337 $ref->dangle($self->getText());
595 160         552 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 141 my $self=shift;
639 96         139 my $tree=shift;
640 96         214 my %result=();
641 96         154 my @order=();
642 96         346 my $map=Data::Sofu::Map->new();
643 96         251 $self->getComment($map);
644 96         348 my $len=$self->getLong($self->get(4));
645 96 50       280 $self->die("Error while reading maplength, maybe EOF") unless defined $len;
646 96 50       209 return $map if $len == 0;
647 96         265 keys(%result) = $len; #Presetting the Hashsize
648 96         377 $#order=($len-1);
649 96         272 for (my $i = 0;$i < $len;$i++) {
650 128         268 my $key = $self->getText();
651 128 50       4807 $self->die("Error while reading key, maybe EOF") unless defined $key;
652 128         393 my $kkey = Data::Sofu::Sofukeyescape($key);
653 128         371 my $type = $self->getType();
654 128         614 $result{$key} = $self->unpackObjectType($type,"$tree->$kkey");
655             #push @order,$key;
656 128         376 $order[$i] = $key;
657 128         957 $self->{Ref}->{"$tree->$kkey"}=$result{$key};
658 128 100       533 push @{$self->{References}},$result{$key} if ($type == 4);
  32         174  
659             }
660 96         235 $map->{Order}=\@order;
661 96         201 $map->{Map}=\%result;
662 96         2457 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 251 my $self=shift;
703 192         347 my $tree=shift;
704 192         1093 my $list=Data::Sofu::List->new();
705 192         432 $self->getComment($list);
706 192         240 my @result;
707 192         579 my $len=$self->getLong($self->get(4));
708 192 50       692 $self->die("Error while reading listlength, maybe EOF") unless defined $len;
709 192 50       459 return $list if $len == 0;
710             #die $len,"\n";
711 192         662 $#result = $len-1; #Grow the Array :)
712 192         787 for (my $i = 0;$i < $len;$i++) {
713 768         1972 my $type = $self->getType();
714 768         2558 $result[$i] = $self->unpackObjectType($type,"$tree->$i");
715 768         3587 $self->{Ref}->{"$tree->$i"}=$result[$i];
716 768 100       2632 push @{$self->{References}},$result[$i] if ($type == 4);
  128         540  
717             }
718 192         447 $list->{List}=\@result;
719 192         664 return $list;
720            
721             }
722              
723             =head2 unpackObjectType(TYPE,TREE)
724              
725             Unpacks a datastructure defined by TYPE
726              
727             =cut
728              
729             sub unpackObjectType {
730 1056     1056 1 1505 my $self=shift;
731 1056         1176 my $type=shift;
732 1056         1221 my $tree=shift;
733 1056 100       3600 if ($type == 0) {
    100          
    100          
    100          
    50          
734 32         117 return $self->unpackUndefined($tree);
735             }
736             elsif ($type == 1) {
737 576         1384 return $self->unpackValue($tree);
738             }
739             elsif ($type == 2) {
740 192         539 return $self->unpackList2($tree);
741             }
742             elsif ($type == 3) {
743 96         336 return $self->unpackMap2($tree);
744             }
745             elsif ($type == 4) {
746 160         360 return $self->unpackReference($tree);
747             }
748             }
749              
750              
751             =head2 unpackObject(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 1 62 my $self=shift;
760 32         63 my $bom=shift;
761 32         112 $self->{References}=[];
762 32         136 $self->{Ref}={};
763 32         696 $self->bom($bom);
764 32         143 my $encoding = $self->get(1);
765 32 50       226 $self->die("No Encoding!") unless defined $encoding;
766 32         135 $self->encoding(CORE::unpack("C",$encoding));
767 32         74 my $tree="";
768 32         391 my $map = Data::Sofu::Map->new();
769 32         234 $self->getComment($map);
770 32         121 while (defined (my $key = $self->getText())) {
771 160         6113 my $kkey = Data::Sofu::Sofukeyescape($key);
772 160         499 my $type = $self->getType();
773 160         655 my $res = $self->unpackObjectType($type,"$tree->$kkey");
774 160         624 $self->{Ref}->{"$tree->$kkey"}=$res;
775 160 50       398 push @{$self->{References}},$res if ($type == 4);
  0         0  
776 160         806 $map->setAttribute($key,$res);
777              
778             }
779 32         117 $self->{Ref}->{"="}=$map;
780 32         100 $self->objectprocess(); #Setting References right.
781 32         4625 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 3742 my $self=shift;
794 1914         2758 my $type=shift;
795 1914         2266 my $str="";
796 1914 100       7524 if ($self->{Mark}) {
797 759 100       2471 $str="Sofu" if rand() < $self->{Mark};
798             }
799 1914         9136 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 4415 my $self=shift;
810 2268         3146 my $text=shift;
811 2268 100 66     13880 return $self->packLong(0) if not defined $text or $text eq "";
812 2030         18677 $text = Encode::encode($self->{Encoding},$text,Encode::FB_CROAK);
813 2030         107232 return $self->packLong(length($text)).$text;
814             }
815              
816             =head2 packData(DATA,TREE)
817              
818             Encodes one perl datastructure and its contents and returns it.
819              
820             =cut
821              
822             sub packData {
823 858     858 1 1238 my $self=shift;
824 858         11836 my $data=shift;
825 858         3228 my $tree=shift;
826 858         2241 my $type=1;
827 858 100       1669 if (ref $data) {
828 286         396 my $r=ref $data;
829 286 100       1826 if ($r eq "ARRAY") {
    50          
830 156         238 $type=2;
831             }
832             elsif ($r eq "HASH") {
833 130         184 $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       1294 if ($self->{SEEN}->{$data}) {
839 52         135 return $self->packType(4).$self->packComment($tree).$self->packText("@".$self->{SEEN}->{$data});
840             }
841             }
842             else {
843 572 100       1040 if (defined ($data)) {
844 546         1380 return $self->packType(1).$self->packComment($tree).$self->packText($data);
845             }
846             else {
847 26         78 return $self->packType(0).$self->packComment($tree);
848             }
849             }
850 234         743 $self->{SEEN}->{$data}=$tree;
851 234 100       728 if ($type==3) {
852 78         201 return $self->packType(3).$self->packComment($tree).$self->packHash($data,$tree);
853             }
854 156         361 return $self->packType(2).$self->packComment($tree).$self->packArray($data,$tree);
855             }
856              
857             =head2 packArray(DATA,TREE)
858              
859             Encodes one perl array and its contents and returns it.
860              
861             =cut
862              
863             sub packArray {
864 156     156 1 200 my $self=shift;
865 156         193 my $data=shift;
866 156         2094 my $tree=shift;
867 156         191 my $str=$self->packLong(scalar @{$data});
  156         569  
868 156         262 my $i=0;
869 156         456 foreach my $element (@{$data}) {
  156         699  
870 624         2314 $str.=$self->packData($element,"$tree->".$i++);
871             }
872 156         2247 return $str;
873             }
874              
875             =head2 packHash(DATA,TREE)
876              
877             Encodes one perl hash and its contents and returns it.
878              
879             =cut
880              
881             sub packHash {
882 78     78 1 166 my $self=shift;
883 78         108 my $data=shift;
884 78         200 my $tree=shift;
885 78         124 my $str=$self->packLong(scalar keys %{$data});
  78         276  
886 78         134 foreach my $key (keys %{$data}) {
  78         1123  
887 104         2339 my $kkey = Data::Sofu::Sofukeyescape($key);
888 104         312 $str.=$self->packText($key);
889 104         515 $str.=$self->packData($data->{$key},"$tree->$kkey");
890             }
891 78         463 return $str;
892             }
893              
894             =head2 pack(TREE,[COMMENTS,[ENCODING,[BYTEORDER,[SOFUMARK]]]])
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 122 my $self=shift;
1083 52         313 $self->{OFFSET}="while packing";
1084 52         351 $self->{SEEN}={};
1085 52         917 my $data=shift;
1086 52         140 my $r = ref $data;
1087 52 100 66     834 return $self->packObject($data,@_) if $r and $r =~ m/Data::Sofu::/ and $data->isa("Data::Sofu::Object");
      66        
1088 26 50 33     279 $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         103 $self->{SEEN}->{$data}="->";
1091 26         49 my $comments=shift;
1092 26 50       86 $comments = {} unless defined $comments;
1093 26 50 33     173 $self->die("Comment format wrong, must be hashref") unless (ref $comments and ref $comments eq "HASH");
1094 26         226 $self->{Comments}=$comments;
1095 26         4674 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         150 my $str=$self->packHeader(@_);
1111 26         120 $str.=$self->packComment("=");
1112 26         54 foreach my $key (keys %{$data}) {
  26         171  
1113 130         331 $str.=$self->packText($key);
1114 130         15124 $str.=$self->packData($data->{$key},"->".Data::Sofu::Sofukeyescape($key));
1115             }
1116              
1117 26         5093 return $str;
1118             }
1119              
1120             =head2 packObject(TREE,[COMMENTS,[ENCODING,[BYTEORDER,[SOFUMARK]]]])
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 54 my $self=shift;
1132 26         61 my $data=shift;
1133 26         56 my $r = ref $data;
1134 26         71 $self->{OFFSET}="while packing";
1135 26         69 $self->{SEEN}={};
1136 26 50 33     381 $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       169 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         111 $self->{SEEN}->{$data}="->";
1146 26         53 my $comments=shift;
1147 26 50       94 $comments = {} unless defined $comments;
1148 26 50 33     271 $self->die("Comment format wrong, must be hashref") unless (ref $comments and ref $comments eq "HASH");
1149 26         76 $self->{Comments}=$comments;
1150 26         128 my $str=$self->packHeader(@_);
1151 26         185 $str.=$self->packComment("=",$data->getComment());
1152 26         147 foreach my $key ($data->orderedKeys()) {
1153             #print $key,"\n";
1154 130         415 my $kkey = Data::Sofu::Sofukeyescape($key);
1155 130         363 $str.=$self->packText($key);
1156 130         553 $str.=$self->packObjectData($data->object($key),"->$kkey");
1157             }
1158             #die $str;
1159 26         54720 return $str;
1160             }
1161              
1162              
1163             =head2 packObjectData(DATA,TREE)
1164              
1165             Encodes one Data::Sofu::Object and its contents and returns it.
1166              
1167             =cut
1168              
1169             sub packObjectData {
1170 858     858 1 1120 my $self=shift;
1171 858         1088 my $data=shift;
1172 858         1103 my $tree=shift;
1173 858         947 my $type=1;
1174 858         1444 my $r = ref $data;
1175             #Maybe call packData on unknown Datastructures..... :)
1176 858 50 33     18660 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         1222 my $odata=$data;
1178 858 100 66     2540 if ($data->isReference() and $data->valid()) {
1179 130         362 $data=$data->follow();
1180             }
1181 858 50       2365 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       4208 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         323 return $self->packType(4).$self->packComment($tree,$odata->getComment()).$self->packText("@".$self->{SEEN}->{$data});
1189             }
1190 728         2463 $self->{SEEN}->{$data}=$tree;
1191 728         1671 $self->{SEEN}->{$odata}=$tree;
1192 728 100       2290 if ($data->isValue()) {
1193 468         1054 return $self->packType(1).$self->packComment($tree,$odata->getComment()).$self->packText($data->toString());
1194             }
1195 260 100       881 if ($data->isMap()) {
1196 78         217 return $self->packType(3).$self->packComment($tree,$odata->getComment()).$self->packMap($data,$tree);
1197             }
1198 182 100       603 if ($data->isList()) {
1199 156         337 return $self->packType(2).$self->packComment($tree,$odata->getComment()).$self->packList($data,$tree);
1200             }
1201 26         73 return $self->packType(0).$self->packComment($tree,$odata->getComment());
1202             }
1203              
1204             =head2 packList(DATA,TREE)
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 208 my $self=shift;
1213 156         188 my $data=shift;
1214 156         196 my $tree=shift;
1215 156         16353 my $str=$self->packLong($data->length());
1216 156         266 my $i=0;
1217 156         502 while (my $element = $data->next()) {
1218 624         2305 $str.=$self->packObjectData($element,"$tree->".$i++);
1219             }
1220 156         1483 return $str;
1221             }
1222              
1223             =head2 packMap(DATA,TREE)
1224              
1225             Encodes one Data::Sofu::Map and its contents and returns it.
1226              
1227             =cut
1228              
1229             sub packMap {
1230 78     78 1 106 my $self=shift;
1231 78         110 my $data=shift;
1232 78         116 my $tree=shift;
1233 78         278 my $str=$self->packLong($data->length());
1234             #foreach my $key (keys %{$data}) {
1235             #while (my ($key,$value) = $data->each()) {
1236 78         281 foreach my $key ($data->orderedKeys()) {
1237             #print $key,"\n";
1238 104         317 my $kkey = Data::Sofu::Sofukeyescape($key);
1239 104         275 $str.=$self->packText($key);
1240 104         509 $str.=$self->packObjectData($data->object($key),"$tree->$kkey");
1241             }
1242 78         727 return $str;
1243             }
1244              
1245              
1246             =head2 packComment(TREE,ADD)
1247              
1248             Packs the comment for (TREE) + ADD and returns it.
1249              
1250             =cut
1251              
1252             sub packComment {
1253 1768     1768 1 2928 my $self=shift;
1254 1768         4355 my $tree=shift;
1255 1768         5093 local $_;
1256 1768         2573 my $add=shift;
1257 1768 100 100     13567 if ($self->{Comments}->{$tree} or $add) {
1258             #$self->die("Comment format wrong for $tree, must be Arrayref");
1259 208         375 my @comments = ();
1260 208 100 66     1707 @comments = @{$self->{Comments}->{$tree}} if (ref $self->{Comments}->{$tree} and ref $self->{Comments}->{$tree} eq "ARRAY");
  104         351  
1261 208 50 66     1576 push @comments,@{$add} if $add and ref $add and ref $add eq "ARRAY";
  104   66     272  
1262 208         2103 return $self->packText(join("\n",@comments));
1263             }
1264             else {
1265 1560         3471 return $self->packLong(0);
1266             }
1267            
1268             }
1269              
1270             =head2 packHeader([ENCODING,[BYTEORDER,[SOFUMARK]]])
1271              
1272             Packs the header of the file and sets encoding and byteorder
1273              
1274             =cut
1275              
1276             sub packHeader {
1277 58     58 1 126 my $self=shift;
1278 58         336 $self->{OFFSET}="while object packing";
1279 58         130 my $encoding=shift;
1280 58         282 my $byteorder=shift;
1281 58 100       200 $encoding=0 unless $encoding;
1282 58 100       149 $byteorder=0 unless $byteorder;
1283 58 100       409 $self->encoding($encoding) unless $self->byteorder($byteorder);
1284 58         128 my $mark=shift;
1285             #$mark = undef unless defined $mark;
1286 58         161 $self->{Mark} = $mark;
1287             #die $mark;
1288 58         125 my $str = "";
1289 58 100 100     342 $str.="Sofu" if $mark or not defined $mark;
1290 58         248 $str.=$self->packendian();
1291 58         212 $str.=$self->packversion();
1292 58         310 $str.=$self->packencoding();
1293 58         263 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;