home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / suntar1.cpt / dehqx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-20  |  21.1 KB  |  784 lines

  1.  
  2. /*******************************************************************************\
  3.  
  4. hqx decoding module
  5.  
  6. part of suntar, ⌐1991-92 Sauro & Gabriele Speranza
  7.  
  8. This program is public domain, feel free to use it or part of it for anything
  9.  
  10. \*******************************************************************************/
  11.  
  12.  
  13. /* #include <StdFilePkg.h> */
  14.  
  15. #include <string.h>
  16.  
  17. #include "suntar.h"
  18. #include "windows.h"
  19.  
  20. #define ASM
  21.  
  22.  
  23. #define hibyte(x)        (((char *) &(x))[0])
  24. #define lobyte(x)        (((char *) &(x))[1])
  25.  
  26. short current_crc;
  27. long hqx_length;
  28. static unsigned char conv_tab[256];
  29. short show_info;
  30. unsigned int max_hqx_header;
  31. short info_file_open=0;
  32. Boolean save_info;
  33. int info_file;
  34. static Boolean EOF_reached;
  35. static int first_in_buffer=0,last_in_buffer=0;
  36. static unsigned char hqxbuf[256];
  37.  
  38. #define RUNCHAR 0x90
  39.  
  40.  
  41. void raise_hqx_error(void);
  42.  
  43.  
  44. void close_info_file()
  45. {
  46. if(info_file_open>0){
  47.     FSClose(info_file);
  48.     }
  49. info_file_open=0;
  50. }
  51.  
  52. int ci_strcmp(p1,p2)
  53. register char *p1,*p2;
  54. /* case-insensitive compare (it's not general purpose: the second string must be
  55. lowercase, and the return value is 0 if equal, 1 if not) */
  56. {
  57. register unsigned char c;
  58. while(*p2){
  59.     if(!(c=*p1++)) return 1;
  60.     if(c>='A'&&c<='Z') c+= 'a'-'A';
  61.     if(c!= *p2++) return 1;
  62.     }
  63. return *p1 != '\0';
  64. }
  65.  
  66. short is_hqx_name()
  67. {
  68. /* returns 0 if the name does not terminate by .hqx, -1 if it does but .hqx is
  69. preceded by "part" (or "p" preceded by a non-letter) followed by one or two digits, 
  70. 1 otherwise.
  71. (obviously, files broken in parts can't be extracted on the fly, and it's customary
  72. to call them contentname.part1.hqx, but we've seen also a_very_long_name.p2.hqx
  73. or long_application_name1.1p3.hqx, and startup10.hqx probably is not a part)
  74. The char comparisons are case-insensitive
  75. */
  76. register int i,l;
  77. static char p[]={'p','a','r','t'};
  78. l=strlen(tarh.name);
  79. if(l <=4 || ci_strcmp(&tarh.name[l-4],".hqx" ) ) return 0;
  80.  
  81. /* se sono qui c'era .hqx, ma se c'Å anche part devo non convertire */
  82.     
  83. if( l < 9 || tarh.name[l-5] <'0' || tarh.name[l-5] >'9' ) return 1;
  84. if(tarh.name[l-6]>='0'&&tarh.name[l-6]<='9') l--;
  85.  
  86. if(l<9) return 1;
  87. if( (tarh.name[l-6]|0x20) == 'p' && ((i=tarh.name[l-7]|0x20)<'a'||i>'z') ) return -1;
  88. for(i=0;i<4;i++)
  89.     if( (tarh.name[l-9+i]|0x20) != p[i] ) return 1;
  90. return -1;    /* il .hqx Å preceduto da part1 o part2 etc., sarebbe inutile cercare 
  91.                 di convertire */
  92. }
  93.  
  94.  
  95. void check_CRC()
  96. {
  97. /* read the stored CRC value from the BinHex file and compare it with the
  98. computed value
  99. */
  100. short calcolato,letto;
  101.  
  102.  
  103. /* per la veritê non sarebbe necessario, il CRC Å fatto in modo che se si calcola
  104. su tutti i dati, CRC compreso, il risultato deve essere 0
  105. -- really, the standard CRC (and CCITT CRC is standard) has this property: 
  106. if you don't compute it on 0 twice (remove the two calls) but compute on the 
  107. two CRC bytes (get the value of current_CRC after the read_hqx(¬_care,2) ), 
  108. then current_CRC is 0 if and only if the computation matches the stored CRC. 
  109. But doing it the same way as the originating routine is easier to understand
  110. */
  111. CalcCRC(0);
  112. CalcCRC(0);
  113.  
  114. calcolato=current_crc;
  115. read_hqx(&letto,2);
  116. /*printf("calcolato=%x,letto=%x,corrente=%x len=%ld:%d\n",calcolato,letto,current_crc,
  117.     hqx_length,last_in_buffer-first_in_buffer);*/
  118. if( calcolato!=letto ){
  119.     printf("Invalid CRC\n");
  120.     if(!ignore_errors) raise_hqx_error();
  121.     }
  122. }
  123.  
  124.  
  125.  
  126. short hqx_header()
  127. {
  128. /* read the header of a BinHex file and place all informations in a struct
  129. which follows the MacBinary format.
  130. In the file "hqx-format.txt", available in public domain archives, containing
  131. contributions by Dave Johnson and Tom Coradeschi, one can read:
  132. >The header format consists of a one byte name length, then the mac
  133. >file name, then a null.  The rest of the header is 20 bytes long,
  134. >and contains the usual file type, creator/author, file flags, data
  135. >and resource lengths, and the two byte crc value for the header.
  136.  
  137. */
  138. static char msg[]="Invalid BinHex header\n";
  139.  
  140. EOF_reached=false;
  141. /* handle all the text before the BinHex data. If there is nothing else,
  142. return immediately */
  143. FindStart();
  144.  
  145. if(!hqx_length) return -1;        /* sono giê in fondo, capita se non ho trovato l'inizio */
  146.  
  147. current_crc=0;
  148. last_in_buffer=first_in_buffer=0;
  149. read_hqx(&macbinh.nlen,1);            /* file name length */
  150. if(macbinh.nlen==0 || macbinh.nlen>63){
  151.     printf(msg);
  152.     raise_hqx_error();
  153.     }
  154. read_hqx(&macbinh.name,macbinh.nlen);    /* rest of file name */
  155.  
  156. if(read_hqx(&macbinh.zero,1),macbinh.zero!=0 && !ignore_errors){    /* a zero byte */
  157.     printf(msg);
  158.     raise_hqx_error();
  159.     }
  160.  
  161. read_hqx(&macbinh.finfo,10);    /* type, creator, Finder flags etc. */
  162. macbinh.protected=0;
  163. macbinh.zero=0;
  164. read_hqx(&macbinh.dflen,8);        /* data fork & resource fork lengths (two long ints) */
  165. /*printf("sizes=%lx %lx\n",macbinh.dflen,macbinh.rflen);*/
  166.  
  167. /* queste informazioni non c'Å bisogno di settarle, basta modificare la routine
  168. che chiama PBSetFInfo in modo che rispetti i valori correnti :
  169. -- the creation and modification dates are missing, but set_binhex will 
  170.     fill those fields
  171.  
  172. *(long*)&macbinh.finfo.fdLocation = 0;
  173. macbinh.finfo.fdFldr=0;
  174. GetDateTime (&macbinh.cdate);
  175. macbinh.mdate=macbinh.cdate;
  176. */
  177.  
  178. check_CRC();
  179. return 0;
  180.  
  181. }
  182.  
  183.  
  184.  
  185. /***************** findstart *********************/
  186.  
  187. void FindStart ()
  188. {
  189. /* routine ispirata a quella (in Pascal) di Peter Lewis, ma perfezionata
  190. -- This routine is vaguely inspired to the Pascal procedure by
  191. Peter Lewis (deHQX.p), but it does not fail if the start string was modified
  192. or deleted from the file
  193. */
  194.  
  195. OSErr oe;
  196. int pos,stat;
  197. unsigned int timeout=file_aperto==ff_binhex?65535:max_hqx_header;
  198. static char startstr[] = "(This file must be converted with BinHex 4.0)";
  199. int oldpos=0;
  200. register int i,b;
  201. Boolean flush_needed;
  202. extern Boolean all_listonly;
  203.  
  204. /* per evitare di scandire centinaia di Kbytes per nulla, ho un "timeout" (20 settori) 
  205. e la possibilitê di gestire anche files in cui la scritta di cui sopra Å stata tolta, 
  206. col che c'Å solo un ":" seguito da uno dei primi codici della stringa hqx (Å la 
  207. lunghezza del nome, in teoria max 63 ma in pratica max 31, diviso per 4 per prendere 
  208. solo 6 bit...) i quali codici sono tutti cose strane da stare dopo un : 
  209. -- a ':' at the start of the line must be followed by one of the first codes
  210. in the hqx decoding string (the file name length can't be longer than 12*4+3 =51:
  211. it's not the "official" limit of 63, but ":0" could be meaningful...
  212. The routine is much more complex than it should be due to the explicit 
  213. handling of buffering with both the file and console output 
  214. */
  215.  
  216. show_info = SHOWINFO;
  217. save_info = SAVEINFO;
  218. if(show_info) disable_autoflush();
  219. stat=0;
  220. pos = 0;
  221. do{
  222.     b = get_hqx_byte(&flush_needed);
  223.  
  224. /* controllo nel caso manchi la stringa ma ci siano i dati BinHex */
  225.     if(b==LF||b==CR||b=='\f')
  226.         stat=0;
  227.     else if(b==':')
  228.         stat++;
  229.     else if(stat==1 && conv_tab[b]<=12){    /*un ':' a inizio riga seguito da...*/
  230.         unget_char();
  231.         flush_hqx_header(0);
  232.         if( show_info) {
  233.             start_of_line();
  234.             enable_autoflush();
  235.             }
  236.         close_info_file();
  237.         return;
  238.         }
  239.     else if(stat==0 && (b==' '||b=='\t') )
  240.         ;
  241.     else
  242.         stat=2;
  243. /* controllo per il caso non ci siano nÄ stringa nÄ dati BinHex */
  244.     if(--timeout==0){
  245.         char buffer[512];
  246.         start_of_line();
  247.         printf(in_Italia?"Non ho trovato dati BinHex nei primi %u bytes\n":
  248.             "BinHex header not found within %u bytes\n",
  249.             file_aperto==ff_binhex?(int)65535:max_hqx_header);
  250.         if(show_info) enable_autoflush();
  251.  
  252.         if(! save_info)
  253.             raise_hqx_error();
  254.         else{
  255.             flush_hqx_header(0);        /* ora passo in modalita' salvataggio 
  256.                             normale, vorrê dire che mando tutto nel .info 
  257.                             -- BinHex data not found => since the .info file
  258.                             contains a copy of all what was read, continue
  259.                             to fill it, without any further search */
  260.             while(hqx_length>0){
  261.                 if(hqx_length>=512L) i=512; else i= (int)hqx_length;
  262.                 hqx_length -= i;
  263.                 if(readblock(buffer,i)!=0)
  264.                     error_message_1("Disk read error %d\n",err_code);
  265.                 for(b=0;b<512;b++)
  266.                     if(buffer[b]==LF) buffer[b]=CR;
  267.                 if(mac_fwrite(buffer,i,info_file)<0)
  268.                     error_message("File write error!\n");
  269.                 }
  270.             }
  271.         close_info_file();
  272.         return;
  273.         }
  274. /* controllo presenza stringa */
  275.     if (b == startstr[pos])
  276.         pos ++;
  277.     else
  278.         pos = 0;
  279. /* copia dei caratteri sulla console e/o file .info */
  280.     if(flush_needed || pos==sizeof(startstr)-1){
  281.         if(save_info && oldpos!=0 && pos!=sizeof(startstr)-1)
  282.             mac_fwrite(startstr,oldpos,info_file);    /* Å poco pulito farlo cosô, fidandosi
  283.                 che il file Å aperto e contiene quello che deve contenere...*/
  284.  
  285.         if(show_info && oldpos!=0 && pos!=sizeof(startstr)-1){
  286.             for(i=0;i<oldpos;i++)
  287.                 put_char(startstr[i]);    /* la volta prima avevo erroneamente omesso
  288.                             dei caratteri ritenendo fossero parte della start string
  289.                 -- when the buffer had to be flushed, I could have seen a part 
  290.                 of the start string: I didn't save it, but if I'm here than I
  291.                 discovered that it was NOT the start string, hence those chars
  292.                 had to be written out: for the console, do it here, for the .info
  293.                 file it's flush_hqx_header which does that */
  294.             }
  295.         oldpos=pos;
  296.         flush_hqx_header(pos);
  297.         }
  298.  
  299.     }
  300. while( pos < sizeof(startstr)-1);
  301.  
  302. close_info_file();
  303. if(show_info){
  304.     start_of_line();
  305.     enable_autoflush();
  306.     }
  307.  
  308. do{
  309.     b = get_hqx_byte(&flush_needed);
  310.     }
  311. while (b!=':');
  312.  
  313. }
  314.  
  315.  
  316.  
  317. /*
  318. io uso tre buffer: quello di uscita Å il solito buffer, quello di ingresso 
  319. contiene il blocco letto dal disco; in pi¥, le conversioni sono fatte a
  320. gruppi di 4 bytes, col che ho un buffer intermedio che contiene solo ...
  321. -- The BinHex conversion is performed in two steps, by two routines
  322. each having its own input buffer
  323. */
  324.  
  325. void init_hqx_tab()
  326. /* initialize the conversion table: need be called only once */
  327. {
  328. static unsigned char hqxchars[]=
  329.  "!\"#$%&\'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  330. register int i;
  331. for( i= 0 ;i<=255; i++)
  332.     conv_tab[i] = 255;
  333. for (i = 0;i<64;i++)
  334.     conv_tab[hqxchars[i]]=i;
  335. conv_tab[LF]=conv_tab[CR]=conv_tab[' ']=conv_tab['\t']=conv_tab['\f']= 254;
  336. }
  337.  
  338.  
  339.  
  340. void read_hqx(destination,nbytes)
  341.  
  342. /* in suntar 1.2, this routine was changed, optimizing for speed: the 
  343. loop present in the callers was moved here, so that register variables
  344. may hold their values for a while, and are not swapped out of the register
  345. after being used just a couple of times */
  346.  
  347. register char *destination;
  348. int nbytes;
  349. /* last conversion stage: it handles the RLL encoding in the BinHex format.
  350. From the file "hqx-format.txt":
  351.  
  352. >There is some run length encoding, where the character to be repeated
  353. >is followed by a 0x90 byte then the repeat count.  For example, ff9004
  354. >means repeat 0xff 4 times.  The special case of a repeat count of zero
  355. >means it's not a run, but a literal 0x90.  2b9000 => 2b90.
  356.  
  357. >*** Note: the 9000 can be followed by a run, which means to repeat the
  358. >0x90 (not the character previous to that).  That is, 2090009003 means
  359. >a 0x20 followed by 3 0x90's.
  360. */
  361.  
  362. {
  363. register unsigned char b;
  364.  
  365. register unsigned char *first=&hqxbuf[first_in_buffer];
  366. register int k=last_in_buffer-first_in_buffer;
  367.  
  368. while(nbytes--){
  369.     if( k < 4 ){
  370.         /* buffer quasi vuoto: riporta quello che resta in testa e riempi di nuovo
  371.         -- refill the buffer by shifting what remains and calling
  372.         read_3_hqx until the buffer is full or the hqx data is over
  373.         */
  374.         mcopy(hqxbuf,first,k);
  375.         first=hqxbuf;
  376.         k += read_3_hqx(&hqxbuf[k],sizeof(hqxbuf)-k);
  377.         last_in_buffer =k;
  378.         if( k<=0 ){
  379.             beep_in_foreground();
  380.             start_of_line();
  381.             printf("hqx: EOF reached\n");
  382.             raise_hqx_error();
  383.             }
  384.         }
  385.     /* sembra troppo semplice per quello che deve fare, ma ho studiato tutti i casi,
  386.     compresi i run di RUNCHAR e la coppia di RUNCHAR, scritto che si deve fare e fatto
  387.     il merge delle azioni comuni fra pi¥ rami, e questo Å il risultato
  388.     -- I decrement the run length count directly in the input buffer, without
  389.     extracting the RLL code from the buffer until the count goes to 0.
  390.     OK, it's not immediately clear that these instructions work: but I considered
  391.     all possible cases and did a flow graph of the resulting operations, than began
  392.     to merge equal boxes at the end of different paths: I've got a lot of merging
  393.     and the result is this very simple set of instructions */
  394.     b=*first;    
  395.     if(b==RUNCHAR){    /* and first[1] surely 0 */
  396.         if(k <4 || first[2]!=RUNCHAR || !first[3] ){
  397.                 first += 2; k -=2;
  398.                 }
  399.         else
  400.             if ( --first[3] <=1 ) {
  401.                 /* see below */
  402.                 if(first[3]==0){
  403.                     first += 4; k -= 4;
  404.                     }
  405.                 else{
  406.                     first+=2; k-=2;
  407.                     first[1]=0;
  408.                     }
  409.                 }
  410.         }
  411.     else{
  412.         if (k <3 || first[1]!=RUNCHAR || !first[2]){
  413.             first++; k--;
  414.             }
  415.         else{
  416. /* run length may be repeated, for example A4 90 FF 90 FF 90 0A means A4 is 
  417. repeated 520 times. Unfortunately, suntar 1.1 did not handle those cases correctly */
  418.             if(  --first[2] <=1 ){
  419.                 if(first[2]==0){
  420.                     first+=3; k-=3;
  421.                     }
  422.                 else{    /* must copy the char to be repeated so that if there is
  423.                         a further run length, it appears to be applied to it; it's
  424.                         easier to exit from the decrement state when the count is 1
  425.                         and copy anyway than exit when it's 0 and copy only if there
  426.                         is a further run length */
  427.                     first+=2; k-=2;
  428.                     *first=b;
  429.                     }
  430.                 }
  431.             }
  432.         }
  433.  
  434.     *destination++ = b;
  435.  
  436. #ifndef ASM
  437.     CalcCRC(b);
  438. #else
  439.     /* save parameter passing + function call */
  440.     asm{
  441.  
  442.         move.w    current_crc,d0
  443.  
  444.         move.w    #7,d2
  445.         move.w    #0x1021,d1    ; CRC CCITT
  446.     loop:
  447.         lsl.b    #1,b
  448.         roxl.w    #1,d0
  449.         bcc.s    @noxor
  450.         eor.w    d1,d0
  451.     noxor:
  452.         dbra    d2,@loop
  453.  
  454.         move.w    d0,current_crc
  455.         }
  456. #endif
  457.  
  458.  
  459.     }
  460. first_in_buffer = first - hqxbuf;
  461. }
  462.  
  463.  
  464. static char UNEXP_EOF[]="End of BinHex file unexpectedly reached\n";
  465.  
  466. #define FAST_GET_HQX_BYTE(b)    \
  467. if(!more_in_bytes)                \
  468.     b=(unsigned char)get_hqx_byte(&dummy);    \
  469. else{                            \
  470.     if((--hqx_length)<0){        \
  471.         printf(UNEXP_EOF);        \
  472.         raise_hqx_error();        \
  473.         }                        \
  474.     b= (unsigned char)disk_buffer[511-(--more_in_bytes)];\
  475.     }
  476.  
  477.  
  478.  
  479.  
  480. extern int more_in_bytes;
  481.  
  482.  
  483. int read_3_hqx(obuf,maxsize)
  484. /* this one too was optimazed by moving here the loop which
  485. was in the caller */
  486.  
  487. register unsigned char *obuf;
  488. register int maxsize;
  489. {
  490. /* read four BinHex characters and convert them to three bytes
  491. From the file "hqx-format.txt":
  492. >The first and last characters are each a ':'.  After the first ':',
  493. >the rest of the file is just string of 6 bit encoded characters.
  494. >All newlines and carriage returns are to be ignored.
  495. That is, data is sliced in 6-bit pieces, and 3 bytes (24 bits) yield 4
  496. pieces, each encoded by a printable ASCII char (0='!' etc., see the
  497. conversion table)
  498. */
  499.  
  500. Boolean dummy;
  501. unsigned char ibuf[4];
  502. register int i,b;
  503. register int nbytes;
  504. register unsigned char *pti;
  505. static char msg[]="Error: not a BinHex character (dec %d)\n";
  506.  
  507. nbytes=0;
  508. maxsize -= 3;
  509.  
  510. while(maxsize>=0 && !EOF_reached){
  511.  
  512.     nbytes += 3;
  513.     pti=ibuf;
  514.     for(i=0;i<4;i++,pti++){
  515.         do{
  516.             FAST_GET_HQX_BYTE(b)
  517.             }
  518.         while((*pti=conv_tab[b])==(unsigned char)254 );
  519.             /* I ignore spaces too: hqx-format.txt does not tell about them,
  520.             but we happened to download a file which did have spaces,
  521.             and neither Stuffit nor Compact Pro succeeded to extract it,
  522.             only Peter Lewis' DeHQX did the job. Now, suntar too does extract
  523.             that file */
  524.         if( *pti==(unsigned char)255){
  525.             if(b==':'){
  526.                 EOF_reached=true;
  527.                 nbytes += ((i+i+i)>>2)-3;    /* i*6/8 -3 */
  528.                 for(;i<4;i++)
  529.                     ibuf[i]=0;
  530.                 break;
  531.                 }
  532.              printf(msg,b);
  533.              if(!ignore_errors)
  534.                   raise_hqx_error();
  535.               }
  536.           }
  537. /*printf("<%x %x %x %x>",ibuf[0],ibuf[1],ibuf[2],ibuf[3]);*/
  538. #ifndef ASM
  539.     *obuf++ = ((ibuf[0] << 2) | (ibuf[1] >> 4));    /* these three instructions */
  540.     *obuf++ = ((ibuf[1] << 4) | (ibuf[2] >> 2));     /* are from Dave Johnson's xbin.c */
  541.     *obuf++ = ((ibuf[2] << 6) | ibuf[3]);            /* (for UNIX machines) */
  542. #else
  543. /* no speed gain, but since I've written and tested it, it's better to use it... */
  544.     asm{
  545.         lea        ibuf,a0
  546.         move.b    (a0)+,d0
  547.         lsl.b    #2,d0
  548.         move.b    (a0)+,d1
  549.         move.b    d1,d2
  550.         lsr.b    #4,d1
  551.         or.b    d1,d0
  552.         move.b    d0,(obuf)+
  553.         lsl.b    #4,d2
  554.         move.b    (a0)+,d1
  555.         move.b    d1,d0
  556.         lsr.b    #2,d1
  557.         or.b    d1,d2
  558.         move.b    d2,(obuf)+
  559.         lsl.b    #6,d0
  560.         or.b    (a0),d0
  561.         move.b    d0,(obuf)+
  562.         }
  563. #endif
  564.  
  565. /*printf("{%x %x %x}\n",obuf[0],obuf[1],ibuf[2]);*/
  566.     maxsize -= 3;
  567.     }
  568. return nbytes;
  569. }
  570.  
  571.  
  572. unsigned char get_hqx_byte(flush_needed)
  573. /* I could implement it by calling readblock, but the hqx decoding has already
  574. so much overhead for each byte that I thought that any instructions saving
  575. was welcome, hence I copied the body of readblock deleting instructions which
  576. are useless when reading one byte at a time
  577. */
  578. Boolean *flush_needed;
  579. {
  580. if((--hqx_length)<0){
  581.     beep_in_foreground();
  582.     start_of_line();
  583.     printf(UNEXP_EOF);
  584.     raise_hqx_error();
  585.     }
  586.  
  587. if(more_in_bytes==0){
  588.     *flush_needed=false;
  589. /* le stesse cose che fa readblock... */
  590.     if(bar_archive)
  591.         bar_check_floppy_swap(0);
  592.     else
  593.         tar_check_floppy_swap(0);
  594.  
  595.     leggi_settore(sect_n,&disk_buffer);
  596.     if(check_error())raise_error();
  597.     check_events();
  598.     more_in_bytes=511;
  599.     sect_n++;
  600.     settori_passati++;
  601.     }
  602. else
  603.     *flush_needed= !--more_in_bytes;
  604. return disk_buffer[511-more_in_bytes];
  605. }
  606.  
  607.  
  608. void open_info_file()
  609. /* opens the .info file: that includes building its name... */
  610. {
  611. char name_buffer[102];
  612. register int i,l;
  613. char *hqx_name=bar_archive ? ((barh_type*)ultimo_header)->name : 
  614.     ((struct tarh_type*)ultimo_header)->name;
  615. extern OSType filecreator,filetype;
  616. extern Boolean devo_chiudere_out;
  617. extern IOParam pb;
  618.  
  619. l=strlen(hqx_name);
  620. strcpy(name_buffer,hqx_name);
  621.  
  622. if(l>4 && !ci_strcmp(&name_buffer[l-4],".hqx")){
  623.     for(i=l-1;i>=0 && hqx_name[i]!='/';i--)
  624.         ;
  625.     /* ora i Å -1 o punta ad un '/', quindi la lunghezza del nome Å : */
  626.     i=l-i+1;
  627.     strcpy(&name_buffer[l-3], i==31 ? "inf" : "info");
  628.     }
  629. else    /* if opened by Open File, it may not contain .hqx */
  630.     strcat(name_buffer,".info");
  631. unix_to_mac(name_buffer);
  632.  
  633. filecreator=text_creator;
  634. filetype='TEXT';
  635. if(create_file(name_buffer,fsWrPerm,false)==0){
  636.     /* non posso controllare che ci stia non sapendo le dimensioni... */
  637.     devo_chiudere_out=false;
  638.     info_file=pb.ioRefNum;
  639.     info_file_open=1;
  640.     }
  641. else
  642.     info_file_open=-1;    /* duplicate name + cancel: don't create an info file ! */
  643. }
  644.  
  645.  
  646. void flush_hqx_header(pos)
  647. /* it's rather complex: it must write data to the console and the .info
  648. file, but both of them may be disabled.
  649. Furthermore, it's called when the buffer is officially empty, but obviously 
  650. its bytes still contain the characters which FindStart has read and discarded
  651. since they were not the start of the BinHex data
  652. */
  653. {
  654. /* attenzione, faccio affidamento sul fatto che nel buffer ci restano i bytes letti,
  655. e che grazie all'ubbidienza al parametro flush_needed della routine precedente 
  656. quelli non ancora salvati partono all'offset 0 */
  657.  
  658. register int i,j;
  659. register char last_char;
  660. if( ! save_info && ! show_info ) return;
  661.  
  662. j=512-more_in_bytes-pos;
  663. if(!j) return;
  664. if(show_info==1 && j>100)
  665.     printf("=============== hqx info ===============\n\n");    /* la prima volta */
  666. if(show_info!=0){
  667.     show_info++;
  668.     disable_autoflush();    /* in alcuni casi un messaggio (nuovo disco...) puÿ averlo
  669.                             abilitato */
  670.     }
  671.  
  672. for(i=0;i<j;i++){    /* butto fuori il contenuto del buffer, ma 
  673.                         togliendo un eventuale inizio della start string
  674.                     -- pos!=0 means that the last pos chars might be part of the
  675.                     start string, I must not write them
  676.                     */
  677.     last_char=disk_buffer[i];
  678.     if(last_char==LF)
  679.         disk_buffer[i]=last_char=CR; /* per la console non serve, per il file sô
  680.                     -- put_char already does the conversion, but mac_fwrite does not
  681.                     */
  682.     if(show_info) put_char(last_char);
  683.     if(last_char==CR && show_info>=4 && more_in_bytes==0){
  684.         printf(in_Italia?"... (testata lunga, non mostrata per intero)\n\n\n":
  685.         "... (long header, further lines are not shown)\n\n\n");
  686.         enable_autoflush();
  687.         show_info=0;
  688.         }
  689.     }
  690.  
  691. if( save_info && j>0){
  692.     if(!info_file_open) open_info_file();    /* the info file is opened on the fly
  693.             here, since FindStart did not open it: if no text precedes the
  694.             BinHex data, the info file is not created */
  695.     if(info_file_open>0)
  696.         if(mac_fwrite(disk_buffer,j,info_file)<0){
  697.             beep_in_foreground();
  698.             error_message("File write error !\n");
  699.             }
  700.     }
  701. }
  702.  
  703. void hqx_end_of_file()
  704. {
  705. hqx_length -= more_in_bytes;
  706. more_in_bytes=0;
  707. if(hqx_length>0)
  708.     sect_n+= (hqx_length+511) >>9;
  709. hqx_length=0;
  710. }
  711.  
  712. static void raise_hqx_error()
  713. /* handles the hqx decoding error by skipping the rest of the file and closing
  714. the open files so that untar_hqx will be able to return regularly, and the
  715. extraction or list will continue with next file */
  716. {
  717. close_or_del_out_file();
  718. close_info_file();
  719. enable_autoflush();
  720.  
  721. hqx_end_of_file();
  722.  
  723. if(fase==reading_disk&&file_aperto!=ff_binhex || fase==selected_reading || fase==hack_listing){
  724.     if(! (fase==reading_disk&&listonly || fase==hack_listing) ){
  725.         one_empty_line();
  726.         printf(in_Italia?"****** Estrazione BinHex interrotta":
  727.         "****** BinHex extraction was aborted");
  728.         printf(" ******\n\n");
  729.         }
  730.     longjmp(main_loop,-2);
  731.     }
  732. else
  733.     longjmp(main_loop,-1);
  734.  
  735. }
  736.  
  737.  
  738. /* assembly language is faster: since you must repeat the body of the loop 
  739. for each BIT (not byte !) of the file, a fast CRC routine is essential if
  740. your BinHex routine must not been very slow... */
  741. #ifdef ASM
  742.  
  743. void CalcCRC(current_byte)
  744. char current_byte;
  745. /* from calcCRC.a in the deHQX source code by Peter Lewis, adapting
  746. it to the C parameter passing conventions and the Think-C half-assembly-half-C
  747. syntax
  748. */
  749. {
  750. asm{
  751.  
  752.     move.w    current_crc,d0
  753.     move.b    current_byte,d1
  754.     
  755.     move.w    #7,d2
  756. loop:
  757.     lsl.b    #1,d1
  758.     roxl.w    #1,d0
  759.     bcc.s    @noxor
  760.     eor.w    #0x1021,d0    ; CRC CCITT
  761. noxor:
  762.     dbra    d2,@loop
  763.     move.w    d0,current_crc
  764.     }
  765. }
  766.  
  767. #else
  768.  
  769. void CalcCRC (v)
  770. {
  771. int temp;
  772. register int     i;
  773.  
  774.     for (i = 1;i<=8;i++){
  775.         temp = current_crc&0x8000;
  776.         current_crc = (current_crc<<1) | (v>>7)&1 ;
  777.         if( temp )
  778.             current_crc ^= 0x1021;
  779.         v <<= 1;
  780.         }
  781. }
  782. #endif
  783.  
  784.