12 # include <machine/endian.h>
14 # include <netinet/in.h>
22 #include <atalk/adouble.h>
23 #include <netatalk/endian.h>
28 /* String used to indicate standard input instead of a disk
29 file. Should be a string not normally used for a file
40 /* Looking for the first or any other line of a binhex file
45 /* This is the binhex run length encoding character
49 /* These are field sizes in bytes of various pieces of the
63 FILE *rawhex, *expandhex;
66 struct hqx_file_data {
67 u_int32_t forklen[ NUMFORKS ];
68 u_short forkcrc[ NUMFORKS ];
69 char path[ MAXPATHLEN + 1];
74 extern char *forkname[];
75 u_char hqx7_buf[8192];
81 hqx_open must be called first. pass it a filename that is supposed
82 to contain a binhqx file. an hqx struct will be allocated and
83 somewhat initialized; hqx_fd is set. skip_junk is called from
84 here; skip_junk leaves hqx7_first and hqx7_last set.
87 hqx_open( hqxfile, flags, fh, options )
95 fprintf( stderr, "megatron: entering hqx_open\n" );
97 if ( flags == O_RDONLY ) {
100 rawhex = fopen( "rawhex.unhex", "w" );
101 expandhex = fopen( "expandhex.unhex", "w" );
106 if ( strcmp( hqxfile, STDIN ) == 0 ) {
107 hqx.filed = fileno( stdin );
108 } else if (( hqx.filed = open( hqxfile, O_RDONLY )) < 0 ) {
113 if ( skip_junk( FIRST ) == 0 ) {
114 if ( hqx_header_read( fh ) == 0 ) {
118 pos = lseek( hqx.filed, 0, L_INCR );
119 fprintf( stderr, "megatron: current position is %ld\n", pos );
125 fprintf( stderr, "%s\n", hqxfile );
128 maxlen = sizeof( hqx.path ) -1;
129 strncpy( hqx.path, fh->name, maxlen );
130 strncpy( hqx.path, mtoupath( hqx.path ), maxlen );
131 strncat( hqx.path, ".hqx", maxlen - strlen( hqx.path ));
132 if (( hqx.filed = open( hqx.path, flags, 0666 )) < 0 ) {
136 if ( hqx_header_write( fh ) != 0 ) {
138 fprintf( stderr, "%s\n", hqx.path );
146 * hqx_close must be called before a second file can be opened using
147 * hqx_open. Upon successful completion, a value of 0 is returned.
148 * Otherwise, a value of -1 is returned.
151 hqx_close( keepflag )
154 if ( keepflag == KEEP ) {
155 return( close( hqx.filed ));
156 } else if ( keepflag == TRASH ) {
157 if (( strcmp( hqx.path, STDIN ) != 0 ) && ( unlink( hqx.path ) < 0 )) {
165 * hqx_read is called until it returns zero for each fork. when it is
166 * and finds that there is zero left to give, it reads in and compares
167 * the crc with the calculated one, and returns zero if all is well.
168 * it returns negative is the crc was bad or if has been called too many
169 * times for the same fork. hqx_read must be called enough times to
170 * return zero and no more than that.
173 hqx_read( fork, buffer, length )
185 pos = lseek( hqx.filed, 0, L_INCR );
186 fprintf( stderr, "hqx_read: current position is %ld\n", pos );
188 fprintf( stderr, "hqx_read: fork is %s\n", forkname[ fork ] );
189 fprintf( stderr, "hqx_read: remaining length is %d\n", hqx.forklen[fork] );
192 if ( hqx.forklen[ fork ] < 0 ) {
193 fprintf( stderr, "This should never happen, dude!\n" );
194 return( hqx.forklen[ fork ] );
197 if ( hqx.forklen[ fork ] == 0 ) {
198 cc = hqx_7tobin( (char *)&storedcrc, sizeof( storedcrc ));
199 if ( cc == sizeof( storedcrc )) {
200 storedcrc = ntohs ( storedcrc );
202 fprintf( stderr, "hqx_read: storedcrc\t\t%x\n", storedcrc );
203 fprintf( stderr, "hqx_read: observed crc\t\t%x\n\n", hqx.forkcrc[fork] );
205 if ( storedcrc == hqx.forkcrc[ fork ] ) {
208 fprintf( stderr, "hqx_read: Bad %s fork crc, dude\n",
214 if ( hqx.forklen[ fork ] < length ) {
215 readlen = hqx.forklen[ fork ];
220 fprintf( stderr, "hqx_read: readlen is %d\n", readlen );
223 cc = hqx_7tobin( buffer, readlen );
225 hqx.forkcrc[ fork ] =
226 updcrc( hqx.forkcrc[ fork ], (u_char *)buffer, cc );
227 hqx.forklen[ fork ] -= cc;
230 fprintf( stderr, "hqx_read: chars read is %d\n", cc );
236 * hqx_header_read is called by hqx_open, and before any information can
237 * read from the hqx_header substruct. it must be called before any
238 * of the bytes of the other two forks can be read, as well.
239 * returns a negative number if it was unable to pull enough information
240 * to fill the hqx_header fields.
243 hqx_header_read( fh )
246 char *headerbuf, *headerptr;
247 u_int32_t time_seconds;
254 headerfork = open( "headerfork", O_WRONLY|O_CREAT, 0622 );
257 mask = htons( 0xfcee );
260 if ( hqx_7tobin( &namelen, sizeof( namelen )) == 0 ) {
261 fprintf( stderr, "Premature end of file :" );
264 hqx.headercrc = updcrc( hqx.headercrc, (u_char *)&namelen,
268 write( headerfork, &namelen, sizeof( namelen ));
272 (char *)malloc( (unsigned int)( namelen + HEADSIZ ))) == 0 ) {
275 if ( hqx_7tobin( headerbuf, ( namelen + HEADSIZ )) == 0 ) {
277 fprintf( stderr, "Premature end of file :" );
280 headerptr = headerbuf;
281 hqx.headercrc = updcrc( hqx.headercrc,
282 (u_char *)headerbuf, ( namelen + HEADSIZ - CRCSIZ ));
285 write( headerfork, headerbuf, ( namelen + HEADSIZ ));
289 * stuff from the hqx file header
292 memcpy( fh->name, headerptr, (int)namelen );
293 headerptr += namelen;
294 headerptr += VERSION;
295 memcpy(&fh->finder_info, headerptr, TCSIZ );
297 memcpy(&fh->finder_info.fdFlags, headerptr, FLAGSIZ );
298 fh->finder_info.fdFlags = fh->finder_info.fdFlags & mask;
299 headerptr += FLAGSIZ;
300 memcpy(&fh->forklen[ DATA ], headerptr, DATASIZ );
301 hqx.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
302 headerptr += DATASIZ;
303 memcpy( &fh->forklen[ RESOURCE ], headerptr, RESSIZ );
304 hqx.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
306 memcpy(&header_crc, headerptr, CRCSIZ );
308 header_crc = ntohs( header_crc );
311 * stuff that should be zero'ed out
314 fh->comment[0] = '\0';
315 fh->finder_info.fdLocation = 0;
316 fh->finder_info.fdFldr = 0;
322 fprintf( stderr, "Values read by hqx_header_read\n" );
323 fprintf( stderr, "name length\t\t%d\n", namelen );
324 fprintf( stderr, "file name\t\t%s\n", fh->name );
325 fprintf( stderr, "get info comment\t%s\n", fh->comment );
326 fprintf( stderr, "type\t\t\t%.*s\n", sizeof( fh->finder_info.fdType ),
327 &fh->finder_info.fdType );
328 fprintf( stderr, "creator\t\t\t%.*s\n",
329 sizeof( fh->finder_info.fdCreator ),
330 &fh->finder_info.fdCreator );
331 memcpy( &flags, &fh->finder_info.fdFlags, sizeof( flags ));
332 flags = ntohs( flags );
333 fprintf( stderr, "flags\t\t\t%x\n", flags );
334 fprintf( stderr, "data fork length\t%ld\n", hqx.forklen[DATA] );
335 fprintf( stderr, "resource fork length\t%ld\n", hqx.forklen[RESOURCE] );
336 fprintf( stderr, "header_crc\t\t%x\n", header_crc );
337 fprintf( stderr, "observed crc\t\t%x\n", hqx.headercrc );
338 fprintf( stderr, "\n" );
343 * create and modify times are figured from right now
346 time_seconds = AD_DATE_FROM_UNIX(time( NULL ));
347 memcpy( &fh->create_date, &time_seconds,
348 sizeof( fh->create_date ));
349 memcpy( &fh->mod_date, &time_seconds,
350 sizeof( fh->mod_date ));
351 fh->backup_date = AD_DATE_START;
354 * stuff that should be zero'ed out
357 fh->comment[0] = '\0';
358 memset( &fh->finder_info.fdLocation, 0,
359 sizeof( fh->finder_info.fdLocation ));
360 memset( &fh->finder_info.fdFldr, 0, sizeof( fh->finder_info.fdFldr ));
362 hqx.forkcrc[ DATA ] = 0;
363 hqx.forkcrc[ RESOURCE ] = 0;
366 if ( header_crc != hqx.headercrc ) {
367 fprintf( stderr, "Bad Header crc, dude :" );
377 hqx_header_write( fh )
384 * hqx7_fill is called from skip_junk and hqx_7tobin. it pulls from the
385 * binhqx file into the hqx7 buffer. returns number of bytes read
386 * or a zero for end of file.
387 * it sets the pointers to the hqx7 buffer up to point to the valid data.
390 hqx7_fill( hqx7_ptr )
396 cs = hqx7_ptr - hqx7_buf;
397 if ( cs >= sizeof( hqx7_buf )) return( -1 );
398 hqx7_first = hqx7_ptr;
399 cc = read( hqx.filed, (char *)hqx7_first, ( sizeof( hqx7_buf ) - cs ));
404 hqx7_last = ( hqx7_first + cc );
409 char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
410 0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
412 Input characters are translated to a number between 0 and 63 by direct
413 array lookup. 0xFF signals a bad character. 0xFE is signals a legal
414 character that should be skipped, namely '\n', '\r'. 0xFD signals ':'.
415 0xFC signals a whitespace character.
418 u_char hqxlookup[] = {
419 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
420 0xFF, 0xFC, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
421 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
422 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
423 0xFC, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
424 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
425 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
426 0x14, 0x15, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
427 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
428 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
429 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
430 0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
431 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
432 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
433 0x3D, 0x3E, 0x3F, 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,
448 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
449 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
450 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
454 * skip_junk is called from hqx_open. it skips over junk in the file until
455 * it comes to a line containing a valid first line of binhqx encoded file.
456 * returns a 0 for success, negative if it never finds good data.
457 * pass a FIRST when looking for the first valid binhex line, a value of
458 * OTHER when looking for any subsequent line.
470 if ( line == FIRST ) {
471 if ( hqx7_fill( hqx7_buf ) <= 0 ) {
472 fprintf( stderr, "Premature end of file :" );
477 while ( found == NOWAY ) {
478 if ( line == FIRST ) {
479 if ( *hqx7_first == ':' ) {
483 while (( stopflag == NOWAY ) &&
484 ( nc < ( hqx7_last - hqx7_first ))) {
485 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
490 stopflag = SURETHANG;
497 if (( nc > 30 ) && ( nc < 64 ) &&
498 (( c == 0xFE ) || ( c == 0xFD ))) found = SURETHANG;
503 if (( prevchar = hqxlookup[ *hqx7_first ] ) == 0xFE ) {
507 while (( stopflag == NOWAY ) &&
508 ( nc < ( hqx7_last - hqx7_first ))) {
509 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
512 if (( prevchar == 0xFC ) || ( prevchar == 0xFE )) {
518 stopflag = SURETHANG;
528 } else if (( nc > 30 ) && ( c == 0xFE )) {
536 if (( hqx7_last - hqx7_first ) == nc ) {
537 if ( line == FIRST ) {
539 } else *hqx7_buf = '\n';
540 memcpy(hqx7_buf + 1, hqx7_first, nc );
541 hqx7_first = hqx7_buf + ( ++nc );
542 if ( hqx7_fill( hqx7_first ) <= 0 ) {
543 fprintf( stderr, "Premature end of file :" );
546 hqx7_first = hqx7_buf;
554 * hqx_7tobin is used to read the data, converted to binary. It is
555 * called by hqx_header_read to get the header information, and must be
556 * called to get the data for each fork, and the crc data for each
557 * fork. it has the same basic calling structure as unix read. the
558 * number of valid bytes read is returned. It does buffering so as to
559 * return the requested length of data every time, unless the end of
563 hqx_7tobin( outbuf, datalen )
567 static u_char hqx8[3];
569 static u_char prev_hqx8;
570 static u_char prev_out;
571 static u_char prev_hqx7;
579 fprintf( stderr, "hqx_7tobin: datalen entering %d\n", datalen );
580 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
583 if ( first_flag == 0 ) {
593 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
597 out_last = out_first + datalen;
599 while (( out_first < out_last ) && ( eofflag == 0 )) {
601 if ( hqx7_first == hqx7_last ) {
602 if ( hqx7_fill( hqx7_buf ) == 0 ) {
610 while (( hqx7i < 4 ) && ( hqx7_first < hqx7_last )) {
611 hqx7[ hqx7i ] = hqxlookup[ *hqx7_first ];
612 switch ( hqx7[ hqx7i ] ) {
614 if (( prev_hqx7 == 0xFC ) || ( prev_hqx7 == 0xFE )) {
621 while ( hqx7i < 4 ) {
626 prev_hqx7 = hqx7[ hqx7i ];
627 if ( skip_junk( OTHER ) < 0 ) {
628 fprintf( stderr, "\n" );
630 while ( hqx7i < 4 ) {
631 hqx7[ hqx7i++ ] = 0; }
635 prev_hqx7 = hqx7[ hqx7i++ ];
642 hqx8[ 0 ] = (( hqx7[ 0 ] << 2 ) | ( hqx7[ 1 ] >> 4 ));
643 hqx8[ 1 ] = (( hqx7[ 1 ] << 4 ) | ( hqx7[ 2 ] >> 2 ));
644 hqx8[ 2 ] = (( hqx7[ 2 ] << 6 ) | ( hqx7[ 3 ] ));
649 while (( hqx8i < 3 ) && ( out_first < out_last )) {
652 putc( hqx8i, rawhex );
653 putc( hqx8[ hqx8i ], rawhex );
656 if ( prev_hqx8 == RUNCHAR ) {
657 if ( hqx8[ hqx8i ] == 0 ) {
658 *out_first = prev_hqx8;
660 putc( *out_first, expandhex );
662 prev_out = prev_hqx8;
665 while (( out_first < out_last ) && ( hqx8[ hqx8i ] > 1 )) {
666 *out_first = prev_out;
668 putc( *out_first, expandhex );
673 if ( hqx8[ hqx8i ] < 2 ) {
674 prev_hqx8 = hqx8[ hqx8i ];
680 prev_hqx8 = hqx8[ hqx8i ];
681 if ( prev_hqx8 != RUNCHAR ) {
682 *out_first = prev_hqx8;
684 putc( *out_first, expandhex );
686 prev_out = prev_hqx8;
694 return( out_first - outbuf );