6 #endif /* HAVE_CONFIG_H */
11 #include <sys/param.h>
22 #include <netinet/in.h>
24 #include <atalk/adouble.h>
25 #include <netatalk/endian.h>
34 /* String used to indicate standard input instead of a disk
35 file. Should be a string not normally used for a file
46 /* Looking for the first or any other line of a binhex file
51 /* This is the binhex run length encoding character
55 /* These are field sizes in bytes of various pieces of the
64 #define BHH_HEADSIZ 21
67 FILE *rawhex, *expandhex;
68 #endif /* HEXOUTPUT */
70 static struct hqx_file_data {
71 u_int32_t forklen[ NUMFORKS ];
72 u_short forkcrc[ NUMFORKS ];
73 char path[ MAXPATHLEN + 1];
78 extern char *forkname[];
79 static u_char hqx7_buf[8192];
80 static u_char *hqx7_first;
81 static u_char *hqx7_last;
82 static int first_flag;
85 hqx_open must be called first. pass it a filename that is supposed
86 to contain a binhqx file. an hqx struct will be allocated and
87 somewhat initialized; hqx_fd is set. skip_junk is called from
88 here; skip_junk leaves hqx7_first and hqx7_last set.
91 int hqx_open(char *hqxfile, int flags, struct FHeader *fh, int options)
96 fprintf( stderr, "megatron: entering hqx_open\n" );
98 select_charset( options);
99 if ( flags == O_RDONLY ) {
102 rawhex = fopen( "rawhex.unhex", "w" );
103 expandhex = fopen( "expandhex.unhex", "w" );
104 #endif /* HEXOUTPUT */
108 if ( strcmp( hqxfile, STDIN ) == 0 ) {
109 hqx.filed = fileno( stdin );
110 } else if (( hqx.filed = open( hqxfile, O_RDONLY )) < 0 ) {
115 if ( skip_junk( FIRST ) == 0 ) {
116 if ( hqx_header_read( fh ) == 0 ) {
120 pos = lseek( hqx.filed, 0, SEEK_CUR );
121 fprintf( stderr, "megatron: current position is %ld\n", pos );
127 fprintf( stderr, "%s\n", hqxfile );
130 maxlen = sizeof( hqx.path ) -1;
131 strncpy( hqx.path, fh->name, maxlen );
132 strncpy( hqx.path, mtoupath( hqx.path ), maxlen );
133 strncat( hqx.path, ".hqx", maxlen - strlen( hqx.path ));
134 if (( hqx.filed = open( hqx.path, flags, 0666 )) < 0 ) {
138 if ( hqx_header_write( fh ) != 0 ) {
140 fprintf( stderr, "%s\n", hqx.path );
148 * hqx_close must be called before a second file can be opened using
149 * hqx_open. Upon successful completion, a value of 0 is returned.
150 * Otherwise, a value of -1 is returned.
153 int hqx_close(int keepflag)
155 if ( keepflag == KEEP ) {
156 return( close( hqx.filed ));
157 } else if ( keepflag == TRASH ) {
158 if (( strcmp( hqx.path, STDIN ) != 0 ) && ( unlink( hqx.path ) < 0 )) {
166 * hqx_read is called until it returns zero for each fork. when it is
167 * and finds that there is zero left to give, it reads in and compares
168 * the crc with the calculated one, and returns zero if all is well.
169 * it returns negative is the crc was bad or if has been called too many
170 * times for the same fork. hqx_read must be called enough times to
171 * return zero and no more than that.
174 ssize_t hqx_read(int fork, char *buffer, size_t length)
183 pos = lseek( hqx.filed, 0, SEEK_CUR );
184 fprintf( stderr, "hqx_read: current position is %ld\n", pos );
186 fprintf( stderr, "hqx_read: fork is %s\n", forkname[ fork ] );
187 fprintf( stderr, "hqx_read: remaining length is %d\n", hqx.forklen[fork] );
188 #endif /* DEBUG >= 3 */
190 if (hqx.forklen[fork] > 0x7FFFFFFF) {
191 fprintf(stderr, "This should never happen, dude!, fork length == %u\n", hqx.forklen[fork]);
195 if ( hqx.forklen[ fork ] == 0 ) {
196 cc = hqx_7tobin( (char *)&storedcrc, sizeof( storedcrc ));
197 if ( cc == sizeof( storedcrc )) {
198 storedcrc = ntohs ( storedcrc );
200 fprintf( stderr, "hqx_read: storedcrc\t\t%x\n", storedcrc );
201 fprintf( stderr, "hqx_read: observed crc\t\t%x\n\n", hqx.forkcrc[fork] );
202 #endif /* DEBUG >= 4 */
203 if ( storedcrc == hqx.forkcrc[ fork ] ) {
206 fprintf( stderr, "hqx_read: Bad %s fork crc, dude\n",
212 if ( hqx.forklen[ fork ] < length ) {
213 readlen = hqx.forklen[ fork ];
218 fprintf( stderr, "hqx_read: readlen is %d\n", readlen );
219 #endif /* DEBUG >= 3 */
221 cc = hqx_7tobin( buffer, readlen );
223 hqx.forkcrc[ fork ] =
224 updcrc( hqx.forkcrc[ fork ], (u_char *)buffer, cc );
225 hqx.forklen[ fork ] -= cc;
228 fprintf( stderr, "hqx_read: chars read is %d\n", cc );
229 #endif /* DEBUG >= 3 */
234 * hqx_header_read is called by hqx_open, and before any information can
235 * read from the hqx_header substruct. it must be called before any
236 * of the bytes of the other two forks can be read, as well.
237 * returns a negative number if it was unable to pull enough information
238 * to fill the hqx_header fields.
241 int hqx_header_read(struct FHeader *fh)
243 char *headerbuf, *headerptr;
244 u_int32_t time_seconds;
251 headerfork = open( "headerfork", O_WRONLY|O_CREAT, 0622 );
252 #endif /* HEXOUTPUT */
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 ));
266 #endif /* HEXOUTPUT */
269 (char *)malloc( (unsigned int)( namelen + BHH_HEADSIZ ))) == NULL ) {
272 if ( hqx_7tobin( headerbuf, ( namelen + BHH_HEADSIZ )) == 0 ) {
274 fprintf( stderr, "Premature end of file :" );
277 headerptr = headerbuf;
278 hqx.headercrc = updcrc( hqx.headercrc,
279 (u_char *)headerbuf, ( namelen + BHH_HEADSIZ - BHH_CRCSIZ ));
282 write( headerfork, headerbuf, ( namelen + BHH_HEADSIZ ));
283 #endif /* HEXOUTPUT */
286 * stuff from the hqx file header
289 memcpy( fh->name, headerptr, (int)namelen );
290 headerptr += namelen;
291 headerptr += BHH_VERSION;
292 memcpy(&fh->finder_info, headerptr, BHH_TCSIZ );
293 headerptr += BHH_TCSIZ;
294 memcpy(&fh->finder_info.fdFlags, headerptr, BHH_FLAGSIZ );
295 fh->finder_info.fdFlags = fh->finder_info.fdFlags & mask;
296 headerptr += BHH_FLAGSIZ;
297 memcpy(&fh->forklen[ DATA ], headerptr, BHH_DATASIZ );
298 hqx.forklen[ DATA ] = ntohl( fh->forklen[ DATA ] );
299 headerptr += BHH_DATASIZ;
300 memcpy( &fh->forklen[ RESOURCE ], headerptr, BHH_RESSIZ );
301 hqx.forklen[ RESOURCE ] = ntohl( fh->forklen[ RESOURCE ] );
302 headerptr += BHH_RESSIZ;
303 memcpy(&header_crc, headerptr, BHH_CRCSIZ );
304 headerptr += BHH_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" );
337 #endif /* DEBUG >= 5 */
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 int hqx_header_write(struct FHeader *fh _U_)
380 * hqx7_fill is called from skip_junk and hqx_7tobin. it pulls from the
381 * binhqx file into the hqx7 buffer. returns number of bytes read
382 * or a zero for end of file.
383 * it sets the pointers to the hqx7 buffer up to point to the valid data.
386 ssize_t hqx7_fill(u_char *hqx7_ptr)
391 cs = hqx7_ptr - hqx7_buf;
392 if ( cs >= sizeof( hqx7_buf )) return( -1 );
393 hqx7_first = hqx7_ptr;
394 cc = read( hqx.filed, (char *)hqx7_first, ( sizeof( hqx7_buf ) - cs ));
399 hqx7_last = ( hqx7_first + cc );
404 char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
405 0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
407 Input characters are translated to a number between 0 and 63 by direct
408 array lookup. 0xFF signals a bad character. 0xFE is signals a legal
409 character that should be skipped, namely '\n', '\r'. 0xFD signals ':'.
410 0xFC signals a whitespace character.
413 static const u_char hqxlookup[] = {
414 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
415 0xFF, 0xFC, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
416 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
417 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
418 0xFC, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
419 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
420 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
421 0x14, 0x15, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
422 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
423 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
424 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
425 0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
426 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
427 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
428 0x3D, 0x3E, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
429 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
430 0xFF, 0xFF, 0xFF, 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,
449 * skip_junk is called from hqx_open. it skips over junk in the file until
450 * it comes to a line containing a valid first line of binhqx encoded file.
451 * returns a 0 for success, negative if it never finds good data.
452 * pass a FIRST when looking for the first valid binhex line, a value of
453 * OTHER when looking for any subsequent line.
456 int skip_junk(int line)
464 if ( line == FIRST ) {
465 if ( hqx7_fill( hqx7_buf ) <= 0 ) {
466 fprintf( stderr, "Premature end of file :" );
471 while ( found == NOWAY ) {
472 if ( line == FIRST ) {
473 if ( *hqx7_first == ':' ) {
477 while (( stopflag == NOWAY ) &&
478 ( nc < ( hqx7_last - hqx7_first ))) {
479 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
484 stopflag = SURETHANG;
491 if (( nc > 30 ) && ( nc < 64 ) &&
492 (( c == 0xFE ) || ( c == 0xFD ))) found = SURETHANG;
497 if (( prevchar = hqxlookup[ *hqx7_first ] ) == 0xFE ) {
501 while (( stopflag == NOWAY ) &&
502 ( nc < ( hqx7_last - hqx7_first ))) {
503 switch ( c = hqxlookup[ hqx7_first[ nc ]] ) {
506 if (( prevchar == 0xFC ) || ( prevchar == 0xFE )) {
512 stopflag = SURETHANG;
522 } else if (( nc > 30 ) && ( c == 0xFE )) {
530 if (( hqx7_last - hqx7_first ) == nc ) {
531 if ( line == FIRST ) {
533 } else *hqx7_buf = '\n';
534 memcpy(hqx7_buf + 1, hqx7_first, nc );
535 hqx7_first = hqx7_buf + ( ++nc );
536 if ( hqx7_fill( hqx7_first ) <= 0 ) {
537 fprintf( stderr, "Premature end of file :" );
540 hqx7_first = hqx7_buf;
548 * hqx_7tobin is used to read the data, converted to binary. It is
549 * called by hqx_header_read to get the header information, and must be
550 * called to get the data for each fork, and the crc data for each
551 * fork. it has the same basic calling structure as unix read. the
552 * number of valid bytes read is returned. It does buffering so as to
553 * return the requested length of data every time, unless the end of
557 size_t hqx_7tobin( char *outbuf, size_t datalen)
559 static u_char hqx8[3];
561 static u_char prev_hqx8;
562 static u_char prev_out;
563 static u_char prev_hqx7;
571 fprintf( stderr, "hqx_7tobin: datalen entering %d\n", datalen );
572 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
575 if ( first_flag == 0 ) {
585 fprintf( stderr, "hqx_7tobin: hqx8i entering %d\n", hqx8i );
589 out_last = out_first + datalen;
591 while (( out_first < out_last ) && ( eofflag == 0 )) {
593 if ( hqx7_first == hqx7_last ) {
594 if ( hqx7_fill( hqx7_buf ) == 0 ) {
602 while (( hqx7i < 4 ) && ( hqx7_first < hqx7_last )) {
603 hqx7[ hqx7i ] = hqxlookup[ *hqx7_first ];
604 switch ( hqx7[ hqx7i ] ) {
606 if (( prev_hqx7 == 0xFC ) || ( prev_hqx7 == 0xFE )) {
613 while ( hqx7i < 4 ) {
618 prev_hqx7 = hqx7[ hqx7i ];
619 if ( skip_junk( OTHER ) < 0 ) {
620 fprintf( stderr, "\n" );
622 while ( hqx7i < 4 ) {
623 hqx7[ hqx7i++ ] = 0; }
627 prev_hqx7 = hqx7[ hqx7i++ ];
634 hqx8[ 0 ] = (( hqx7[ 0 ] << 2 ) | ( hqx7[ 1 ] >> 4 ));
635 hqx8[ 1 ] = (( hqx7[ 1 ] << 4 ) | ( hqx7[ 2 ] >> 2 ));
636 hqx8[ 2 ] = (( hqx7[ 2 ] << 6 ) | ( hqx7[ 3 ] ));
641 while (( hqx8i < 3 ) && ( out_first < out_last )) {
644 putc( hqx8i, rawhex );
645 putc( hqx8[ hqx8i ], rawhex );
646 #endif /* HEXOUTPUT */
648 if ( prev_hqx8 == RUNCHAR ) {
649 if ( hqx8[ hqx8i ] == 0 ) {
650 *out_first = prev_hqx8;
652 putc( *out_first, expandhex );
653 #endif /* HEXOUTPUT */
654 prev_out = prev_hqx8;
657 while (( out_first < out_last ) && ( hqx8[ hqx8i ] > 1 )) {
658 *out_first = prev_out;
660 putc( *out_first, expandhex );
661 #endif /* HEXOUTPUT */
665 if ( hqx8[ hqx8i ] < 2 ) {
666 prev_hqx8 = hqx8[ hqx8i ];
672 prev_hqx8 = hqx8[ hqx8i ];
673 if ( prev_hqx8 != RUNCHAR ) {
674 *out_first = prev_hqx8;
676 putc( *out_first, expandhex );
677 #endif /* HEXOUTPUT */
678 prev_out = prev_hqx8;
686 return( out_first - outbuf );