]> arthur.barton.de Git - netatalk.git/blob - contrib/shell_utils/apple_dump.in
Merge branch 'master' of ssh://netatalk.git.sourceforge.net/gitroot/netatalk/netatalk
[netatalk.git] / contrib / shell_utils / apple_dump.in
1 #!@PERL@
2 #
3 # AppleSingle/AppleDouble dump
4 #
5 # (c) 2009-2010 by HAT <hat@fa2.so-net.ne.jp>
6 #
7 #  This program is free software; you can redistribute it and/or modify
8 #  it under the terms of the GNU General Public License as published by
9 #  the Free Software Foundation; either version 2 of the License, or
10 #  (at your option) any later version.
11 #
12 #  This program is distributed in the hope that it will be useful,
13 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #  GNU General Public License for more details.
16
17
18
19 # References:
20
21 # Applesingle and AppleDouble format internals (version 1)
22 # http://users.phg-online.de/tk/netatalk/doc/Apple/v1/
23
24 # AppleSingle/AppleDouble Formats for Foreign Files Developer's Note (version2)
25 # http://users.phg-online.de/tk/netatalk/doc/Apple/v2/AppleSingle_AppleDouble.pdf
26
27 # Inside Macintosh: Macintosh Toolbox Essentials /
28 # Chapter 7 - Finder Interface / Finder Interface Reference
29 # http://developer.apple.com/legacy/mac/library/documentation/mac/toolbox/Toolbox-463.html
30
31 # Finder Interface Reference
32 # http://developer.apple.com/legacy/mac/library/documentation/Carbon/Reference/Finder_Interface/Reference/reference.html
33
34 # Technical Note TN1150  HFS Plus Volume Format
35 # http://developer.apple.com/mac/library/technotes/tn/tn1150.html#FinderInfo
36
37 # CarbonHeaders source
38 # http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-8A428/Finder.h
39 # http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-9A581/Finder.h
40
41 # Xcode 3.2.1
42 # /usr/bin/SetFile
43 # /usr/bin/GetFileInfo
44
45 # Mac OS X 10.6.2 kernel source
46 # http://www.opensource.apple.com/source/xnu/xnu-1486.2.11/bsd/vfs/vfs_xattr.c
47
48
49 use File::Basename;
50 use File::Spec;
51 use bigint; # require perl >= 5.8
52
53 # parse command line -----------------------------------------------
54
55 $finderinfo = 0;              #  0: unknown   1: file   2: directory
56 while ($arg = shift @ARGV)
57 {
58     if  ($arg =~ /^(-h|-help|--help)$/ ) {
59         printf ("usage: %s [-a] FILE|DIR\n"     ,basename($0));
60         printf (" or:   %s -f FILE\n"           ,basename($0));
61         printf (" or:   %s -d FILE\n"           ,basename($0));
62         printf (" or:   %s -h|-help|--help\n"   ,basename($0));
63         printf ("Dump AppleSingle/AppleDouble format file.\n");
64         printf ("\n");
65         printf ("  -a (default)     Dump a AppleSingle/AppleDouble file for FILE or DIR\n");
66         printf ("                   automatically.\n");
67         printf ("                   Extrapolate FinderInfo type from absolute path.\n");
68         printf ("                   If FILE is not AppleSingle/AppleDouble format,\n");
69         printf ("                   look for '.AppleDouble/FILE' and '._FILE'.\n");
70         printf ("                   If DIR, look for 'DIR/.AppleDouble/.Parent' and '._DIR'.\n");
71         printf ("  -f               Dump FILE. Assume FinderInfo to be FileInfo.\n");
72         printf ("  -d               Dump FILE. Assume FinderInfo to be DirInfo.\n");
73         printf ("  -h,-help,--help  Display this help and exit\n");
74         printf ("\n");
75         printf ("There is no way to detect whether FinderInfo is FileInfo or DirInfo.\n");
76         printf ("By default, %s examins whether file or directory,\n"   ,basename($0));
77         printf ("a parent directory is .AppleDouble, filename is ._*, filename is .Parent,\n");
78         printf ("and so on.\n");
79         printf ("If setting option -f or -d, %s assume FinderInfo and doesn't look for\n");
80         printf ("another file.\n");
81         exit 0;
82     } elsif ($arg eq "-a") {
83         $finderinfo = 0;
84     } elsif ($arg eq "-f") {
85         $finderinfo = 1;
86     } elsif ($arg eq "-d") {
87         $finderinfo = 2;
88     } elsif ($arg =~ /^-/) {
89         printf (STDERR "%s: invalid option %s\n", basename($0), $arg);
90         printf (STDERR "Try \`%s\ -h' for more information.\n", basename($0));
91         exit 1;
92     } else {
93         $afile = $arg;
94     }
95 }
96
97 if (!($afile)) {
98     printf (STDERR "missing file operand.\n");
99     exit 1;
100 }
101 if (!( -e $afile)) {
102     printf (STDERR "\"%s\" not found.\n", $afile);
103     exit 1;
104 }
105
106 # detect FinderInfo, and search AppleSingle/AppleDouble file --------------
107
108 $abspath = File::Spec->rel2abs($afile);
109 ($basename, $path, $ext) = fileparse($abspath);
110
111 if ( $finderinfo != 0 ) {
112     ;
113 } elsif ( -f $afile ) {
114     if ( $basename eq ".Parent") {
115         $finderinfo = 2;
116     } elsif ( $path =~ /\/.AppleDouble\/$/ ) {
117         $finderinfo =1;
118     } elsif ( $basename =~ /^._/ ) {
119         if ( -f $path.substr($basename, 2) ) {
120             $finderinfo =1;
121         } elsif ( -d $path.substr($basename, 2) ) {
122             $finderinfo =2;
123         }
124     }
125     if (!open(INFILE, "<$afile")) {
126         printf (STDERR "cannot open %s\n",  $afile);
127         exit 1;
128     }
129     read(INFILE,$buf,4);
130     $val = unpack("N", $buf );
131     close(INFILE);
132     if ($val == 0x00051600 || $val == 0x00051607) {
133         ;
134     } else {
135         printf ("\"%s\" is not AppleSingle/AppleDouble format.\n", $afile);
136         $finderinfo = 1;
137         $netatalkfile = $path.".AppleDouble/".$basename;
138         $osxfile = $path."._".$basename;
139
140         if (( -e $netatalkfile ) && !( -e $osxfile )) {
141             $afile = $netatalkfile;
142         } elsif (!( -e $netatalkfile ) && ( -e $osxfile )) {
143             $afile = $osxfile;
144         } elsif (( -e $netatalkfile ) && ( -e $osxfile )) {
145             printf ("\"%s\" found.\n", $netatalkfile);
146             printf ("\"%s\" found.\n", $osxfile);
147             printf ("Specify which of file.\n");
148             exit 1;
149         } else {
150             printf ("\"%s\" not found.\n", $netatalkfile);
151             printf ("\"%s\" not found.\n", $osxfile);
152             exit 1;
153         }
154     }
155 } elsif ( -d $afile) {
156     printf ("\"%s\" is a directory.\n", $afile);
157     $finderinfo =2;
158     $netatalkfile = $path.$basename."/.AppleDouble/.Parent";
159     $osxfile = $path."._".$basename;
160
161     if (( -e $netatalkfile ) && !( -e $osxfile )) {
162         $afile = $netatalkfile;
163     } elsif (!( -e $netatalkfile ) && ( -e $osxfile )) {
164         $afile = $osxfile;
165     } elsif (( -e $netatalkfile ) && ( -e $osxfile )) {
166         printf ("\"%s\" found.\n", $netatalkfile);
167         printf ("\"%s\" found.\n", $osxfile);
168         printf ("Specify which of file.\n");
169         exit 1;
170     } else {
171         printf ("\"%s\" not found.\n", $netatalkfile);
172         printf ("\"%s\" not found.\n", $osxfile);
173         exit 1;
174     }
175 } else {
176     printf (STDERR "unknown error: %s\n", $afile);
177     exit 1;
178 }
179
180 if (!open(INFILE, "<$afile")) {
181     printf (STDERR "cannot open %s\n",  $afile);
182     exit 1;
183 }
184 printf ("%s:\n\n", $afile);
185
186 # Magic Number -----------------------------------------------
187
188 print "-------------------------------------------------------------------------------\n";
189
190 read(INFILE,$buf,4);
191 $val = unpack("N", $buf );
192 printf("MagicNumber: %08X", $val);
193 if    ( $val == 0x00051600 ) {
194     printf("                                        : AppleSingle");
195 }
196 elsif ( $val == 0x00051607 ) {
197     printf("                                        : AppleDouble");
198 }
199 else                         {
200     printf("                                        : Unknown"    );
201 }
202 print "\n";
203
204 # Version Number ---------------------------------------------
205
206 read(INFILE,$buf,4);
207 $version = unpack("N", $buf );
208 printf("Version    : %08X", $version);
209 if ( $version == 0x00010000 ) {
210     printf("                                        : Version 1");
211 } elsif ( $version == 0x00020000 ) {
212     printf("                                        : Version 2");
213 } else {
214     printf("                                        : Unknown"  );
215 }
216 print "\n";
217
218 # v1:Home file system / v2:Filler ----------------------------
219
220 read(INFILE,$buf,16);
221 if ( $version == 0x00010000 ) {
222     print "HomeFileSys:";
223 } else {
224     print "Filler     :";
225 }
226 hexdump($buf, 16, 16, " ");
227
228 # Number of entities -----------------------------------------
229
230 read(INFILE,$buf,2);
231 $entnum = unpack("n", $buf );
232 printf("Num. of ent: %04X    ", $entnum);
233 printf("                                        : %d", $entnum);
234 print "\n";
235
236 # data -------------------------------------------------------
237
238 for ( $num = 0 ; $num < $entnum ; $num++) {
239
240     seek(INFILE, ($num * 12 + 26), 0);
241
242 #    Entry ---------------------------------------------------
243
244     read(INFILE,$buf,4);
245     $entid = unpack("N", $buf );
246     print "\n-------------------------------------------------------------------------------\n";
247     printf("Entry ID   : %08X", $entid);
248     if    ( $entid ==  1 )         { printf(" : Data Fork"); }
249     elsif ( $entid ==  2 )         { printf(" : Resource Fork"); }
250     elsif ( $entid ==  3 )         { printf(" : Real Name"); }
251     elsif ( $entid ==  4 )         { printf(" : Comment"); }
252     elsif ( $entid ==  5 )         { printf(" : Icon, B&W"); }
253     elsif ( $entid ==  6 )         { printf(" : Icon Color"); }
254     elsif ( $entid ==  7 )         { printf(" : File Info"); }
255     elsif ( $entid ==  8 )         { printf(" : File Dates Info"); }
256     elsif ( $entid ==  9 )         { printf(" : Finder Info"); }
257     elsif ( $entid == 10 )         { printf(" : Macintosh File Info"); }
258     elsif ( $entid == 11 )         { printf(" : ProDOS File Info"); }
259     elsif ( $entid == 12 )         { printf(" : MS-DOS File Info"); }
260     elsif ( $entid == 13 )         { printf(" : Short Name"); }
261     elsif ( $entid == 14 )         { printf(" : AFP File Info"); }
262     elsif ( $entid == 15 )         { printf(" : Directory ID"); }
263     elsif ( $entid == 0x8053567E ) { printf(" : CNID (Netatalk Extended)"); }
264     elsif ( $entid == 0x8053594E ) { printf(" : DB stamp (Netatalk Extended)"); }
265     elsif ( $entid == 0x80444556 ) { printf(" : dev (Netatalk Extended)"); }
266     elsif ( $entid == 0x80494E4F ) { printf(" : inode (Netatalk Extended)"); }
267     else                           { printf(" : Unknown"); }
268     print "\n";
269
270 #    Offset -------------------------------------------------
271
272     read(INFILE,$buf,4);
273     $ofst = unpack("N", $buf );
274     printf("Offset     : %08X", $ofst);
275     printf(" : %d ", $ofst);
276
277 #    Length -------------------------------------------------
278
279     read(INFILE,$buf,4);
280     $len = unpack("N", $buf );
281     printf("\nLength     : %08X", $len);
282     printf(" : %d", $len);
283     $quo = $len >> 4;
284     $rem = $len & 0xF;
285     print "\n";
286
287 #     Dump for each Entry ID --------------------------------
288
289 #    if ( $entid ==  1 ) { ; } # Data Fork
290 #    if ( $entid ==  2 ) { ; } # Resource Fork
291 #    if ( $entid ==  3 ) { ; } # Real Name
292 #    if ( $entid ==  4 ) { ; } # Comment
293 #    if ( $entid ==  5 ) { ; } # Icon, B&W
294 #    if ( $entid ==  6 ) { ; } # Icon Color
295 #    if ( $entid ==  7 ) { ; } # File Info
296     if ( $entid ==  8 ) { filedatesdump($ofst,$len); }
297     elsif ( $entid ==  9 ) { finderinfodump($ofst,$len); }
298 #    if ( $entid == 10 ) { ; } # Macintosh File Info
299 #    if ( $entid == 11 ) { ; } # ProDOS File Info
300 #    if ( $entid == 12 ) { ; } # MS-DOS File Info
301 #    if ( $entid == 13 ) { ; } # Short Name
302 #    if ( $entid == 14 ) { ; } # AFP File Info 
303     elsif ( $entid == 15 ) { print "\n"; bedump($ofst,$len); } # Directory ID
304     elsif ( $entid == 0x8053567E  ) { print "\n"; bedump($ofst,$len); } # CNID (Netatalk Extended)
305     elsif ( $entid == 0x8053594E  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # DB stamp (Netatalk Extended)
306     elsif ( $entid == 0x80444556  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # dev (Netatalk Extended)
307     elsif ( $entid == 0x80494E4F  ) { print "\n"; bedump($ofst,$len); ledump($ofst,$len); } # inode (Netatalk Extended)
308
309 #    RAW Dump ---------------------------------------------------
310
311     if ( ($quo > 0) || ($rem > 0)) {
312         print "\n";
313         print "-RAW DUMP--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
314     }
315
316     seek(INFILE, $ofst, 0);
317     rawdump($quo, $rem);
318
319 }
320
321 close(INFILE);
322 exit 0;
323
324 #sub -----------------------------------------------------------
325
326 sub filedatesdump {
327     my ($ofst, $len) = @_;
328     my ($datedata);
329     my ($i);
330     my ($datestr);
331
332     @datetype =('create    ', 'modify    ', 'backup    ', 'access    ');
333
334     seek(INFILE, $ofst, 0);
335
336     print "\n";
337     printf ("-DATE------:          : (GMT)                    : (Local)\n");
338
339     for ( $i = 0 ; $i < 4 ; $i++) {
340         read(INFILE,$buf,4);
341         $datedata = unpack("N", $buf );
342         if ($datedata < 0x80000000) {
343             $datestr = gmtime( $datedata + 946684800)
344                 ." : "
345                 .localtime( $datedata + 946684800);
346         } elsif ($datedata == 0x80000000) {
347             $datestr = "Unknown or Initial";
348         } else {
349             $datestr = gmtime( $datedata - 3348282496)
350                 ." : "
351                 .localtime( $datedata - 3348282496);
352         }
353         printf ("%s : %08X : %s\n",$datetype[$i], $datedata, $datestr);
354     }
355 }
356
357 sub finderinfodump {
358     my ($ofst, $len) = @_;
359
360     seek(INFILE, $ofst, 0);
361
362     if ($finderinfo == 0) {
363         print "\n";
364         print "-NOTE------: cannot detect whether FInfo or DInfo. assume FInfo.\n";
365     }
366
367     if ($finderinfo == 0 || $finderinfo == 1) {
368         filefinderinfodump();
369     } elsif ($finderinfo == 2) {
370         dirfinderinfodump();
371     } else {
372         print STDERR "unknown FinderInfo type\n"
373     }
374
375     if ($len > 32) { eadump(); }
376 }
377
378 sub filefinderinfodump {
379
380     print "\n";
381     print "-FInfo-----:\n";
382
383     read(INFILE,$buf,4);
384     print "Type       : ";
385     hexdump($buf, 4, 4, "");
386
387     read(INFILE,$buf,4);
388     print "Creator    : ";
389     hexdump($buf, 4, 4, "");
390
391     flagsdump();
392
393     read(INFILE,$buf,2);
394     $val = unpack("n", $buf );
395     printf("Location v : %04X", $val);
396     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
397
398     read(INFILE,$buf,2);
399     $val = unpack("n", $buf );
400     printf("Location h : %04X", $val);
401     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
402
403     read(INFILE,$buf,2);
404     print "Fldr       : ";
405     hexdump($buf, 2, 4, "");
406
407     print "\n";
408     print "-FXInfo----:\n";
409
410     read(INFILE,$buf,2);
411     $val = unpack("n", $buf );
412     printf("Rsvd|IconID: %04X", $val);
413     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
414
415     read(INFILE,$buf,2);
416     print "Rsvd       : ";
417     hexdump($buf, 2, 4, "");
418     read(INFILE,$buf,2);
419     print "Rsvd       : ";
420     hexdump($buf, 2, 4, "");
421     read(INFILE,$buf,2);
422     print "Rsvd       : ";
423     hexdump($buf, 2, 4, "");
424
425     xflagsdump();
426
427     read(INFILE,$buf,2);
428     $val = unpack("n", $buf );
429     printf("Rsvd|commnt: %04X", $val);
430     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
431
432     read(INFILE,$buf,4);
433     $val = unpack("N", $buf );
434     printf("PutAway    : %08X", $val);
435     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
436
437 }
438
439 sub dirfinderinfodump {
440
441     print "\n";
442     print "-DInfo-----:\n";
443
444     read(INFILE,$buf,2);
445     $val = unpack("n", $buf );
446     printf("Rect top   : %04X", $val);
447     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
448
449     read(INFILE,$buf,2);
450     $val = unpack("n", $buf );
451     printf("Rect left  : %04X", $val);
452     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
453
454     read(INFILE,$buf,2);
455     $val = unpack("n", $buf );
456     printf("Rect bottom: %04X", $val);
457     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
458
459     read(INFILE,$buf,2);
460     $val = unpack("n", $buf );
461     printf("Rect right : %04X", $val);
462     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
463
464     flagsdump();
465
466     read(INFILE,$buf,2);
467     $val = unpack("n", $buf );
468     printf("Location v : %04X", $val);
469     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
470
471     read(INFILE,$buf,2);
472     $val = unpack("n", $buf );
473     printf("Location h : %04X", $val);
474     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
475
476     read(INFILE,$buf,2);
477     print "View       : ";
478     hexdump($buf, 2, 4, "");
479
480     print "\n";
481     print "-DXInfo----:\n";
482
483     read(INFILE,$buf,2);
484     $val = unpack("n", $buf );
485     printf("Scroll v   : %04X", $val);
486     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
487
488     read(INFILE,$buf,2);
489     $val = unpack("n", $buf );
490     printf("Scroll h   : %04X", $val);
491     printf("     : %d\n", $val>0x7FFF?$val-0x10000:$val);
492
493     read(INFILE,$buf,4);
494     $val = unpack("N", $buf );
495     printf("Rsvd|OpnChn: %08X", $val);
496     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
497
498     xflagsdump();
499
500     read(INFILE,$buf,2);
501     print "Comment    : ";
502     hexdump($buf, 2, 4, "");
503
504     read(INFILE,$buf,4);
505     $val = unpack("N", $buf );
506     printf("PutAway    : %08X", $val);
507     printf(" : %d\n", $val>0x7FFFFFFF?$val-0x100000000:$val); # Why SInt32?
508
509 }
510 sub flagsdump {
511
512     @colortype =('none', 'gray', 'green', 'purple', 'blue', 'yellow', 'red', 'orange');
513
514     read(INFILE,$buf,2);
515     $flags = unpack("n", $buf );
516     printf ("isAlias    : %d\n", ($flags >> 15) & 1);
517     printf ("Invisible  : %d\n", ($flags >> 14) & 1);
518     printf ("hasBundle  : %d\n", ($flags >> 13) & 1);
519     printf ("nameLocked : %d\n", ($flags >> 12) & 1);
520     printf ("Stationery : %d\n", ($flags >> 11) & 1);
521     printf ("CustomIcon : %d\n", ($flags >> 10) & 1);
522     printf ("Reserved   : %d\n", ($flags >>  9) & 1);
523     printf ("Inited     : %d\n", ($flags >>  8) & 1);
524     printf ("NoINITS    : %d\n", ($flags >>  7) & 1);
525     printf ("Shared     : %d\n", ($flags >>  6) & 1);
526     printf ("SwitchLaunc: %d\n", ($flags >>  5) & 1);
527     printf ("Hidden Ext : %d\n", ($flags >>  4) & 1);
528     printf ("color      : %d%d%d      : %s\n", ($flags >>  3) & 1,
529             ($flags >>  2) & 1,
530             ($flags >>  1) & 1,
531             @colortype[($flags & 0xE)>>1]);
532     printf ("isOnDesk   : %d\n", ($flags >>  0) & 1);
533
534 }
535
536 sub xflagsdump {
537     
538     read(INFILE,$buf,2);
539     $flags = unpack("n", $buf );
540     
541     if (($flags >> 15) == 1) {
542         print "Script     : ";
543         hexdump($buf, 1, 4, "");
544     } else {
545         printf ("AreInvalid : %d\n", ($flags >> 15) & 1);
546         printf ("unknown bit: %d\n", ($flags >> 14) & 1);
547         printf ("unknown bit: %d\n", ($flags >> 13) & 1);
548         printf ("unknown bit: %d\n", ($flags >> 12) & 1);
549         printf ("unknown bit: %d\n", ($flags >> 11) & 1);
550         printf ("unknown bit: %d\n", ($flags >> 10) & 1);
551         printf ("unknown bit: %d\n", ($flags >>  9) & 1);
552     }
553
554     printf ("CustomBadge: %d\n", ($flags >>  8) & 1);
555     printf ("ObjctIsBusy: %d\n", ($flags >>  7) & 1);
556     printf ("unknown bit: %d\n", ($flags >>  6) & 1);
557     printf ("unknown bit: %d\n", ($flags >>  5) & 1);
558     printf ("unknown bit: %d\n", ($flags >>  4) & 1);
559     printf ("unknown bit: %d\n", ($flags >>  3) & 1);
560     printf ("RoutingInfo: %d\n", ($flags >>  2) & 1);
561     printf ("unknown bit: %d\n", ($flags >>  1) & 1);
562     printf ("unknown bit: %d\n", ($flags >>  0) & 1);
563
564 }
565
566 sub eadump {
567     
568     print "\n";
569     print "-EA--------:\n";
570
571     read(INFILE,$buf,2);
572     print "pad        : ";
573     hexdump($buf, 2, 4, "");
574
575     read(INFILE,$buf,4);
576     print "magic      : ";
577     hexdump($buf, 4, 4, "");
578
579     read(INFILE,$buf,4);
580     $ea_debug_tag = unpack("N", $buf );
581     printf("debug_tag  : %08X", $ea_debug_tag);
582     printf(" : %d\n", $ea_debug_tag);
583
584     read(INFILE,$buf,4);
585     $ea_total_size = unpack("N", $buf );
586     printf("total_size : %08X", $ea_total_size);
587     printf(" : %d\n", $ea_total_size);
588
589     read(INFILE,$buf,4);
590     $ea_data_start = unpack("N", $buf );
591     printf("data_start : %08X", $ea_data_start);
592     printf(" : %d\n", $ea_data_start);
593
594     read(INFILE,$buf,4);
595     $ea_data_length = unpack("N", $buf );
596     printf("data_length: %08X", $ea_data_length);
597     printf(" : %d\n", $ea_data_length);
598
599     read(INFILE,$buf,4);
600     print "reserved[0]: ";
601     hexdump($buf, 4, 4, "");
602
603     read(INFILE,$buf,4);
604     print "reserved[1]: ";
605     hexdump($buf, 4, 4, "");
606
607     read(INFILE,$buf,4);
608     print "reserved[2]: ";
609     hexdump($buf, 4, 4, "");
610
611     read(INFILE,$buf,2);
612     print "flags      : ";
613     hexdump($buf, 2, 4, "");
614
615     read(INFILE,$buf,2);
616     $ea_num_attrs = unpack("n", $buf );
617     printf("num_attrs  : %04X", $ea_num_attrs);
618     printf("     : %d\n", $ea_num_attrs);
619
620     $pos = tell(INFILE);
621     
622     for ($i = 0 ; $i < $ea_num_attrs ; $i++) {
623         
624         $pos = (($pos & 0x3) == 0) ? ($pos) : ((($pos >> 2) + 1) << 2);
625         seek(INFILE, $pos, 0);
626
627         print "-EA ENTRY--:\n";
628         
629         read(INFILE,$buf,4);
630         $ea_offset = unpack("N", $buf );
631         printf("offset     : %08X", $ea_offset);
632         printf(" : %d\n", $ea_offset);
633         
634         read(INFILE,$buf,4);
635         $ea_length = unpack("N", $buf );
636         printf("length     : %08X", $ea_length);
637         printf(" : %d\n", $ea_length);
638         
639         read(INFILE,$buf,2);
640         print "flags      : ";
641         hexdump($buf, 2, 4, "");
642         
643         read(INFILE,$buf,1);
644         $ea_namelen = unpack("C", $buf );
645         printf("namelen    : %02X", $ea_namelen);
646         printf("       : %d\n", $ea_namelen);
647
648         $ea_namequo = $ea_namelen >> 4;
649         $ea_namerem = $ea_namelen & 0xF;
650         print "-EA NAME---:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
651         rawdump($ea_namequo, $ea_namerem);
652
653         $pos = tell(INFILE);
654
655         seek(INFILE, $ea_offset, 0);
656         $ea_quo = $ea_length >> 4;
657         $ea_rem = $ea_length & 0xF;
658         print "-EA VALUE--:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F : (ASCII)\n";
659         rawdump($ea_quo, $ea_rem);
660     }
661 }
662
663 sub bedump  {
664     my ($ofst, $len) = @_;
665     my ($i);
666     my ($value);
667     
668     seek(INFILE, $ofst, 0);
669     
670     printf("%2dbit-BE   : ", $len * 8 );
671     
672     $value = 0;
673     for ( $i=0 ; $i < $len ; $i++ ) {
674         read(INFILE,$buf,1);
675         $bytedata[$i] = unpack("C", $buf );
676         $value += $bytedata[$i] << (($len - $i -1) * 8) ;
677     }
678
679     for ( $i=0 ; $i < $len ; $i++ ) {
680         printf("%02X", $bytedata[$i]);
681     }
682
683     printf(" : %s", $value);
684     print "\n";
685     
686 }
687
688 sub ledump  {
689     my ($ofst, $len) = @_;
690     my ($i);
691     my ($value);
692     
693     seek(INFILE, $ofst, 0);
694     
695     printf("%2dbit-LE   : ", $len * 8 );
696     
697     $value = 0;
698     for ( $i=0 ; $i < $len ; $i++ ) {
699         read(INFILE,$buf,1);
700         $bytedata[$len - $i - 1] = unpack("C", $buf );
701         $value += $bytedata[$len - $i -1] << ($i * 8) ;
702     }
703
704     for ( $i=0 ; $i < $len ; $i++ ) {
705         printf("%02X", $bytedata[$i]);
706     }
707
708     printf(" : %s", $value);
709     print "\n";
710     
711 }
712
713 sub rawdump {
714     my ($quo, $rem) = @_;
715     my ($addrs, $line, $buf);
716     
717     $addrs = 0;
718     for ( $line = 0 ; $line < $quo ; $line++) {
719         read(INFILE, $buf, 16);
720         printf ( "%08X   :", $addrs);
721         hexdump($buf, 16, 16, " ");
722         $addrs = $addrs + 0x10;
723     }
724     if ( $rem != 0 ) {
725         read(INFILE, $buf, $rem);
726         printf ( "%08X   :", $addrs);
727         hexdump($buf, $rem, 16, " ");
728     }
729     
730 }
731
732 sub hexdump {
733     my ($buf, $len, $col, $delimit) = @_;
734     my ($i);
735
736     $hexstr = "";
737     $ascstr = "";
738
739     for ( $i=0 ; $i < $len ; $i++ ) {
740         $val = substr($buf, $i, 1);
741         $ascval = ord($val);
742         $hexstr .= sprintf("%s%02X", $delimit, $ascval);
743
744         if (($ascval < 32) || (  $ascval > 126 )) {
745             $val = ".";
746         }
747         $ascstr .= $val;
748     }
749     for ( ; $i < $col ; $i++) {
750         $hexstr .= "  ".$delimit;
751         $ascstr .= " ";
752     }
753
754     printf("%s : %s", $hexstr,$ascstr);
755
756     print "\n";
757 }
758
759 #EOF