8 # include <machine/endian.h>
10 # include <netinet/in.h>
18 #include <atalk/adouble.h>
19 #include <netatalk/endian.h>
25 /* String used to indicate standard input instead of a disk
26 file. Should be a string not normally used for a file
37 /* Looking for the first or any other line of a binhex file
42 /* This is the binhex run length encoding character
46 /* These are field sizes in bytes of various pieces of the
60 FILE *rawhex, *expandhex;
63 struct hqx_file_data {
64 u_int32_t forklen[ NUMFORKS ];
65 u_short forkcrc[ NUMFORKS ];
66 char path[ MAXPATHLEN + 1];
71 extern char *forkname[];
72 u_char hqx7_buf[8192];
78 hqx_open must be called first. pass it a filename that is supposed
79 to contain a binhqx file. an hqx struct will be allocated and
80 somewhat initialized; hqx_fd is set. skip_junk is called from
81 here; skip_junk leaves hqx7_first and hqx7_last set.
84 hqx_open( hqxfile, flags, fh, options )
92 fprintf( stderr, "megatron: entering hqx_open\n" );
94 if ( flags == O_RDONLY ) {
97 rawhex = fopen( "rawhex.unhex", "w" );
98 expandhex = fopen( "expandhex.unhex", "w" );
103 if ( strcmp( hqxfile, STDIN ) == 0 ) {
104 hqx.filed = fileno( stdin );
105 } else if (( hqx.filed = open( hqxfile, O_RDONLY )) < 0 ) {
110 if ( skip_junk( FIRST ) == 0 ) {
111 if ( hqx_header_read( fh ) == 0 ) {
115 pos = lseek( hqx.filed, 0, L_INCR );
116 fprintf( stderr, "megatron: current position is %ld\n", pos );
122 fprintf( stderr, "%s\n", hqxfile );
125 maxlen = sizeof( hqx.path ) -1;
126 strncpy( hqx.path, fh->name, maxlen );
127 strncpy( hqx.path, mtoupath( hqx.path ), maxlen );
128 strncat( hqx.path, ".hqx", maxlen - strlen( hqx.path ));
129 if (( hqx.filed = open( hqx.path, flags, 0666 )) < 0 ) {
133 if ( hqx_header_write( fh ) != 0 ) {
135 fprintf( stderr, "%s\n", hqx.path );
143 * hqx_close must be called before a second file can be opened using
144 * hqx_open. Upon successful completion, a value of 0 is returned.
145 * Otherwise, a value of -1 is returned.
148 hqx_close( keepflag )
151 if ( keepflag == KEEP ) {
152 return( close( hqx.filed ));
153 } else if ( keepflag == TRASH ) {
154 if (( strcmp( hqx.path, STDIN ) != 0 ) && ( unlink( hqx.path ) < 0 )) {
162 * hqx_read is called until it returns zero for each fork. when it is
163 * and finds that there is zero left to give, it reads in and compares
164 * the crc with the calculated one, and returns zero if all is well.
165 * it returns negative is the crc was bad or if has been called too many
166 * times for the same fork. hqx_read must be called enough times to
167 * return zero and no more than that.
170 hqx_read( fork, buffer, length )
182 pos = lseek( hqx.filed, 0, L_INCR );
183 fprintf( stderr, "hqx_read: current position is %ld\n", pos );
185 fprintf( stderr, "hqx_read: fork is %s\n", forkname[ fork ] );
186 fprintf( stderr, "hqx_read: remaining length is %d\n", hqx.forklen[fork] );
189 if ( hqx.forklen[ fork ] < 0 ) {
190 fprintf( stderr, "This should never happen, dude!\n" );
191 return( hqx.forklen[ fork ] );
194 if ( hqx.forklen[ fork ] == 0 ) {
195 cc = hqx_7tobin( (char *)&storedcrc, sizeof( storedcrc ));
196 if ( cc == sizeof( storedcrc )) {
197 storedcrc = ntohs ( storedcrc );
199 fprintf( stderr, "hqx_read: storedcrc\t\t%x\n", storedcrc );
200 fprintf( stderr, "hqx_read: observed crc\t\t%x\n\n", hqx.forkcrc[fork] );
202 if ( storedcrc == hqx.forkcrc[ fork ] ) {
205 fprintf( stderr, "hqx_read: Bad %s fork crc, dude\n",
211 if ( hqx.forklen[ fork ] < length ) {
212 readlen = hqx.forklen[ fork ];
217 fprintf( stderr, "hqx_read: readlen is %d\n", readlen );
220 cc = hqx_7tobin( buffer, readlen );
222 hqx.forkcrc[ fork ] =
223 updcrc( hqx.forkcrc[ fork ], (u_char *)buffer, cc );
224 hqx.forklen[ fork ] -= cc;
227 fprintf( stderr, "hqx_read: chars read is %d\n", cc );
233 * hqx_header_read is called by hqx_open, and before any information can
234 * read from the hqx_header substruct. it must be called before any
235 * of the bytes of the other two forks can be read, as well.
236 * returns a negative number if it was unable to pull enough information
237 * to fill the hqx_header fields.
240 hqx_header_read( fh )
243 char *headerbuf, *headerptr;
244 u_int32_t time_seconds;
251 headerfork = open( "headerfork", O_WRONLY|O_CREAT, 0622 );
254 mask = htons( 0xfcee );
257 if ( hqx_7tobin( &namelen, sizeof( namelen )) == 0 ) {
258 fprintf( stderr, "Premature end of file :" );
261 hqx.headercrc = updcrc( hqx.headercrc, (u_char *)&namelen,
265 write( headerfork, &namelen, sizeof( namelen ));
269 (char *)malloc( (unsigned int)( namelen + HEADSIZ ))) == 0 ) {
272 if ( hqx_7tobin( headerbuf, ( namelen + HEADSIZ )) == 0 ) {
274 fprintf( stderr, "Premature end of file :" );
277 headerptr = headerbuf;
278 hqx.headercrc = updcrc( hqx.headercrc,
279 (u_char *)headerbuf, ( namelen + HEADSIZ - CRCSIZ ));
282 write( headerfork, headerbuf, ( namelen + HEADSIZ ));
286 * stuff from the hqx file header
289 memcpy( fh->name, headerptr, (int)namelen );
290 headerptr += namelen;
291 headerptr += VERSION;
292 memcpy(&fh->finder_info, headerptr, TCSIZ );
294 memcpy(&fh->finder_info.fdFlags, headerptr, FLAGSIZ );
295 fh->finder_info.fdFlags = fh->finder_info.fdFlags & mask;
296 headerptr += FLAGSIZ;
297 memcpy(&fh->forklen[ DATA ], headerptr, DATASIZ );
298 hqx.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
299 headerptr += DATASIZ;
300 memcpy( &fh->forklen[ RESOURCE ], headerptr, RESSIZ );
301 hqx.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
303 memcpy(&header_crc, headerptr, CRCSIZ );
305 header_crc = ntohs( header_crc );
308 * stuff that should be zero'ed out
311 fh->comment[0] = '\0';
312 fh->finder_info.fdLocation = 0;
313 fh->finder_info.fdFldr = 0;
319 fprintf( stderr, "Values read by hqx_header_read\n" );
320 fprintf( stderr, "name length\t\t%d\n", namelen );
321 fprintf( stderr, "file name\t\t%s\n", fh->name );
322 fprintf( stderr, "get info comment\t%s\n", fh->comment );
323 fprintf( stderr, "type\t\t\t%.*s\n", sizeof( fh->finder_info.fdType ),
324 &fh->finder_info.fdType );
325 fprintf( stderr, "creator\t\t\t%.*s\n",
326 sizeof( fh->finder_info.fdCreator ),
327 &fh->finder_info.fdCreator );
328 memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
329 flags = ntohs( flags );
330 fprintf( stderr, "flags\t\t\t%x\n", flags );
331 fprintf( stderr, "data fork length\t%ld\n", hqx.forklen[DATA] );
332 fprintf( stderr, "resource fork length\t%ld\n", hqx.forklen[RESOURCE] );
333 fprintf( stderr, "header_crc\t\t%x\n", header_crc );
334 fprintf( stderr, "observed crc\t\t%x\n", hqx.headercrc );
335 fprintf( stderr, "\n" );
340 * create and modify times are figured from right now
343 time_seconds = AD_DATE_FROM_UNIX(time( NULL ));
344 memcpy( &fh->create_date, &time_seconds,
345 sizeof( fh->create_date ));
346 memcpy( &fh->mod_date, &time_seconds,
347 sizeof( fh->mod_date ));
348 fh->backup_date = AD_DATE_START;
351 * stuff that should be zero'ed out
354 fh->comment[0] = '\0';
355 memset( &fh->finder_info.fdLocation, 0,
356 sizeof( fh->finder_info.fdLocation ));
357 memset( &fh->finder_info.fdFldr, 0, sizeof( fh->finder_info.fdFldr ));
359 hqx.forkcrc[ DATA ] = 0;
360 hqx.forkcrc[ RESOURCE ] = 0;
363 if ( header_crc != hqx.headercrc ) {
364 fprintf( stderr, "Bad Header crc, dude :" );
374 hqx_header_write( fh )
381 * hqx7_fill is called from skip_junk and hqx_7tobin. it pulls from the
382 * binhqx file into the hqx7 buffer. returns number of bytes read
383 * or a zero for end of file.
384 * it sets the pointers to the hqx7 buffer up to point to the valid data.
387 hqx7_fill( hqx7_ptr )
393 cs = hqx7_ptr - hqx7_buf;
394 if ( cs >= sizeof( hqx7_buf )) return( -1 );
395 hqx7_first = hqx7_ptr;
396 cc = read( hqx.filed, (char *)hqx7_first, ( sizeof( hqx7_buf ) - cs ));
401 hqx7_last = ( hqx7_first + cc );
406 char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
407 0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
409 Input characters are translated to a number between 0 and 63 by direct
410 array lookup. 0xFF signals a bad character. 0xFE is signals a legal
411 character that should be skipped, namely '\n', '\r'. 0xFD signals ':'.
412 0xFC signals a whitespace character.
415 u_char hqxlookup[] = {
416 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
417 0xFF, 0xFC, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
418 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
419 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
420 0xFC, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
421 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
422 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
423 0x14, 0x15, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
424 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
425 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
426 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
427 0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
428 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
429 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
430 0x3D, 0x3E, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
431 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
432 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
433 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
434 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
435 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
436 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
437 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
438 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
439 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
440 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
441 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
442 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
443 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
444 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
445 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
446 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
447 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
451 * skip_junk is called from hqx_open. it skips over junk in the file until
452 * it comes to a line containing a valid first line of binhqx encoded file.
453 * returns a 0 for success, negative if it never finds good data.
454 * pass a FIRST when looking for the first valid binhex line, a value of
455 * OTHER when looking for any subsequent line.
467 if ( line == FIRST ) {
468 if ( hqx7_fill( hqx7_buf ) <= 0 ) {
469 fprintf( stderr, "Premature end of file :" );
474 while ( found == NOWAY ) {
475 if ( line == FIRST ) {
476 if ( *hqx7_first == ':' ) {
480 while (( stopflag == NOWAY ) &&
481 ( nc < ( hqx7_last - hqx7_first ))) {
482 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
487 stopflag = SURETHANG;
494 if (( nc > 30 ) && ( nc < 64 ) &&
495 (( c == 0xFE ) || ( c == 0xFD ))) found = SURETHANG;
500 if (( prevchar = hqxlookup[ *hqx7_first ] ) == 0xFE ) {
504 while (( stopflag == NOWAY ) &&
505 ( nc < ( hqx7_last - hqx7_first ))) {
506 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
509 if (( prevchar == 0xFC ) || ( prevchar == 0xFE )) {
515 stopflag = SURETHANG;
525 } else if (( nc > 30 ) && ( c == 0xFE )) {
533 if (( hqx7_last - hqx7_first ) == nc ) {
534 if ( line == FIRST ) {
536 } else *hqx7_buf = '\n';
537 memcpy(hqx7_buf + 1, hqx7_first, nc );
538 hqx7_first = hqx7_buf + ( ++nc );
539 if ( hqx7_fill( hqx7_first ) <= 0 ) {
540 fprintf( stderr, "Premature end of file :" );
543 hqx7_first = hqx7_buf;
551 * hqx_7tobin is used to read the data, converted to binary. It is
552 * called by hqx_header_read to get the header information, and must be
553 * called to get the data for each fork, and the crc data for each
554 * fork. it has the same basic calling structure as unix read. the
555 * number of valid bytes read is returned. It does buffering so as to
556 * return the requested length of data every time, unless the end of
560 hqx_7tobin( outbuf, datalen )
564 static u_char hqx8[3];
566 static u_char prev_hqx8;
567 static u_char prev_out;
568 static u_char prev_hqx7;
576 fprintf( stderr, "hqx_7tobin: datalen entering %d\n", datalen );
577 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
580 if ( first_flag == 0 ) {
590 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
594 out_last = out_first + datalen;
596 while (( out_first < out_last ) && ( eofflag == 0 )) {
598 if ( hqx7_first == hqx7_last ) {
599 if ( hqx7_fill( hqx7_buf ) == 0 ) {
607 while (( hqx7i < 4 ) && ( hqx7_first < hqx7_last )) {
608 hqx7[ hqx7i ] = hqxlookup[ *hqx7_first ];
609 switch ( hqx7[ hqx7i ] ) {
611 if (( prev_hqx7 == 0xFC ) || ( prev_hqx7 == 0xFE )) {
618 while ( hqx7i < 4 ) {
623 prev_hqx7 = hqx7[ hqx7i ];
624 if ( skip_junk( OTHER ) < 0 ) {
625 fprintf( stderr, "\n" );
627 while ( hqx7i < 4 ) {
628 hqx7[ hqx7i++ ] = 0; }
632 prev_hqx7 = hqx7[ hqx7i++ ];
639 hqx8[ 0 ] = (( hqx7[ 0 ] << 2 ) | ( hqx7[ 1 ] >> 4 ));
640 hqx8[ 1 ] = (( hqx7[ 1 ] << 4 ) | ( hqx7[ 2 ] >> 2 ));
641 hqx8[ 2 ] = (( hqx7[ 2 ] << 6 ) | ( hqx7[ 3 ] ));
646 while (( hqx8i < 3 ) && ( out_first < out_last )) {
649 putc( hqx8i, rawhex );
650 putc( hqx8[ hqx8i ], rawhex );
653 if ( prev_hqx8 == RUNCHAR ) {
654 if ( hqx8[ hqx8i ] == 0 ) {
655 *out_first = prev_hqx8;
657 putc( *out_first, expandhex );
659 prev_out = prev_hqx8;
662 while (( out_first < out_last ) && ( hqx8[ hqx8i ] > 1 )) {
663 *out_first = prev_out;
665 putc( *out_first, expandhex );
670 if ( hqx8[ hqx8i ] < 2 ) {
671 prev_hqx8 = hqx8[ hqx8i ];
677 prev_hqx8 = hqx8[ hqx8i ];
678 if ( prev_hqx8 != RUNCHAR ) {
679 *out_first = prev_hqx8;
681 putc( *out_first, expandhex );
683 prev_out = prev_hqx8;
691 return( out_first - outbuf );