mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-14 15:37:55 +00:00
734 lines
16 KiB
C
734 lines
16 KiB
C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* apple_double_encode.c
|
|
* ---------------------
|
|
*
|
|
* The routines doing the Apple Double Encoding.
|
|
*
|
|
* 2aug95 mym Created.
|
|
*
|
|
*/
|
|
|
|
#include "msg.h"
|
|
#include "appledbl.h"
|
|
#include "ad_codes.h"
|
|
|
|
#ifdef XP_MAC
|
|
|
|
extern int MK_UNABLE_TO_OPEN_TMP_FILE;
|
|
extern int MK_MIME_ERROR_WRITING_FILE;
|
|
|
|
#include <Errors.h>
|
|
|
|
/*
|
|
** Local Functions prototypes.
|
|
*/
|
|
PRIVATE int output64chunk( appledouble_encode_object* p_ap_encode_obj,
|
|
int c1, int c2, int c3, int pads);
|
|
|
|
PRIVATE int to64(appledouble_encode_object* p_ap_encode_obj,
|
|
char *p,
|
|
int in_size);
|
|
|
|
PRIVATE int finish64(appledouble_encode_object* p_ap_encode_obj);
|
|
|
|
|
|
#define BUFF_LEFT(p) ((p)->s_outbuff - (p)->pos_outbuff)
|
|
|
|
/*
|
|
** write_stream.
|
|
*/
|
|
int write_stream(
|
|
appledouble_encode_object *p_ap_encode_obj,
|
|
char *out_string,
|
|
int len)
|
|
{
|
|
if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff)
|
|
{
|
|
XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
|
|
out_string,
|
|
len);
|
|
p_ap_encode_obj->pos_outbuff += len;
|
|
return noErr;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
** If the buff doesn't have enough space, use the overflow buffer then.
|
|
*/
|
|
int s_len = p_ap_encode_obj->s_outbuff - p_ap_encode_obj->pos_outbuff;
|
|
|
|
XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff,
|
|
out_string,
|
|
s_len);
|
|
XP_MEMCPY(p_ap_encode_obj->b_overflow + p_ap_encode_obj->s_overflow,
|
|
out_string + s_len,
|
|
p_ap_encode_obj->s_overflow += (len - s_len));
|
|
p_ap_encode_obj->pos_outbuff += s_len;
|
|
return errEOB;
|
|
}
|
|
}
|
|
|
|
int fill_apple_mime_header(
|
|
appledouble_encode_object *p_ap_encode_obj)
|
|
{
|
|
int status;
|
|
|
|
char tmpstr[266];
|
|
|
|
#if 0
|
|
// strcpy(tmpstr, "Content-Type: multipart/mixed; boundary=\"-\"\n\n---\n");
|
|
// status = write_stream(p_ap_encode_env,
|
|
// tmpstr,
|
|
// strlen(tmpstr));
|
|
// if (status != noErr)
|
|
// return status;
|
|
|
|
sprintf(tmpstr,
|
|
"Content-Type: multipart/appledouble; boundary=\"=\"; name=\"");
|
|
status = write_stream(p_ap_encode_obj,
|
|
tmpstr,
|
|
strlen(tmpstr));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
status = write_stream(p_ap_encode_obj,
|
|
p_ap_encode_obj->fname,
|
|
XP_STRLEN(p_ap_encode_obj->fname));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
XP_SPRINTF(tmpstr,
|
|
"\"\nContent-Disposition: inline; filename=\"%s\"\n\n\n--=\n",
|
|
p_ap_encode_obj->fname);
|
|
#endif
|
|
XP_SPRINTF(tmpstr, "--%s"CRLF, p_ap_encode_obj->boundary);
|
|
status = write_stream(p_ap_encode_obj,
|
|
tmpstr,
|
|
XP_STRLEN(tmpstr));
|
|
return status;
|
|
}
|
|
|
|
int ap_encode_file_infor(
|
|
appledouble_encode_object *p_ap_encode_obj)
|
|
{
|
|
CInfoPBRec cipbr;
|
|
HFileInfo *fpb = (HFileInfo *)&cipbr;
|
|
ap_header head;
|
|
ap_entry entries[NUM_ENTRIES];
|
|
ap_dates dates;
|
|
short i;
|
|
long comlen, procID;
|
|
DateTimeRec cur_time;
|
|
unsigned long cur_secs;
|
|
IOParam vinfo;
|
|
GetVolParmsInfoBuffer vp;
|
|
DTPBRec dtp;
|
|
char comment[256];
|
|
Str63 fname;
|
|
int status;
|
|
|
|
strcpy((char *)fname+1,p_ap_encode_obj->fname);
|
|
fname[0] = XP_STRLEN(p_ap_encode_obj->fname);
|
|
|
|
fpb->ioNamePtr = fname;
|
|
fpb->ioDirID = p_ap_encode_obj->dirId;
|
|
fpb->ioVRefNum = p_ap_encode_obj->vRefNum;
|
|
fpb->ioFDirIndex = 0;
|
|
if (PBGetCatInfoSync(&cipbr) != noErr)
|
|
{
|
|
return errFileOpen;
|
|
}
|
|
|
|
/* get a file comment, if possible */
|
|
procID = 0;
|
|
GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID);
|
|
memset((void *) &vinfo, '\0', sizeof (vinfo));
|
|
vinfo.ioCompletion = nil;
|
|
vinfo.ioVRefNum = fpb->ioVRefNum;
|
|
vinfo.ioBuffer = (Ptr) &vp;
|
|
vinfo.ioReqCount = sizeof (vp);
|
|
comlen = 0;
|
|
if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr &&
|
|
((vp.vMAttrib >> bHasDesktopMgr) & 1))
|
|
{
|
|
memset((void *) &dtp, '\0', sizeof (dtp));
|
|
dtp.ioVRefNum = fpb->ioVRefNum;
|
|
if (PBDTGetPath(&dtp) == noErr)
|
|
{
|
|
dtp.ioCompletion = nil;
|
|
dtp.ioDTBuffer = (Ptr) comment;
|
|
dtp.ioNamePtr = fpb->ioNamePtr;
|
|
dtp.ioDirID = fpb->ioFlParID;
|
|
if (PBDTGetCommentSync(&dtp) == noErr)
|
|
comlen = dtp.ioDTActCount;
|
|
}
|
|
}
|
|
|
|
/* write header */
|
|
// head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC;
|
|
head.magic = APPLEDOUBLE_MAGIC; /* always do apple double */
|
|
head.version = VERSION;
|
|
memset(head.fill, '\0', sizeof (head.fill));
|
|
head.entries = NUM_ENTRIES - 1;
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) &head,
|
|
sizeof (head));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write entry descriptors */
|
|
entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries;
|
|
entries[0].id = ENT_NAME;
|
|
entries[0].length = *fpb->ioNamePtr;
|
|
entries[1].id = ENT_FINFO;
|
|
entries[1].length = sizeof (FInfo) + sizeof (FXInfo);
|
|
entries[2].id = ENT_DATES;
|
|
entries[2].length = sizeof (ap_dates);
|
|
entries[3].id = ENT_COMMENT;
|
|
entries[3].length = comlen;
|
|
entries[4].id = ENT_RFORK;
|
|
entries[4].length = fpb->ioFlRLgLen;
|
|
entries[5].id = ENT_DFORK;
|
|
entries[5].length = fpb->ioFlLgLen;
|
|
|
|
/* correct the link in the entries. */
|
|
for (i = 1; i < NUM_ENTRIES; ++i)
|
|
{
|
|
entries[i].offset = entries[i-1].offset + entries[i-1].length;
|
|
}
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) entries,
|
|
sizeof (ap_entry) * head.entries);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write name */
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) fpb->ioNamePtr + 1,
|
|
*fpb->ioNamePtr);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write finder info */
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) &fpb->ioFlFndrInfo,
|
|
sizeof (FInfo));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) &fpb->ioFlXFndrInfo,
|
|
sizeof (FXInfo));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write dates */
|
|
GetTime(&cur_time);
|
|
DateToSeconds(&cur_time, &cur_secs);
|
|
dates.create = fpb->ioFlCrDat + CONVERT_TIME;
|
|
dates.modify = fpb->ioFlMdDat + CONVERT_TIME;
|
|
dates.backup = fpb->ioFlBkDat + CONVERT_TIME;
|
|
dates.access = cur_secs + CONVERT_TIME;
|
|
status = to64(p_ap_encode_obj,
|
|
(char *) &dates,
|
|
sizeof (ap_dates));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write comment */
|
|
if (comlen)
|
|
{
|
|
status = to64(p_ap_encode_obj,
|
|
comment,
|
|
comlen * sizeof(char));
|
|
}
|
|
/*
|
|
** Get some help information on deciding the file type.
|
|
*/
|
|
if (fpb->ioFlFndrInfo.fdType == 'TEXT' || fpb->ioFlFndrInfo.fdType == 'text')
|
|
{
|
|
p_ap_encode_obj->text_file_type = true;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
/*
|
|
** ap_encode_header
|
|
**
|
|
** encode the file header and the resource fork.
|
|
**
|
|
*/
|
|
int ap_encode_header(
|
|
appledouble_encode_object* p_ap_encode_obj,
|
|
XP_Bool firstime)
|
|
{
|
|
Str255 name;
|
|
char rd_buff[256];
|
|
short fileId;
|
|
OSErr retval = noErr;
|
|
int status;
|
|
long inCount;
|
|
|
|
if (firstime)
|
|
{
|
|
XP_STRCPY(rd_buff,
|
|
"Content-Type: application/applefile\nContent-Transfer-Encoding: base64\n\n");
|
|
status = write_stream(p_ap_encode_obj,
|
|
rd_buff,
|
|
strlen(rd_buff));
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
status = ap_encode_file_infor(p_ap_encode_obj);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/*
|
|
** preparing to encode the resource fork.
|
|
*/
|
|
name[0] = strlen(p_ap_encode_obj->fname);
|
|
strcpy((char *)name+1, p_ap_encode_obj->fname);
|
|
if (HOpenRF(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId,
|
|
name, fsRdPerm,
|
|
&p_ap_encode_obj->fileId) != noErr)
|
|
{
|
|
return errFileOpen;
|
|
}
|
|
}
|
|
|
|
fileId = p_ap_encode_obj->fileId;
|
|
while (retval == noErr)
|
|
{
|
|
if (BUFF_LEFT(p_ap_encode_obj) < 400)
|
|
break;
|
|
|
|
inCount = 256;
|
|
retval = FSRead(fileId, &inCount, rd_buff);
|
|
if (inCount)
|
|
{
|
|
status = to64(p_ap_encode_obj,
|
|
rd_buff,
|
|
inCount);
|
|
if (status != noErr)
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (retval == eofErr)
|
|
{
|
|
FSClose(fileId);
|
|
|
|
status = finish64(p_ap_encode_obj);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/*
|
|
** write out the boundary
|
|
*/
|
|
XP_SPRINTF(rd_buff,
|
|
CRLF"--%s"CRLF,
|
|
p_ap_encode_obj->boundary);
|
|
|
|
status = write_stream(p_ap_encode_obj,
|
|
rd_buff,
|
|
XP_STRLEN(rd_buff));
|
|
if (status == noErr)
|
|
status = errDone;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static void replace(char *p, int len, char frm, char to)
|
|
{
|
|
for (; len > 0; len--, p++)
|
|
if (*p == frm) *p = to;
|
|
}
|
|
|
|
/* Description of the various file formats and their magic numbers */
|
|
struct magic
|
|
{
|
|
char *name; /* Name of the file format */
|
|
char *num; /* The magic number */
|
|
int len; /* Length (0 means strlen(magicnum)) */
|
|
};
|
|
|
|
/* The magic numbers of the file formats we know about */
|
|
static struct magic magic[] =
|
|
{
|
|
{ "image/gif", "GIF", 0 },
|
|
{ "image/jpeg", "\377\330\377", 0 },
|
|
{ "video/mpeg", "\0\0\001\263", 4 },
|
|
{ "application/postscript", "%!", 0 },
|
|
};
|
|
static int num_magic = (sizeof(magic)/sizeof(magic[0]));
|
|
|
|
static char *text_type = TEXT_PLAIN; /* the text file type. */
|
|
static char *default_type = APPLICATION_OCTET_STREAM;
|
|
|
|
|
|
/*
|
|
* Determins the format of the file "inputf". The name
|
|
* of the file format (or NULL on error) is returned.
|
|
*/
|
|
PRIVATE char *magic_look(char *inbuff, int numread)
|
|
{
|
|
int i, j;
|
|
|
|
for (i=0; i<num_magic; i++)
|
|
{
|
|
if (magic[i].len == 0)
|
|
magic[i].len = XP_STRLEN(magic[i].num);
|
|
}
|
|
|
|
for (i=0; i<num_magic; i++)
|
|
{
|
|
if (numread >= magic[i].len)
|
|
{
|
|
for (j=0; j<magic[i].len; j++)
|
|
{
|
|
if (inbuff[j] != magic[i].num[j]) break;
|
|
}
|
|
|
|
if (j == magic[i].len)
|
|
return magic[i].name;
|
|
}
|
|
}
|
|
|
|
return default_type;
|
|
}
|
|
/*
|
|
** ap_encode_data
|
|
**
|
|
** ---------------
|
|
**
|
|
** encode on the data fork.
|
|
**
|
|
*/
|
|
int ap_encode_data(
|
|
appledouble_encode_object* p_ap_encode_obj,
|
|
XP_Bool firstime)
|
|
{
|
|
Str255 name;
|
|
char rd_buff[256];
|
|
short fileId;
|
|
OSErr retval = noErr;
|
|
long in_count;
|
|
int status;
|
|
|
|
if (firstime)
|
|
{
|
|
char* magic_type;
|
|
|
|
/*
|
|
** preparing to encode the data fork.
|
|
*/
|
|
name[0] = XP_STRLEN(p_ap_encode_obj->fname);
|
|
XP_STRCPY((char*)name+1, p_ap_encode_obj->fname);
|
|
if (HOpen( p_ap_encode_obj->vRefNum,
|
|
p_ap_encode_obj->dirId,
|
|
name,
|
|
fsRdPerm,
|
|
&fileId) != noErr)
|
|
{
|
|
return errFileOpen;
|
|
}
|
|
p_ap_encode_obj->fileId = fileId;
|
|
|
|
|
|
if (!p_ap_encode_obj->text_file_type)
|
|
{
|
|
OSErr err;
|
|
FSSpec file_spec;
|
|
char* path;
|
|
Bool do_magic = true;
|
|
|
|
/* First attempt to get the file's mime type via FE_FileType.
|
|
If that fails, we'll do a "magic_look"
|
|
*/
|
|
|
|
err = FSMakeFSSpec(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId, name, &file_spec);
|
|
if (err == noErr)
|
|
{
|
|
path = my_PathnameFromFSSpec(&file_spec);
|
|
if (path != NULL)
|
|
{
|
|
char* ignore;
|
|
FE_FileType(path, &do_magic, &magic_type, &ignore);
|
|
|
|
/*
|
|
if we ended up with the default type, dispose of it
|
|
so we can do a magic_look
|
|
*/
|
|
|
|
if (do_magic && magic_type)
|
|
XP_FREE(magic_type);
|
|
}
|
|
}
|
|
|
|
if (do_magic)
|
|
{
|
|
/*
|
|
** do a smart check for the file type.
|
|
*/
|
|
in_count = 256;
|
|
retval = FSRead(fileId, &in_count, rd_buff);
|
|
magic_type = magic_look(rd_buff, in_count);
|
|
|
|
/* don't forget to rewind the index to start point. */
|
|
SetFPos(fileId, fsFromStart, 0L);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
magic_type = text_type; /* we already know it is a text type. */
|
|
}
|
|
|
|
/*
|
|
** the data portion header information.
|
|
*/
|
|
XP_SPRINTF(rd_buff,
|
|
"Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\""CRLF CRLF,
|
|
magic_type,
|
|
p_ap_encode_obj->fname,
|
|
p_ap_encode_obj->fname);
|
|
|
|
status = write_stream(p_ap_encode_obj,
|
|
rd_buff,
|
|
XP_STRLEN(rd_buff));
|
|
if (status != noErr)
|
|
return status;
|
|
}
|
|
|
|
while (retval == noErr)
|
|
{
|
|
if (BUFF_LEFT(p_ap_encode_obj) < 400)
|
|
break;
|
|
|
|
in_count = 256;
|
|
retval = FSRead(p_ap_encode_obj->fileId,
|
|
&in_count,
|
|
rd_buff);
|
|
if (in_count)
|
|
{
|
|
/* replace(rd_buff, in_count, '\r', '\n'); */
|
|
/* ** may be need to do character set conversion here for localization. ** */
|
|
status = to64(p_ap_encode_obj,
|
|
rd_buff,
|
|
in_count);
|
|
if (status != noErr)
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (retval == eofErr)
|
|
{
|
|
FSClose(p_ap_encode_obj->fileId);
|
|
|
|
status = finish64(p_ap_encode_obj);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
/* write out the boundary */
|
|
|
|
XP_SPRINTF(rd_buff,
|
|
CRLF"--%s--"CRLF CRLF,
|
|
p_ap_encode_obj->boundary);
|
|
|
|
status = write_stream(p_ap_encode_obj,
|
|
rd_buff,
|
|
XP_STRLEN(rd_buff));
|
|
|
|
if (status == noErr)
|
|
status = errDone;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static char basis_64[] =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
/*
|
|
** convert the stream in the inbuff to 64 format and put it in the out buff.
|
|
** To make the life easier, the caller will responcable of the cheking of the outbuff's bundary.
|
|
*/
|
|
PRIVATE int
|
|
to64(appledouble_encode_object* p_ap_encode_obj,
|
|
char *p,
|
|
int in_size)
|
|
{
|
|
int status;
|
|
int c1, c2, c3, ct;
|
|
unsigned char *inbuff = (unsigned char*)p;
|
|
|
|
ct = p_ap_encode_obj->ct; /* the char count left last time. */
|
|
|
|
/*
|
|
** resume the left state of the last conversion.
|
|
*/
|
|
switch (p_ap_encode_obj->state64)
|
|
{
|
|
case 0:
|
|
p_ap_encode_obj->c1 = c1 = *inbuff ++;
|
|
if (--in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->state64 = 1;
|
|
return noErr;
|
|
}
|
|
p_ap_encode_obj->c2 = c2 = *inbuff ++;
|
|
if (--in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->state64 = 2;
|
|
return noErr;
|
|
}
|
|
c3 = *inbuff ++; --in_size;
|
|
break;
|
|
case 1:
|
|
c1 = p_ap_encode_obj->c1;
|
|
p_ap_encode_obj->c2 = c2 = *inbuff ++;
|
|
if (--in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->state64 = 2;
|
|
return noErr;
|
|
}
|
|
c3 = *inbuff ++; --in_size;
|
|
break;
|
|
case 2:
|
|
c1 = p_ap_encode_obj->c1;
|
|
c2 = p_ap_encode_obj->c2;
|
|
c3 = *inbuff ++; --in_size;
|
|
break;
|
|
}
|
|
|
|
while (in_size >= 0)
|
|
{
|
|
status = output64chunk(p_ap_encode_obj,
|
|
c1,
|
|
c2,
|
|
c3,
|
|
0);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
ct += 4;
|
|
if (ct > 71)
|
|
{
|
|
status = write_stream(p_ap_encode_obj,
|
|
CRLF,
|
|
2);
|
|
if (status != noErr)
|
|
return status;
|
|
|
|
ct = 0;
|
|
}
|
|
|
|
if (in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->state64 = 0;
|
|
break;
|
|
}
|
|
|
|
c1 = (int)*inbuff++;
|
|
if (--in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->c1 = c1;
|
|
p_ap_encode_obj->state64 = 1;
|
|
break;
|
|
}
|
|
c2 = *inbuff++;
|
|
if (--in_size <= 0)
|
|
{
|
|
p_ap_encode_obj->c1 = c1;
|
|
p_ap_encode_obj->c2 = c2;
|
|
p_ap_encode_obj->state64 = 2;
|
|
break;
|
|
}
|
|
c3 = *inbuff++;
|
|
in_size--;
|
|
}
|
|
p_ap_encode_obj->ct = ct;
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
** clear the left base64 encodes.
|
|
*/
|
|
PRIVATE int
|
|
finish64(appledouble_encode_object* p_ap_encode_obj)
|
|
{
|
|
int status;
|
|
|
|
switch (p_ap_encode_obj->state64)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
status = output64chunk(p_ap_encode_obj,
|
|
p_ap_encode_obj->c1,
|
|
0,
|
|
0,
|
|
2);
|
|
break;
|
|
case 2:
|
|
status = output64chunk(p_ap_encode_obj,
|
|
p_ap_encode_obj->c1,
|
|
p_ap_encode_obj->c2,
|
|
0,
|
|
1);
|
|
break;
|
|
}
|
|
status = write_stream(p_ap_encode_obj, CRLF, 2);
|
|
p_ap_encode_obj->state64 = 0;
|
|
p_ap_encode_obj->ct = 0;
|
|
return status;
|
|
}
|
|
|
|
PRIVATE int output64chunk(
|
|
appledouble_encode_object* p_ap_encode_obj,
|
|
int c1, int c2, int c3, int pads)
|
|
{
|
|
char tmpstr[32];
|
|
char *p = tmpstr;
|
|
|
|
*p++ = basis_64[c1>>2];
|
|
*p++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
|
if (pads == 2)
|
|
{
|
|
*p++ = '=';
|
|
*p++ = '=';
|
|
}
|
|
else if (pads)
|
|
{
|
|
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
|
*p++ = '=';
|
|
}
|
|
else
|
|
{
|
|
*p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
|
*p++ = basis_64[c3 & 0x3F];
|
|
}
|
|
return write_stream(p_ap_encode_obj,
|
|
tmpstr,
|
|
p-tmpstr);
|
|
}
|
|
|
|
#endif /* if define XP_MAC */
|