~ubuntu-branches/debian/lenny/netatalk/lenny

« back to all changes in this revision

Viewing changes to bin/megatron/macbin.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: macbin.c,v 1.10 2002/02/16 17:12:53 srittau Exp $
 
3
 */
 
4
 
 
5
#ifdef HAVE_CONFIG_H
 
6
#include "config.h"
 
7
#endif /* HAVE_CONFIG_H */
 
8
 
 
9
#include <sys/types.h>
 
10
#include <sys/uio.h>
 
11
#include <sys/time.h>
 
12
#include <sys/param.h>
 
13
#ifdef HAVE_FCNTL_H
 
14
#include <fcntl.h>
 
15
#endif /* HAVE_FCNTL_H */
 
16
#ifdef HAVE_UNISTD_H
 
17
#include <unistd.h>
 
18
#endif /* HAVE_UNISTD_H */
 
19
#include <string.h>
 
20
#include <strings.h>
 
21
#include <ctype.h>
 
22
#include <stdio.h>
 
23
#include <time.h>
 
24
 
 
25
#include <atalk/adouble.h>
 
26
#include <netatalk/endian.h>
 
27
#include "megatron.h"
 
28
#include "macbin.h"
 
29
 
 
30
/* This allows megatron to generate .bin files that won't choke other
 
31
   well-known converter apps. It also makes sure that checksums
 
32
   always match. (RLB) */
 
33
#define MACBINARY_PLAY_NICE_WITH_OTHERS
 
34
 
 
35
/*      String used to indicate standard input instead of a disk
 
36
        file.  Should be a string not normally used for a file
 
37
 */
 
38
#ifndef STDIN
 
39
#       define  STDIN   "-"
 
40
#endif /* STDIN */
 
41
 
 
42
/*      Yes and no
 
43
 */
 
44
#define NOWAY           0
 
45
#define SURETHANG       1
 
46
 
 
47
/*      Size of a macbinary file header
 
48
 */
 
49
#define HEADBUFSIZ      128
 
50
 
 
51
/*      Both input and output routines use this struct and the
 
52
        following globals; therefore this module can only be used
 
53
        for one of the two functions at a time.
 
54
 */
 
55
struct bin_file_data {
 
56
    u_int32_t           forklen[ NUMFORKS ];
 
57
    char                path[ MAXPATHLEN + 1];
 
58
    int                 filed;
 
59
    u_short             headercrc;
 
60
    time_t              gmtoff; /* to convert from/to localtime */
 
61
}               bin;
 
62
 
 
63
extern char     *forkname[];
 
64
u_char          head_buf[HEADBUFSIZ];
 
65
 
 
66
/* 
 
67
 * bin_open must be called first.  pass it a filename that is supposed
 
68
 * to contain a macbinary file.  an bin struct will be allocated and
 
69
 * somewhat initialized; bin_filed is set.
 
70
 */
 
71
 
 
72
int bin_open( binfile, flags, fh, options )
 
73
    char                *binfile;
 
74
    int                 flags, options;
 
75
    struct FHeader      *fh;
 
76
{
 
77
    int                 maxlen;
 
78
    int                 rc;
 
79
    time_t              t;
 
80
    struct tm           *tp;
 
81
 
 
82
#if DEBUG
 
83
    fprintf( stderr, "entering bin_open\n" );
 
84
#endif /* DEBUG */
 
85
 
 
86
    /* call localtime so that we get the timezone offset */
 
87
    bin.gmtoff = 0;
 
88
#ifndef NO_STRUCT_TM_GMTOFF
 
89
    time(&t);
 
90
    tp = localtime(&t);
 
91
    if (tp)
 
92
        bin.gmtoff = tp->tm_gmtoff;
 
93
#endif /* ! NO_STRUCT_TM_GMTOFF */
 
94
 
 
95
    if ( flags == O_RDONLY ) { /* input */
 
96
        if ( strcmp( binfile, STDIN ) == 0 ) {
 
97
            bin.filed = fileno( stdin );
 
98
        } else if (( bin.filed = open( binfile, flags )) < 0 ) {
 
99
            perror( binfile );
 
100
            return( -1 );
 
101
        }
 
102
#if DEBUG
 
103
        fprintf( stderr, "opened %s for read\n", binfile );
 
104
#endif /* DEBUG */
 
105
        if ((( rc = test_header() ) > 0 ) && 
 
106
                ( bin_header_read( fh, rc ) == 0 )) {
 
107
            return( 0 );
 
108
        }
 
109
        fprintf( stderr, "%s is not a macbinary file.\n", binfile );
 
110
        return( -1 );
 
111
    } else { /* output */
 
112
        if (options & OPTION_STDOUT) 
 
113
          bin.filed = fileno(stdout);
 
114
        else {
 
115
          maxlen = sizeof( bin.path ) - 1;
 
116
#if DEBUG
 
117
          fprintf( stderr, "sizeof bin.path\t\t\t%d\n", sizeof( bin.path ));
 
118
          fprintf( stderr, "maxlen \t\t\t\t%d\n", maxlen );
 
119
#endif /* DEBUG */
 
120
          strncpy( bin.path, fh->name, maxlen );
 
121
          strncpy( bin.path, mtoupath( bin.path ), maxlen );
 
122
          strncat( bin.path, ".bin", maxlen - strlen( bin.path ));
 
123
          if (( bin.filed = open( bin.path, flags, 0666 )) < 0 ) {
 
124
            perror( bin.path );
 
125
            return( -1 );
 
126
          }
 
127
#if DEBUG
 
128
          fprintf( stderr, "opened %s for write\n", 
 
129
                   (options & OPTION_STDOUT) ? "(stdout)" : bin.path );
 
130
#endif /* DEBUG */
 
131
        }
 
132
 
 
133
        if ( bin_header_write( fh ) != 0 ) {
 
134
            bin_close( TRASH );
 
135
            fprintf( stderr, "%s\n", bin.path );
 
136
            return( -1 );
 
137
        }
 
138
        return( 0 );
 
139
    }
 
140
}
 
141
 
 
142
/* 
 
143
 * bin_close must be called before a second file can be opened using
 
144
 * bin_open.  Upon successful completion, a value of 0 is returned.  
 
145
 * Otherwise, a value of -1 is returned.
 
146
 */
 
147
 
 
148
int bin_close( keepflag )
 
149
    int                 keepflag;
 
150
{
 
151
#if DEBUG
 
152
    fprintf( stderr, "entering bin_close\n" );
 
153
#endif /* DEBUG */
 
154
    if ( keepflag == KEEP ) {
 
155
        return( close( bin.filed ));
 
156
    } else if ( keepflag == TRASH ) {
 
157
        if (( strcmp( bin.path, STDIN ) != 0 ) && 
 
158
                ( unlink( bin.path ) < 0 )) {
 
159
            perror ( bin.path );
 
160
        }
 
161
        return( 0 );
 
162
    } else return( -1 );
 
163
}
 
164
 
 
165
/*
 
166
 * bin_read is called until it returns zero for each fork.  when it is
 
167
 * and finds that there is zero left to give, it seeks to the position
 
168
 * of the next fork (if there is one ).
 
169
 * bin_read must be called enough times to
 
170
 * return zero and no more than that.
 
171
 */
 
172
 
 
173
int bin_read( fork, buffer, length )
 
174
    int                 fork;
 
175
    char                *buffer;
 
176
    int                 length;
 
177
{
 
178
    char                *buf_ptr;
 
179
    int                 readlen;
 
180
    int                 cc = 1;
 
181
    off_t               pos;
 
182
 
 
183
#if DEBUG >= 3
 
184
    fprintf( stderr, "bin_read: fork is %s\n", forkname[ fork ] );
 
185
    fprintf( stderr, "bin_read: remaining length is %d\n", bin.forklen[fork] );
 
186
#endif /* DEBUG >= 3 */
 
187
 
 
188
    if ( bin.forklen[ fork ] < 0 ) {
 
189
        fprintf( stderr, "This should never happen, dude!\n" );
 
190
        return( bin.forklen[ fork ] );
 
191
    }
 
192
 
 
193
    if ( bin.forklen[ fork ] == 0 ) {
 
194
        if ( fork == DATA ) {
 
195
            pos = lseek( bin.filed, 0, SEEK_CUR );
 
196
#if DEBUG
 
197
            fprintf( stderr, "current position is %ld\n", pos );
 
198
#endif /* DEBUG */
 
199
            pos %= HEADBUFSIZ;
 
200
            if (pos != 0) {
 
201
              pos = lseek( bin.filed, HEADBUFSIZ - pos, SEEK_CUR );
 
202
            }
 
203
#if DEBUG
 
204
            fprintf( stderr, "current position is %ld\n", pos );
 
205
#endif /* DEBUG */
 
206
        }
 
207
        return( 0 );
 
208
    }
 
209
 
 
210
    if ( bin.forklen[ fork ] < length ) {
 
211
        readlen = bin.forklen[ fork ];
 
212
    } else {
 
213
        readlen = length;
 
214
    }
 
215
#if DEBUG >= 3
 
216
    fprintf( stderr, "bin_read: readlen is %d\n", readlen );
 
217
    fprintf( stderr, "bin_read: cc is %d\n", cc );
 
218
#endif /* DEBUG >= 3 */
 
219
 
 
220
    buf_ptr = buffer;
 
221
    while (( readlen > 0 ) && ( cc > 0 )) {
 
222
        if (( cc = read( bin.filed, buf_ptr, readlen )) > 0 ) {
 
223
#if DEBUG >= 3
 
224
            fprintf( stderr, "bin_read: cc is %d\n", cc );
 
225
#endif /* DEBUG >= 3 */
 
226
            readlen -= cc;
 
227
            buf_ptr += cc;
 
228
        }
 
229
    }
 
230
    if ( cc >= 0 ) {
 
231
        cc = buf_ptr - buffer;
 
232
        bin.forklen[ fork ] -= cc;
 
233
    }
 
234
 
 
235
#if DEBUG >= 3
 
236
    fprintf( stderr, "bin_read: chars read is %d\n", cc );
 
237
#endif /* DEBUG >= 3 */
 
238
    return( cc );
 
239
}
 
240
 
 
241
/*
 
242
 * bin_write 
 
243
 */
 
244
 
 
245
int bin_write( fork, buffer, length )
 
246
    int                 fork;
 
247
    char                *buffer;
 
248
    int                 length;
 
249
{
 
250
    char                *buf_ptr;
 
251
    int                 writelen;
 
252
    int                 cc = 0;
 
253
    off_t               pos;
 
254
    u_char              padchar = 0x7f;
 
255
                /* Not sure why, but it seems this must be 0x7f to match
 
256
                   other converters, not 0. (RLB) */
 
257
 
 
258
#if DEBUG >= 3
 
259
    fprintf( stderr, "bin_write: fork is %s\n", forkname[ fork ] );
 
260
    fprintf( stderr, "bin_write: remaining length is %d\n", bin.forklen[fork] );
 
261
#endif /* DEBUG >= 3 */
 
262
 
 
263
    if (( fork == RESOURCE ) && ( bin.forklen[ DATA ] != 0 )) {
 
264
        fprintf( stderr, "Forklength error.\n" );
 
265
        return( -1 );
 
266
    }
 
267
 
 
268
    buf_ptr = (char *)buffer;
 
269
    if ( bin.forklen[ fork ] >= length ) {
 
270
        writelen = length;
 
271
    } else {
 
272
        fprintf( stderr, "Forklength error.\n" );
 
273
        return( -1 );
 
274
    }
 
275
 
 
276
#if DEBUG >= 3
 
277
    fprintf( stderr, "bin_write: write length is %d\n", writelen );
 
278
#endif /* DEBUG >= 3 */
 
279
 
 
280
    while (( writelen > 0 ) && ( cc >= 0 )) {
 
281
        cc = write( bin.filed, buf_ptr, writelen );
 
282
        buf_ptr += cc;
 
283
        writelen -= cc;
 
284
    }
 
285
    if ( cc < 0 ) {
 
286
        perror( "Couldn't write to macbinary file:" );
 
287
        return( cc );
 
288
    }
 
289
    bin.forklen[ fork ] -= length;
 
290
 
 
291
    if ( bin.forklen[ fork ] < 0 ) {
 
292
        fprintf( stderr, "This should never happen, dude!\n" );
 
293
        return( bin.forklen[ fork ] );
 
294
    }
 
295
 
 
296
/*
 
297
 * add the padding at end of data and resource forks
 
298
 */
 
299
 
 
300
    if ( bin.forklen[ fork ] == 0 ) {
 
301
        pos = lseek( bin.filed, 0, SEEK_CUR );
 
302
#if DEBUG
 
303
        fprintf( stderr, "current position is %ld\n", pos );
 
304
#endif /* DEBUG */
 
305
        pos %= HEADBUFSIZ;
 
306
        if (pos != 0) { /* pad only if we need to */
 
307
          pos = lseek( bin.filed, HEADBUFSIZ - pos - 1, SEEK_CUR );
 
308
          if ( write( bin.filed, &padchar, 1 ) != 1 ) {
 
309
            perror( "Couldn't write to macbinary file:" );
 
310
            return( -1 );
 
311
          }
 
312
        }
 
313
#if DEBUG
 
314
          fprintf( stderr, "current position is %ld\n", pos );
 
315
#endif /* DEBUG */
 
316
    }
 
317
 
 
318
#if DEBUG
 
319
        fprintf( stderr, "\n" );
 
320
#endif /* DEBUG */
 
321
 
 
322
    return( length );
 
323
}
 
324
 
 
325
/* 
 
326
 * bin_header_read is called by bin_open, and before any information can
 
327
 * read from the fh substruct.  it must be called before any
 
328
 * of the bytes of the other two forks can be read, as well.
 
329
 */
 
330
 
 
331
int bin_header_read( fh, revision )
 
332
    struct FHeader      *fh;
 
333
    int                 revision;
 
334
{
 
335
    u_short             mask;
 
336
 
 
337
/*
 
338
 * Set the appropriate finder flags mask for the type of macbinary
 
339
 * file it is, and copy the extra macbinary II stuff from the header.
 
340
 * If it is not a macbinary file revision of I or II, then return
 
341
 * negative.
 
342
 */
 
343
 
 
344
    switch ( revision ) {
 
345
        case 3:
 
346
        case 2 :
 
347
            mask = htons( 0xfcee );
 
348
            memcpy(&fh->finder_info.fdFlags + 1, head_buf + 101,1 );
 
349
            break;
 
350
        case 1 :
 
351
            mask = htons( 0xfc00 );
 
352
            break;
 
353
        default :
 
354
            return( -1 );
 
355
            break;
 
356
    }
 
357
 
 
358
/*
 
359
 * Go through and copy all the stuff you can get from the 
 
360
 * MacBinary header into the fh struct.  What fun!
 
361
 */
 
362
 
 
363
    memcpy(fh->name, head_buf +  2, head_buf[ 1 ] );
 
364
    memcpy(&fh->create_date, head_buf +  91, 4 );
 
365
    fh->create_date = MAC_DATE_TO_UNIX(fh->create_date) - bin.gmtoff;
 
366
    fh->create_date = AD_DATE_FROM_UNIX(fh->create_date);
 
367
    memcpy( &fh->mod_date, head_buf +  95, 4 );
 
368
    fh->mod_date = MAC_DATE_TO_UNIX(fh->mod_date) - bin.gmtoff;
 
369
    fh->mod_date = AD_DATE_FROM_UNIX(fh->mod_date);
 
370
    fh->backup_date = AD_DATE_START;
 
371
    memcpy( &fh->finder_info, head_buf +  65, 8 );
 
372
 
 
373
#ifndef MACBINARY_PLAY_NICE_WITH_OTHERS /* (RLB) */
 
374
    memcpy( &fh->finder_info.fdFlags, head_buf + 73, 1 );
 
375
    fh->finder_info.fdFlags &= mask;
 
376
#else /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
 
377
        memcpy( &fh->finder_info.fdFlags, head_buf + 73, 2 );
 
378
#endif /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
 
379
 
 
380
    memcpy(&fh->finder_info.fdLocation, head_buf + 75, 4 );
 
381
    memcpy(&fh->finder_info.fdFldr, head_buf +  79, 2 );
 
382
    memcpy(&fh->forklen[ DATA ],  head_buf + 83, 4 );
 
383
    bin.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
 
384
    memcpy(&fh->forklen[ RESOURCE ],  head_buf +  87, 4 );
 
385
    bin.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
 
386
    fh->comment[0] = '\0';
 
387
 
 
388
    if (revision == 3) {
 
389
      fh->finder_xinfo.fdScript = *(head_buf + 106);
 
390
      fh->finder_xinfo.fdXFlags = *(head_buf + 107);
 
391
    }
 
392
 
 
393
#if DEBUG >= 5
 
394
    {
 
395
        short           flags;
 
396
        long            flags_long;
 
397
 
 
398
        fprintf( stderr, "Values read by bin_header_read\n" );
 
399
        fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
 
400
        fprintf( stderr, "file name\t\t%s\n", fh->name );
 
401
        fprintf( stderr, "get info comment\t%s\n", fh->comment );
 
402
        fprintf( stderr, "type\t\t\t%.*s\n", sizeof( fh->finder_info.fdType ),
 
403
                &fh->finder_info.fdType );
 
404
        fprintf( stderr, "creator\t\t\t%.*s\n", 
 
405
                sizeof( fh->finder_info.fdCreator ), 
 
406
                &fh->finder_info.fdCreator );
 
407
        memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
 
408
        flags = ntohs( flags );
 
409
        fprintf( stderr, "flags\t\t\t%x\n", flags );
 
410
 
 
411
        /* Show fdLocation too (RLB) */
 
412
        memcpy( &flags_long, &fh->finder_info.fdLocation,
 
413
                sizeof( flags_long ));
 
414
        flags_long = ntohl( flags_long );
 
415
        fprintf( stderr, "location flags\t\t%lx\n", flags_long );
 
416
 
 
417
        fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
 
418
        fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
 
419
        fprintf( stderr, "\n" );
 
420
    }
 
421
#endif /* DEBUG >= 5 */
 
422
 
 
423
    return( 0 );
 
424
}
 
425
 
 
426
/* 
 
427
 * bin_header_write is called by bin_open, and relies on information
 
428
 * from the fh substruct.  it must be called before any
 
429
 * of the bytes of the other two forks can be written, as well.
 
430
 * bin_header_write and bin_header_read are opposites.
 
431
 */
 
432
 
 
433
int bin_header_write( fh )
 
434
    struct FHeader      *fh;
 
435
{
 
436
    char                *write_ptr;
 
437
    u_int32_t           t;
 
438
    int                 wc;
 
439
    int                 wr;
 
440
 
 
441
    memset(head_buf, 0, sizeof( head_buf ));
 
442
    head_buf[ 1 ] = (u_char)strlen( fh->name );
 
443
    memcpy( head_buf + 2, fh->name, head_buf[ 1 ] );
 
444
    memcpy( head_buf + 65, &fh->finder_info, 8 );
 
445
 
 
446
#ifndef MACBINARY_PLAY_NICE_WITH_OTHERS /* (RLB) */
 
447
    memcpy( head_buf + 73, &fh->finder_info.fdFlags, 1 );
 
448
#else /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
 
449
    memcpy( head_buf + 73, &fh->finder_info.fdFlags, 2 );
 
450
#endif /* ! MACBINARY_PLAY_NICE_WITH_OTHERS */
 
451
 
 
452
    memcpy( head_buf + 75, &fh->finder_info.fdLocation, 4 );
 
453
    memcpy( head_buf + 79, &fh->finder_info.fdFldr, 2 );
 
454
    memcpy( head_buf + 83, &fh->forklen[ DATA ], 4 );
 
455
    memcpy( head_buf + 87, &fh->forklen[ RESOURCE ], 4 );
 
456
    t = AD_DATE_TO_UNIX(fh->create_date) + bin.gmtoff;
 
457
    t = MAC_DATE_FROM_UNIX(t);
 
458
    memcpy( head_buf + 91, &t, sizeof(t) );
 
459
    t = AD_DATE_TO_UNIX(fh->mod_date) + bin.gmtoff;
 
460
    t = MAC_DATE_FROM_UNIX(t);
 
461
    memcpy( head_buf + 95, &t, sizeof(t) );
 
462
    memcpy( head_buf + 101, &fh->finder_info.fdFlags + 1, 1);
 
463
 
 
464
    /* macbinary III */
 
465
    memcpy( head_buf + 102, "mBIN", 4);
 
466
    *(head_buf + 106) = fh->finder_xinfo.fdScript;
 
467
    *(head_buf + 107) = fh->finder_xinfo.fdXFlags;
 
468
    head_buf[ 122 ] = 130;
 
469
 
 
470
    head_buf[ 123 ] = 129;
 
471
 
 
472
    bin.headercrc = htons( updcrc( (u_short) 0, head_buf, 124 ));
 
473
    memcpy(head_buf + 124, &bin.headercrc, sizeof( bin.headercrc ));
 
474
 
 
475
    bin.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
 
476
    bin.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
 
477
 
 
478
#if DEBUG >= 5
 
479
    {
 
480
        short   flags;
 
481
        long    flags_long;
 
482
 
 
483
        fprintf( stderr, "Values written by bin_header_write\n" );
 
484
        fprintf( stderr, "name length\t\t%d\n", head_buf[ 1 ] );
 
485
        fprintf( stderr, "file name\t\t%s\n", (char *)&head_buf[ 2 ] );
 
486
        fprintf( stderr, "type\t\t\t%.4s\n", (char *)&head_buf[ 65 ] );
 
487
        fprintf( stderr, "creator\t\t\t%.4s\n", (char *)&head_buf[ 69 ] );
 
488
 
 
489
        memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
 
490
        flags = ntohs( flags );
 
491
        fprintf( stderr, "flags\t\t\t%x\n", flags );
 
492
 
 
493
        /* Show fdLocation too (RLB) */
 
494
        memcpy( &flags_long, &fh->finder_info.fdLocation,
 
495
                sizeof( flags_long ));
 
496
        flags_long = ntohl( flags_long );
 
497
        fprintf( stderr, "location flags\t\t%ldx\n", flags_long );
 
498
 
 
499
        fprintf( stderr, "data fork length\t%ld\n", bin.forklen[DATA] );
 
500
        fprintf( stderr, "resource fork length\t%ld\n", bin.forklen[RESOURCE] );
 
501
        fprintf( stderr, "\n" );
 
502
    }
 
503
#endif /* DEBUG >= 5 */
 
504
 
 
505
    write_ptr = (char *)head_buf;
 
506
    wc = sizeof( head_buf );
 
507
    wr = 0;
 
508
    while (( wc > 0 ) && ( wr >= 0 )) {
 
509
        wr = write( bin.filed, write_ptr, wc );
 
510
        write_ptr += wr;
 
511
        wc -= wr;
 
512
    }
 
513
    if ( wr < 0 ) {
 
514
        perror( "Couldn't write macbinary header:" );
 
515
        return( wr );
 
516
    }
 
517
 
 
518
    return( 0 );
 
519
}
 
520
 
 
521
/*
 
522
 * test_header is called from bin_open.  it checks certain values of
 
523
 * the first 128 bytes, determines if the file is a MacBinary,
 
524
 * MacBinary II, MacBinary III, or non-MacBinary file, and returns a
 
525
 * one, two, three or negative one to indicate the file type.
 
526
 *
 
527
 * If the signature at 102 is equal to "mBIN," then it's a MacBinary
 
528
 * III file. Bytes 0 and 74 must be zero for the file to be any type
 
529
 * of MacBinary.  If the crc of bytes 0 through 123 equals the value
 
530
 * at offset 124 then it is a MacBinary II.  If not, then if byte 82
 
531
 * is zero, byte 2 is a valid value for a mac filename length (between
 
532
 * one and sixty-three), and bytes 101 through 125 are all zero, then
 
533
 * the file is a MacBinary. 
 
534
 *
 
535
 * NOTE: apple's MacBinary II files have a non-zero value at byte 74.
 
536
 * so, the check for byte 74 isn't very useful.
 
537
 */
 
538
 
 
539
int test_header(void)
 
540
{
 
541
    const char          zeros[25] = "";
 
542
    u_int32_t           cc;
 
543
    u_short             header_crc;
 
544
    u_char              namelen;
 
545
 
 
546
#if DEBUG
 
547
    fprintf( stderr, "entering test_header\n" );
 
548
#endif /* DEBUG */
 
549
 
 
550
    cc = read( bin.filed, (char *)head_buf, sizeof( head_buf ));
 
551
    if ( cc < sizeof( head_buf )) {
 
552
        perror( "Premature end of file :" );
 
553
        return( -1 );
 
554
    }
 
555
 
 
556
#if DEBUG
 
557
    fprintf( stderr, "was able to read HEADBUFSIZ bytes\n" );
 
558
#endif /* DEBUG */
 
559
 
 
560
    /* check for macbinary III header */
 
561
    if (memcmp(head_buf + 102, "mBIN", 4) == 0)
 
562
        return 3;
 
563
 
 
564
    /* check for macbinary II even if only one of the bytes is zero */
 
565
    if (( head_buf[ 0 ] == 0 ) || ( head_buf[ 74 ] == 0 )) {
 
566
#if DEBUG
 
567
      fprintf( stderr, "byte 0 and 74 are both zero\n" );
 
568
#endif /* DEBUG */
 
569
      bin.headercrc = updcrc( (u_short) 0, head_buf, 124 );
 
570
      memcpy(&header_crc, head_buf + 124, sizeof( header_crc ));
 
571
      header_crc = ntohs( header_crc );
 
572
      if ( header_crc == bin.headercrc ) {
 
573
        return( 2 );
 
574
      }
 
575
 
 
576
#if DEBUG
 
577
      fprintf( stderr, "header crc didn't pan out\n" );
 
578
#endif /* DEBUG */
 
579
    }
 
580
 
 
581
    /* now see if we have a macbinary file. */
 
582
    if ( head_buf[ 82 ] != 0 ) {
 
583
        return( -1 );
 
584
    }
 
585
    memcpy( &namelen, head_buf + 1, sizeof( namelen ));
 
586
#if DEBUG
 
587
    fprintf( stderr, "name length is %d\n", namelen );
 
588
#endif /* DEBUG */
 
589
    if (( namelen < 1 ) || ( namelen > 63 )) {
 
590
        return( -1 );
 
591
    }
 
592
 
 
593
    /* bytes 101 - 125 should be zero */
 
594
    if (memcmp(head_buf + 101, zeros, sizeof(zeros)) != 0)
 
595
        return -1;
 
596
 
 
597
    /* macbinary forks aren't larger than 0x7FFFFF */
 
598
    memcpy(&cc, head_buf + 83, sizeof(cc));
 
599
    cc = ntohl(cc);
 
600
    if (cc > 0x7FFFFF)
 
601
        return -1;
 
602
    memcpy(&cc, head_buf + 87, sizeof(cc));
 
603
    cc = ntohl(cc);
 
604
    if (cc > 0x7FFFFF)
 
605
        return -1;
 
606
 
 
607
 
 
608
#if DEBUG
 
609
    fprintf( stderr, "byte 82 is zero and name length is cool\n" );
 
610
#endif /* DEBUG */
 
611
 
 
612
    return( 1 );
 
613
}