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