Back to index

lightning-sunbird  0.9+nobinonly
nsMsgBinHex.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org Code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /*
00039 *
00040 *      Mac_BinHex.c
00041 *      ------------
00042 *
00043 *      The decode and encode for BinHex 4.0
00044 *
00045 *             09sep95       mym           Created
00046 *             18sep95       mym           Added the functions to do encoding from 
00047 *                                         the input stream instead of file.
00048 */
00049 
00050 #include "nscore.h"
00051 #include "msgCore.h"
00052 #include "nsCRT.h"
00053 
00054 #include "nsMsgAppleDouble.h"
00055 #include "nsMsgAppleCodes.h"
00056 #include "nsMsgBinHex.h"
00057 
00058 /* for XP_GetString() */
00059 #include "xpgetstr.h"
00060 
00061 #ifdef XP_MAC
00062 #include <StandardFile.h>
00063 #pragma warn_unusedarg off
00064 #endif
00065 
00066 static char BinHexTable[64] = 
00067 {
00068        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
00069        0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x30, 0x31, 0x32,
00070        0x33, 0x34, 0x35, 0x36, 0x38, 0x39, 0x40, 0x41,
00071        0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
00072        0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x50, 0x51, 0x52,
00073        0x53, 0x54, 0x55, 0x56, 0x58, 0x59, 0x5a, 0x5b,
00074        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x68,
00075        0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x70, 0x71, 0x72 
00076 };
00077 
00078 /*
00079  *     The encode for bin hex format.
00080  */
00081  
00082 PRIVATE int binhex_fill_data(
00083        binhex_encode_object* p_bh_encode_obj, char c)
00084 {
00085        int i;
00086        
00087        if (p_bh_encode_obj->pos_outbuff >= p_bh_encode_obj->s_outbuff)
00088        {
00089               p_bh_encode_obj->overflow[p_bh_encode_obj->s_overflow++] = c;
00090        }
00091        else
00092        {
00093               p_bh_encode_obj->outbuff[p_bh_encode_obj->pos_outbuff++] =c;
00094        }
00095        
00096        if (++p_bh_encode_obj->line_length == 64)
00097        {
00098               /*
00099               **  Incase the new line is 2 character. LRCR
00100               */
00101               for(i = 1; i <= p_bh_encode_obj->newline[0]; i++)
00102                      binhex_fill_data(p_bh_encode_obj, p_bh_encode_obj->newline[i]);
00103                      
00104               p_bh_encode_obj->line_length = 0;
00105        }
00106        
00107        return p_bh_encode_obj->s_overflow ? errEOB : NOERR;
00108 }
00109 
00110 /************************************************************************
00111  * EncodeDataChar - encode an 8-bit data char into a six-bit buffer
00112  * returns the number of valid encoded characters generated
00113  ************************************************************************/
00114 PRIVATE int binhex_encode_data_char(
00115        binhex_encode_object *p_bh_encode_obj, 
00116        unsigned char c)
00117 {
00118        int status = 0;
00119 
00120        switch (p_bh_encode_obj->state86++)
00121        {
00122               case 0:
00123                      status = binhex_fill_data(p_bh_encode_obj,
00124                                                  BinHexTable[(c>>2)&0x3f]);
00125                      p_bh_encode_obj->saved_bits = (c&0x3)<<4;
00126                      break;
00127               case 1:
00128                      status = binhex_fill_data(p_bh_encode_obj, 
00129                                                  BinHexTable[p_bh_encode_obj->saved_bits | ((c>>4)&0xf)]);
00130                      p_bh_encode_obj->saved_bits = (c&0xf)<<2;
00131                      break;
00132               case 2:
00133                      status = binhex_fill_data(p_bh_encode_obj, 
00134                                                  BinHexTable[p_bh_encode_obj->saved_bits | ((c>>6)&0x3)]);
00135                      if (status != NOERR)
00136                             break;
00137                      
00138                      status = binhex_fill_data(p_bh_encode_obj, 
00139                                                  BinHexTable[c&0x3f]);
00140                      p_bh_encode_obj->state86 = 0;
00141                      break;
00142        }
00143        return status;
00144 } 
00145 
00146 #define BYTEMASK     0xff
00147 #define BYTEBIT      0x100
00148 #define WORDMASK     0xffff
00149 #define WORDBIT      0x10000
00150 #define CRCCONSTANT 0x1021
00151 
00152 #define WOW { \
00153               c <<= 1; \
00154               if ((temp <<= 1) & WORDBIT) \
00155                      temp = (temp & WORDMASK) ^ CRCCONSTANT; \
00156               temp ^= (c >> 8); \
00157               c &= BYTEMASK; \
00158        }
00159 
00160 PRIVATE void binhex_comp_q_crc_out(
00161        binhex_encode_object *p_bh_encode_obj, uint16 c)
00162 {
00163        register uint32 temp = p_bh_encode_obj->CRC;
00164 
00165        WOW;
00166        WOW;
00167        WOW;
00168        WOW;
00169        WOW;
00170        WOW;
00171        WOW;
00172        WOW;
00173        p_bh_encode_obj->CRC = temp;
00174 }
00175 
00176 PRIVATE int binhex_encode_buff(
00177        binhex_encode_object *p_bh_encode_obj,
00178        unsigned char*       data, 
00179        int    size)
00180 {
00181        int  i, status = 0;
00182        unsigned char dc;
00183        
00184        for (i = 0; i < size; i++)
00185        {
00186               dc = *data++;
00187 
00188               status = binhex_encode_data_char(p_bh_encode_obj, dc);
00189               if ((char)dc == (char)0x90)
00190                      status = binhex_encode_data_char(p_bh_encode_obj, 0);
00191                      
00192               if (status != NOERR)
00193                      break;
00194                      
00195               binhex_comp_q_crc_out(p_bh_encode_obj, dc);             /* and compute the CRC too */ 
00196        }
00197        return status;
00198 }
00199 
00200 PRIVATE int binhex_encode_end_a_part(
00201        binhex_encode_object* p_bh_encode_obj)
00202 {
00203        int           status;
00204        uint16  tempCrc;
00205        
00206        /*
00207        ** write the CRC to the encode.
00208        */
00209        binhex_comp_q_crc_out(p_bh_encode_obj, 0);
00210        binhex_comp_q_crc_out(p_bh_encode_obj, 0);
00211        tempCrc = (uint16)(p_bh_encode_obj->CRC & 0xffff);
00212        tempCrc = htons(tempCrc);
00213        status = binhex_encode_buff(p_bh_encode_obj,
00214                                    (unsigned char*)&tempCrc, 
00215                                    sizeof(uint16));
00216        p_bh_encode_obj->CRC = 0;
00217        return status;
00218 }
00219 
00220 PRIVATE int binhex_encode_finishing(
00221        binhex_encode_object *p_bh_encode_obj)
00222 {
00223        int i, status = 0;
00224        
00225        if (p_bh_encode_obj->state86) 
00226               status = binhex_encode_buff(p_bh_encode_obj, (unsigned char*)&status, 1);
00227        
00228        /*
00229        **     The close token.
00230        */     
00231        status = binhex_fill_data(p_bh_encode_obj, ':');
00232 
00233        for (i=1; i <= p_bh_encode_obj->newline[0]; i++)
00234               status = binhex_fill_data(p_bh_encode_obj, 
00235                                    p_bh_encode_obj->newline[i]);
00236 
00237        return errDone;             
00238 }
00239 
00240 
00241 int binhex_encode_init(binhex_encode_object *p_bh_encode_obj)
00242 {      
00243        /*
00244        ** init all the status.
00245        */
00246        memset(p_bh_encode_obj, 0, sizeof(binhex_encode_object));
00247        
00248        p_bh_encode_obj->line_length = 1;
00249        
00250        p_bh_encode_obj->newline[0] = 2;
00251        p_bh_encode_obj->newline[1] = CR;
00252        p_bh_encode_obj->newline[2] = LF;         /*     to confirm with rfc822, use CRLF   */
00253        
00254        return NOERR;
00255 }
00256 
00257 int binhex_encode_next(
00258        binhex_encode_object* p_bh_encode_obj, 
00259        char   *in_buff,
00260        int32  in_size,
00261        char   *out_buff, 
00262        int32  buff_size,
00263        int32  *real_size)
00264 {
00265        int status = 0;
00266        /*
00267        ** setup the buffer information.
00268        */
00269        p_bh_encode_obj->outbuff     = out_buff;
00270        p_bh_encode_obj->s_outbuff   = buff_size;
00271        p_bh_encode_obj->pos_outbuff = 0;
00272        
00273        /*
00274        ** copy over the left over from last time.
00275        */
00276        if (p_bh_encode_obj->s_overflow)
00277        {
00278               memcpy(p_bh_encode_obj->overflow, 
00279                      p_bh_encode_obj->outbuff, 
00280                      p_bh_encode_obj->s_overflow);
00281                             
00282               p_bh_encode_obj->pos_outbuff = p_bh_encode_obj->s_overflow;
00283               p_bh_encode_obj->s_overflow = 0;
00284        } 
00285        
00286        /*
00287        **     Jump to the right state.
00288        */
00289        if ( p_bh_encode_obj->state < BINHEX_STATE_DONE)
00290        {
00291               if (in_buff == NULL && in_size == 0)
00292               {
00293                      /* this is our special token of end of a part, time to append crc codes      */
00294                      if (p_bh_encode_obj->state != BINHEX_STATE_FINISH)                    
00295                             status = binhex_encode_end_a_part(p_bh_encode_obj);
00296                      else
00297                             status = binhex_encode_finishing(p_bh_encode_obj);
00298                      
00299                      p_bh_encode_obj->state += 2;              /* so we can jump to the next state.*/
00300               }
00301               else
00302               {
00303                      if  (p_bh_encode_obj->state == BINHEX_STATE_START)
00304                      {
00305                             PL_strcpy(p_bh_encode_obj->outbuff + p_bh_encode_obj->pos_outbuff,
00306                                                  "\r\n(This file must be converted with BinHex 4.0)\r\n\r\n:");
00307                             p_bh_encode_obj->pos_outbuff += 52;
00308                      
00309                             p_bh_encode_obj->state = BINHEX_STATE_HEADER;
00310                             
00311                             memcpy(p_bh_encode_obj->name,
00312                                    in_buff, 
00313                                    in_size);     
00314                      }
00315                      else if  (p_bh_encode_obj->state == BINHEX_STATE_HEADER)
00316                      {
00317                             memcpy(&(p_bh_encode_obj->head),
00318                                    in_buff, 
00319                                    sizeof(binhex_header));
00320                             
00321                             if (in_size == 20)   /* in the platform that alignment is 4-bytes. */
00322                                    in_size = 18;
00323                                                  
00324                             p_bh_encode_obj->head.dlen = 0;           /* we just can't trust the dlen from      */
00325                                                                                            /* apple double decoder told us.          */
00326                                                                                            /* do our own counting.                                 */                          
00327                      }                    
00328                      else if  (p_bh_encode_obj->state == BINHEX_STATE_DFORK)
00329                      {
00330                             if (p_bh_encode_obj->head.dlen == 0)
00331                             {
00332                                    p_bh_encode_obj->c[0] = in_buff[0];       /* save the first 2 bytes, in case  */
00333                                    p_bh_encode_obj->c[1] = in_buff[1]; /* head and data share 1 code block */
00334                             }
00335                             p_bh_encode_obj->head.dlen += in_size;
00336                      }
00337                      
00338                      status        = binhex_encode_buff(p_bh_encode_obj, 
00339                                                  (unsigned char *)in_buff, 
00340                                                  in_size);
00341               }
00342        }                           
00343        *real_size = p_bh_encode_obj->pos_outbuff;
00344        return status;
00345 }
00346 
00347 /*
00348 **     Only generate the header part of the encoding,
00349 **            so we can fix up the 
00350 */
00351 int binhex_reencode_head(
00352        binhex_encode_object *p_bh_encode_obj,
00353        char*  outbuff,
00354        int32  buff_size,
00355        int32*  real_size)
00356 {
00357        int32  size, dlen;
00358        int    status;
00359        char   buff[64];
00360        
00361        p_bh_encode_obj->state             = 0;   
00362        p_bh_encode_obj->state86    = 0;   
00363        p_bh_encode_obj->CRC        = 0;
00364        p_bh_encode_obj->line_length= 1;
00365        p_bh_encode_obj->saved_bits = 0;
00366        p_bh_encode_obj->s_overflow = 0    ;
00367        
00368        status = binhex_encode_next(
00369                                           p_bh_encode_obj, 
00370                                           p_bh_encode_obj->name,             
00371                                           p_bh_encode_obj->name[0]+2,        /* in_size */
00372                                           outbuff, 
00373                                           buff_size,
00374                                           real_size);
00375        if (status != NOERR)
00376               return status;
00377               
00378        size = *real_size;
00379        
00380        /* now we should have the right data length in the head structure, but don't               */
00381        /* forget convert it back to the net byte order (i.e., Motolora) before write it    */
00382        /*                                                                                                                                                 */
00383        /* Note:      since we don't change the size of rlen, so don't need to worry about it      */
00384        
00385        p_bh_encode_obj->head.dlen = htonl(dlen = p_bh_encode_obj->head.dlen);
00386        
00387        /* make a copy before do the encoding, -- it may modify the head!!!. */
00388        memcpy(buff, (char*)&p_bh_encode_obj->head, 
00389               sizeof(binhex_header));
00390        if (18 < sizeof(binhex_header))
00391        {
00392               /* we get an alignment problem here.      */
00393         memcpy(buff + 10, buff + 12, 8);
00394        }
00395                                                                
00396        status = binhex_encode_next(
00397                                           p_bh_encode_obj, 
00398                                           (char*)buff,         
00399                                           18,                                       /* sizeof(binhex_header),*/
00400                                           outbuff   + size, 
00401                                           buff_size - size,
00402                                           real_size);
00403        if (status != NOERR)
00404               return status;
00405        
00406        size += *real_size;
00407               
00408        status = binhex_encode_next(                                   /* for CRC */
00409                                           p_bh_encode_obj, 
00410                                           NULL,         
00411                                           0,                                               /* in_size */
00412                                           outbuff  + size, 
00413                                           buff_size - size,
00414                                           real_size);
00415        
00416        if (status != NOERR)
00417               return status;
00418               
00419        size += *real_size;
00420 
00421        if (p_bh_encode_obj->state86 != 0)
00422        {
00423               /*     
00424               **     Make sure we don't destroy the orignal valid coding.
00425               **
00426               **     (Keep in mind that 3 characters share 4 coding chars,
00427               **      so it is possible for the head and data stream share one 4 code group.
00428               **
00429               **     How about only one or zero character in the data fork?
00430               **            ---- just rerun the encoding, not a big deal.
00431               */
00432               if (dlen <= 1)
00433               {
00434                      /* why just rerun the encoding once more. */
00435                      status = binhex_encode_next(
00436                                           p_bh_encode_obj,
00437                                           p_bh_encode_obj->c,
00438                                           dlen,
00439                                           outbuff   + size,
00440                                           buff_size - size,
00441                                           real_size);
00442                      if (status != NOERR)
00443                             return status;
00444                             
00445                      size += *real_size;                                            /* encode the data fork            */
00446                      
00447                      status = binhex_encode_next(
00448                                           p_bh_encode_obj,
00449                                           NULL,
00450                                           0,
00451                                           outbuff   + size,
00452                                           buff_size - size,
00453                                           real_size);
00454                      if (status != NOERR)
00455                             return status;
00456 
00457                      size += *real_size;                                            /* for the end up data fork */
00458                      
00459                      status = binhex_encode_next(
00460                                           p_bh_encode_obj,
00461                                           NULL,
00462                                           0,
00463                                           outbuff   + size,
00464                                           buff_size - size,
00465                                           real_size);                                      /* for the end up encoding*/
00466               }
00467               else
00468               {
00469                      status = binhex_encode_next(
00470                                           p_bh_encode_obj, 
00471                                           p_bh_encode_obj->c,         
00472                                           3 - p_bh_encode_obj->state86,      /* in_size */
00473                                           outbuff   + size, 
00474                                           buff_size - size,
00475                                           real_size);
00476               }
00477               size += *real_size;  
00478        }
00479        *real_size = size;
00480        
00481        return status;
00482 }
00483 
00484 int binhex_encode_end (
00485        binhex_encode_object *p_bh_encode_obj, 
00486        XP_Bool is_aborting)
00487 {
00488        return NOERR;
00489 }
00490 
00491 
00492 /*
00493 **     The decode's.
00494 */
00495 static char binhex_decode[256] = 
00496 {
00497        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00498        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00499        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, -1, -1,
00500        13, 14, 15, 16, 17, 18, 19, -1, 20, 21, -1, -1, -1, -1, -1, -1,
00501        22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1,
00502        37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, -1, -1, -1, -1,
00503        48, 49, 50, 51, 52, 53, 54, -1, 55, 56, 57, 58, 59, 60, -1, -1,
00504        61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00505        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00506        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00507        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00508        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00509        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00510        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00511        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00512        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00513 };
00514 
00515 #define BHEXVAL(c) (binhex_decode[(unsigned char) c])
00516 
00517 /*
00518 **     the decode for bin hex format.
00519 */
00520 int binhex_decode_init (
00521        binhex_decode_object *p_bh_decode_obj)
00522 {
00523        memset(p_bh_decode_obj, 0, sizeof(binhex_decode_object));
00524        
00525        p_bh_decode_obj->octetin    = 26;
00526        p_bh_decode_obj->donepos    = 3;
00527 
00528        return NOERR;
00529 }
00530 
00531 PRIVATE void binhex_process(
00532        binhex_decode_object *p_bh_decode_obj)
00533 {
00534        int32         status;
00535        uint16        tmpcrc, cval;
00536        unsigned char  ctmp, c = p_bh_decode_obj->rlebuf;
00537        
00538        /* do CRC */
00539        ctmp = p_bh_decode_obj->inCRC ? c : 0;
00540        cval = p_bh_decode_obj->CRC   & 0xf000;
00541        tmpcrc = ((uint16) (p_bh_decode_obj->CRC << 4) | 
00542                                            (ctmp >> 4))
00543                                     ^ (cval | (cval >> 7) | 
00544                                           (cval >> 12));
00545        cval = tmpcrc & 0xf000;
00546        p_bh_decode_obj->CRC = ((uint16) (tmpcrc << 4) | 
00547                                                  (ctmp & 0x0f))
00548                                            ^ (cval | (cval >> 7) | 
00549                                                  (cval >> 12));
00550 
00551        /* handle state */
00552        switch (p_bh_decode_obj->state) 
00553        {
00554               case BINHEX_STATE_START:
00555                      p_bh_decode_obj->state             = BINHEX_STATE_FNAME;
00556                      p_bh_decode_obj->count             = 1;
00557 #ifndef XP_MAC
00558                      p_bh_decode_obj->name = XP_ALLOC(64);
00559 #endif
00560                      *(p_bh_decode_obj->name) = (c & 63);
00561                      break;
00562                      
00563               case BINHEX_STATE_FNAME:
00564                      p_bh_decode_obj->name[p_bh_decode_obj->count] = c;
00565                      
00566                      if (p_bh_decode_obj->count++ > *(p_bh_decode_obj->name)) 
00567                      {
00568 #if 0                
00569                             char* p;
00570                             /* convert it to the c-string too.               */
00571                             c = *(p_bh_decode_obj->name);
00572                             p = p_bh_decode_obj->name;
00573                      
00574                             while (c--)
00575                             {
00576                                    *p = *(p+1); p++;
00577                             }
00578                                    
00579                             *p = '\0';
00580 #endif                      
00581                             p_bh_decode_obj->state = BINHEX_STATE_HEADER;
00582                             p_bh_decode_obj->count = 0;
00583                      }
00584                      break;
00585                      
00586               case BINHEX_STATE_HEADER:
00587                      ((char *)&p_bh_decode_obj->head)[p_bh_decode_obj->count] = c;
00588                      if (++p_bh_decode_obj->count == 18) 
00589                      {
00590 #ifndef XP_MAC
00591                             if (sizeof(binhex_header) != 18)   /* fix the alignment problem in some OS */
00592                             {
00593                                    char *p = (char *)&p_bh_decode_obj->head;
00594                                    p += 19;
00595                                    for (c = 0; c < 8; c++)
00596                                    {
00597                                           *p = *(p-2);  p--;
00598                                    }
00599                             }
00600 #endif
00601                             p_bh_decode_obj->state = BINHEX_STATE_HCRC;
00602                             p_bh_decode_obj->inCRC = 1;
00603                             p_bh_decode_obj->count = 0;
00604                      }
00605                      break;
00606                      
00607               case BINHEX_STATE_DFORK:
00608               case BINHEX_STATE_RFORK:
00609                      p_bh_decode_obj->outbuff[p_bh_decode_obj->pos_outbuff++] = c;
00610                      if (-- p_bh_decode_obj->count == 0) 
00611                      {
00612 #ifdef XP_MAC 
00613                             long howMuch = p_bh_decode_obj->pos_outbuff;
00614                             status = FSWrite(p_bh_decode_obj->fileId, 
00615                                                         &howMuch,
00616                                                         p_bh_decode_obj->outbuff);                                                   
00617                             FSClose(p_bh_decode_obj->fileId);
00618 #else                       
00619                                                         /* only output data fork in the non-mac system.                */
00620                             if (p_bh_decode_obj->state == BINHEX_STATE_DFORK)
00621                             {
00622                                    status = p_bh_decode_obj->fileId->write(p_bh_decode_obj->outbuff, 
00623                                                   p_bh_decode_obj->pos_outbuff)
00624                                                                    == p_bh_decode_obj->pos_outbuff ? NOERR : errFileWrite;
00625                                                         
00626                                    p_bh_decode_obj->fileId->close();
00627                             }
00628                             else
00629                             {
00630                                    status = NOERR;                           /* do nothing for resource fork.   */
00631                             }
00632 #endif
00633                             p_bh_decode_obj->pos_outbuff = 0;
00634                             
00635                             if (status != NOERR)
00636                                    p_bh_decode_obj->state = status;
00637                             else
00638                             {
00639                                    p_bh_decode_obj->state ++;
00640                                    p_bh_decode_obj->fileId = 0;
00641                             }
00642                             p_bh_decode_obj->inCRC = 1;
00643                      }
00644                      else if (p_bh_decode_obj->pos_outbuff >= MAX_BUFF_SIZE)
00645                      {                           
00646 #ifdef XP_MAC 
00647                             long howMuch = p_bh_decode_obj->pos_outbuff;
00648                             status = FSWrite(p_bh_decode_obj->fileId, 
00649                                                         &howMuch,
00650                                                         p_bh_decode_obj->outbuff);
00651 #else
00652                             if (p_bh_decode_obj->state == BINHEX_STATE_DFORK)
00653                             {
00654                                    status = p_bh_decode_obj->fileId->write(p_bh_decode_obj->outbuff,
00655                                                                                           p_bh_decode_obj->pos_outbuff) 
00656                                                                    == p_bh_decode_obj->pos_outbuff ? NOERR : errFileWrite; 
00657                             }
00658                             else
00659                             {
00660                                    status = NOERR;                    /* don't care about the resource fork. */
00661                             }
00662 #endif                                           
00663                             if (status != NOERR)
00664                                    p_bh_decode_obj->state = status;
00665                                    
00666                             p_bh_decode_obj->pos_outbuff = 0;
00667                      }
00668                      break;
00669                      
00670               case BINHEX_STATE_HCRC:
00671               case BINHEX_STATE_DCRC:
00672               case BINHEX_STATE_RCRC:
00673                      if (!p_bh_decode_obj->count++) 
00674                      {
00675                             p_bh_decode_obj->fileCRC = (unsigned short) c << 8;
00676                      } 
00677                      else 
00678                      {
00679                             if ((p_bh_decode_obj->fileCRC | c) != p_bh_decode_obj->CRC) 
00680                             {
00681                                    if (p_bh_decode_obj->state > BINHEX_STATE_HCRC) 
00682                                    {
00683 #ifdef XP_MAC
00684                                           HDelete(p_bh_decode_obj->vRefNum, 
00685                                                         p_bh_decode_obj->parID,
00686                                                         (unsigned char*)p_bh_decode_obj->name);
00687 #else
00688                                           p_bh_decode_obj->name->Delete(PR_FALSE);
00689 #endif
00690                                    }
00691                                    p_bh_decode_obj->state = errDecoding;
00692                                    break;
00693                             }
00694                             
00695                             /*
00696                             ** passed the CRC check!!!
00697                             */
00698                             p_bh_decode_obj->CRC = 0;
00699                             if (++ p_bh_decode_obj->state == BINHEX_STATE_FINISH) 
00700                             {
00701 #ifdef XP_MAC
00702                                    FInfo  finfo;
00703 
00704                                    /* set back the file information.before we declare done ! */
00705                                    finfo.fdType  = p_bh_decode_obj->head.type;
00706                                    finfo.fdCreator = p_bh_decode_obj->head.creator;
00707                                    finfo.fdFlags        = p_bh_decode_obj->head.flags & 0xf800;
00708                                    
00709                                    HSetFInfo(p_bh_decode_obj->vRefNum, 
00710                                                         p_bh_decode_obj->parID, 
00711                                                         (unsigned char *)p_bh_decode_obj->name, 
00712                                                         &finfo);
00713 #endif
00714                                    /*     now We are done with everything.   */            
00715                                    p_bh_decode_obj->state++;
00716                                    break;
00717                             }
00718                             
00719                             if (p_bh_decode_obj->state == BINHEX_STATE_DFORK) 
00720                             {
00721 #ifdef XP_MAC
00722                                    StandardFileReply    reply;
00723                                    if( !p_bh_decode_obj->mSpec )
00724                                    {      
00725                                           StandardPutFile("\pSave decoded file as:", 
00726                                                                (unsigned char *)p_bh_decode_obj->name, 
00727                                                                &reply);
00728                                                                
00729                                           if (!reply.sfGood) 
00730                                           {
00731                                                  p_bh_decode_obj->state = errUsrCancel;
00732                                                  break;
00733                                           }
00734                                    }
00735                                    else
00736                                    {
00737                                           reply.sfFile.vRefNum = p_bh_decode_obj->mSpec->vRefNum;
00738                                           reply.sfFile.parID = p_bh_decode_obj->mSpec->parID;
00739                                           memcpy(&reply.sfFile.name, p_bh_decode_obj->mSpec->name , 63 );              
00740                                    }                                  
00741                                    
00742                                        memcpy(p_bh_decode_obj->name, 
00743                                               reply.sfFile.name, 
00744                                               *(reply.sfFile.name)+1);       /* save the new file name.  */
00745                                           
00746                                    p_bh_decode_obj->vRefNum = reply.sfFile.vRefNum;
00747                                    p_bh_decode_obj->parID   = reply.sfFile.parID;
00748                                           
00749                                    HDelete(reply.sfFile.vRefNum,
00750                                                                reply.sfFile.parID, 
00751                                                                reply.sfFile.name);
00752                                    
00753                                    status = HCreate(p_bh_decode_obj->vRefNum, 
00754                                                                 p_bh_decode_obj->parID, 
00755                                                                 reply.sfFile.name,
00756                                                                 p_bh_decode_obj->head.creator, 
00757                                                                 p_bh_decode_obj->head.type);
00758 #else  /* non-mac OS case */
00759                                    char* filename;
00760                                    
00761                                    filename = XP_ALLOC(1024);
00762                                    if (filename == NULL 
00763 /*JFD Do we still need this?
00764                                      ||
00765                                           FE_PromptForFileName(p_bh_decode_obj->context, 
00766                                                                       XP_GetString(MK_MSG_SAVE_DECODED_AS),
00767                                                                       0,
00768                                                                       FALSE,
00769                                                                       FALSE,
00770                                                                       simple_copy,
00771                                                                       filename) == -1
00772 */
00773                                                                       )
00774                                    {
00775                                           FREEIF(filename);
00776                                           p_bh_decode_obj->state = errUsrCancel;
00777                                           break;
00778                                    }
00779 
00780                                    if (p_bh_decode_obj->name)
00781             delete p_bh_decode_obj->fileId;
00782 
00783                                    p_bh_decode_obj->name = new nsFileSpec(filename);
00784           if (!p_bh_decode_obj->name)
00785             status = errFileOpen;
00786           else
00787           {
00788                                      p_bh_decode_obj->fileId = new nsIOFileStream(*(p_bh_decode_obj->name), (PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE));
00789                                      if (p_bh_decode_obj->fileId == NULL)
00790                                             status = errFileOpen;
00791                                      else
00792                                             status = NOERR;
00793           }
00794 
00795                                    XP_FREE(filename);
00796                                    
00797 #endif
00798                                    if (status != NOERR)
00799                                           p_bh_decode_obj->state = status;
00800                                           
00801                                    p_bh_decode_obj->count 
00802                                           = ntohl(p_bh_decode_obj->head.dlen);
00803                             }
00804                             else
00805                             {
00806                                    p_bh_decode_obj->count 
00807                                           = ntohl(p_bh_decode_obj->head.rlen);      /* it should in host byte order */
00808                             }
00809                             
00810                             if (p_bh_decode_obj->count) 
00811                             {
00812                                    p_bh_decode_obj->inCRC = 0;
00813 #ifdef XP_MAC
00814                                    if (p_bh_decode_obj->state == BINHEX_STATE_DFORK)
00815                                           status = HOpen(p_bh_decode_obj->vRefNum,
00816                                                                   p_bh_decode_obj->parID,
00817                                                                   (unsigned char*)p_bh_decode_obj->name,
00818                                                                   fsWrPerm,
00819                                                                   &(p_bh_decode_obj->fileId));
00820                                    else
00821                                           status = HOpenRF(p_bh_decode_obj->vRefNum,
00822                                                                   p_bh_decode_obj->parID,
00823                                                                   (unsigned char*)p_bh_decode_obj->name,
00824                                                                   fsWrPerm,
00825                                                                   &(p_bh_decode_obj->fileId));
00826                                    if (status != NOERR) 
00827                                    {
00828                                           p_bh_decode_obj->state = errFileOpen;
00829                                           HDelete(p_bh_decode_obj->vRefNum,
00830                                                                       p_bh_decode_obj->parID, 
00831                                                                       (unsigned char*)p_bh_decode_obj->name);
00832                                           break;
00833                                    }
00834 #else
00835                                    /* for None Mac OS -- nothing is required, file already open.  */
00836                                    
00837 #endif                                           
00838                             } 
00839                             else 
00840                             {
00841                                    /* nothing inside, so skip to the next state. */
00842                                    p_bh_decode_obj->state ++;
00843                             }
00844                      }
00845                      break;
00846        }
00847        
00848        return;
00849 }
00850 
00851 static int get_next_char(binhex_decode_object *p_bh_decode_obj)
00852 {
00853        char c = 0;
00854        
00855        while (p_bh_decode_obj->pos_inbuff < p_bh_decode_obj->s_inbuff)
00856        {
00857               c = p_bh_decode_obj->inbuff[p_bh_decode_obj->pos_inbuff++];
00858               if (c != LF && c != CR)
00859                      break;
00860        }
00861        return (c == LF || c == CR) ? 0 : (int) c;
00862 }
00863 
00864 int binhex_decode_next (
00865        binhex_decode_object *p_bh_decode_obj, 
00866        const char *in_buff, 
00867        int32  buff_size)
00868 {
00869        int    found_start;
00870        int octetpos, c = 0;
00871        uint32               val;
00872        
00873        /*
00874        **     reset the buff first. 
00875        */
00876        p_bh_decode_obj->inbuff     = (char*)in_buff;
00877        p_bh_decode_obj->s_inbuff   = buff_size;
00878        p_bh_decode_obj->pos_inbuff = 0;
00879        
00880        /*
00881        **     if it is the first time, seek to the right start place. 
00882        */
00883        if (p_bh_decode_obj->state == BINHEX_STATE_START)
00884        {
00885                found_start = FALSE;
00886               /*
00887               **     go through the line, until we get a ':'
00888               */
00889               while (p_bh_decode_obj->pos_inbuff < p_bh_decode_obj->s_inbuff)
00890               {
00891                      c = p_bh_decode_obj->inbuff[p_bh_decode_obj->pos_inbuff++];
00892                      while (c == CR || c == LF)
00893                      {
00894                             if (p_bh_decode_obj->pos_inbuff >= p_bh_decode_obj->s_inbuff)
00895                                    break;
00896                                                                                                                 
00897                             c = p_bh_decode_obj->inbuff[p_bh_decode_obj->pos_inbuff++];
00898                             if (c == ':')
00899                             {
00900                                    found_start = TRUE;
00901                                    break;
00902                             }
00903                      }
00904                      if (found_start)     break;        /* we got the start point.                       */
00905               }
00906               
00907               if (p_bh_decode_obj->pos_inbuff >= p_bh_decode_obj->s_inbuff)
00908                      return NOERR;               /* we meet buff end before we get the     */
00909                                                                /* start point, wait till next fills.     */
00910               
00911               if (c != ':')
00912                      return errDecoding;         /* can't find the start character. */
00913        }
00914        
00915        /*
00916        **     run - through the in-stream now.
00917        */
00918        while (p_bh_decode_obj->state >= 0 && 
00919                  p_bh_decode_obj->state < BINHEX_STATE_DONE) 
00920        {
00921               /* fill in octetbuf */
00922               do 
00923               {
00924                      if (p_bh_decode_obj->pos_inbuff >= p_bh_decode_obj->s_inbuff)
00925                             return NOERR;               /* end of buff, go on for the nxet calls. */
00926                                    
00927                      c = get_next_char(p_bh_decode_obj);
00928                      if (c == 0)
00929                             return NOERR;
00930                              
00931                      if ((val = BHEXVAL(c)) == -1) 
00932                      {
00933                             /*
00934                             ** we incount an invalid character.
00935                             */
00936                             if (c) 
00937                             {
00938                                    /*
00939                                    ** rolling back.
00940                                    */
00941                                    p_bh_decode_obj->donepos --;
00942                                    if (p_bh_decode_obj->octetin >= 14)              p_bh_decode_obj->donepos--;
00943                                    if (p_bh_decode_obj->octetin >= 20)       p_bh_decode_obj->donepos--;
00944                             }
00945                             break;
00946                      }
00947                      p_bh_decode_obj->octetbuf.val |= val << p_bh_decode_obj->octetin;
00948               } 
00949               while ((p_bh_decode_obj->octetin -= 6) > 2);
00950                      
00951               /* handle decoded characters -- run length encoding (rle) detection */
00952 
00953 #ifndef XP_MAC              
00954               p_bh_decode_obj->octetbuf.val 
00955                      = ntohl(p_bh_decode_obj->octetbuf.val);
00956 #endif
00957 
00958               for (octetpos = 0; octetpos < p_bh_decode_obj->donepos; ++octetpos) 
00959               {
00960                      c = p_bh_decode_obj->octetbuf.c[octetpos];
00961                      
00962                      if (c == 0x90 && !p_bh_decode_obj->marker++) 
00963                             continue;
00964                                           
00965                      if (p_bh_decode_obj->marker) 
00966                      {
00967                             if (c == 0) 
00968                             {
00969                                    p_bh_decode_obj->rlebuf = 0x90;
00970                                    binhex_process(p_bh_decode_obj);
00971                             } 
00972                             else 
00973                             {
00974                                    while (--c > 0)                           /* we are in the run lenght mode */ 
00975                                    {
00976                                           binhex_process(p_bh_decode_obj);
00977                                    }
00978                             }
00979                             p_bh_decode_obj->marker = 0;
00980                      } 
00981                      else 
00982                      {
00983                             p_bh_decode_obj->rlebuf = (unsigned char) c;
00984                             binhex_process(p_bh_decode_obj);
00985                      }
00986                      
00987                      
00988                      if (p_bh_decode_obj->state >= BINHEX_STATE_FINISH) 
00989                             break;
00990               }
00991               
00992               /* prepare for next 3 characters.  */
00993               if (p_bh_decode_obj->donepos < 3 && p_bh_decode_obj->state < BINHEX_STATE_FINISH) 
00994                      p_bh_decode_obj->state = errDecoding;
00995                                    
00996               p_bh_decode_obj->octetin           = 26;
00997               p_bh_decode_obj->octetbuf.val      = 0;
00998        }
00999        
01000        /* 
01001        **     Error clean-ups 
01002        */
01003        if (p_bh_decode_obj->state < 0 && p_bh_decode_obj->fileId) 
01004        {
01005 #ifdef XP_MAC
01006               FSClose(p_bh_decode_obj->fileId);
01007               p_bh_decode_obj->fileId = 0;
01008               HDelete(p_bh_decode_obj->vRefNum, 
01009                             p_bh_decode_obj->parID, 
01010                             (unsigned char*)p_bh_decode_obj->name);
01011 #else
01012               p_bh_decode_obj->fileId->close();
01013               delete p_bh_decode_obj->fileId;
01014               p_bh_decode_obj->name->delete(PR_FALSE);
01015 #endif
01016        }
01017        
01018        
01019        return        p_bh_decode_obj->state < 0                                ? (p_bh_decode_obj->state) : 
01020                      p_bh_decode_obj->state >= BINHEX_STATE_FINISH ? errDone : NOERR;
01021 }
01022 
01023 int binhex_decode_end (
01024        binhex_decode_object *p_bh_decode_obj, 
01025        XP_Bool       is_aborting)
01026 {
01027 #ifdef XP_MAC
01028        if (p_bh_decode_obj->fileId)
01029        {
01030               FSClose(p_bh_decode_obj->fileId);
01031               p_bh_decode_obj->fileId = 0;
01032               
01033               if (is_aborting)
01034               {
01035                      HDelete(p_bh_decode_obj->vRefNum, 
01036                                    p_bh_decode_obj->parID, 
01037                                    (unsigned char*)p_bh_decode_obj->name);
01038               }
01039        }
01040        
01041 #else
01042 
01043        if (p_bh_decode_obj->fileId)
01044        {
01045               p_bh_decode_obj->fileId->close();
01046               
01047               if (is_aborting)
01048                      p_bh_decode_obj->name->Delete(PR_FALSE);
01049        }
01050        FREEIF(p_bh_decode_obj->name);
01051 #endif
01052 
01053        return NOERR;
01054 }
01055 
01056