зеркало из https://github.com/mozilla/pjs.git
459 строки
11 KiB
C++
459 строки
11 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
*/
|
|
|
|
#include "nscore.h"
|
|
#include "nsString.h"
|
|
#include "nsCRT.h"
|
|
#include "nsImportMimeEncode.h"
|
|
|
|
#include "ImportCharSet.h"
|
|
#include "ImportTranslate.h"
|
|
|
|
#define kNoState 0
|
|
#define kStartState 1
|
|
#define kEncodeState 2
|
|
#define kDoneState 3
|
|
|
|
#define kEncodeBufferSz (8192 * 8)
|
|
|
|
nsImportMimeEncode::nsImportMimeEncode()
|
|
{
|
|
m_pOut = nsnull;
|
|
m_state = kNoState;
|
|
m_bytesProcessed = 0;
|
|
m_pInputBuf = nsnull;
|
|
m_pMimeFile = nsnull;
|
|
}
|
|
|
|
nsImportMimeEncode::~nsImportMimeEncode()
|
|
{
|
|
NS_IF_RELEASE( m_pMimeFile);
|
|
if (m_pInputBuf)
|
|
delete [] m_pInputBuf;
|
|
}
|
|
|
|
void nsImportMimeEncode::EncodeFile( nsIFileSpec *pInFile, ImportOutFile *pOut, const char *pFileName, const char *pMimeType)
|
|
{
|
|
m_fileName = pFileName;
|
|
m_mimeType = pMimeType;
|
|
|
|
m_pMimeFile = pInFile;
|
|
NS_IF_ADDREF( m_pMimeFile);
|
|
|
|
m_pOut = pOut;
|
|
m_state = kStartState;
|
|
}
|
|
|
|
void nsImportMimeEncode::CleanUp( void)
|
|
{
|
|
CleanUpEncodeScan();
|
|
}
|
|
|
|
PRBool nsImportMimeEncode::SetUpEncode( void)
|
|
{
|
|
nsCString errStr;
|
|
if (!m_pInputBuf) {
|
|
m_pInputBuf = new PRUint8[kEncodeBufferSz];
|
|
}
|
|
|
|
m_appleSingle = PR_FALSE;
|
|
|
|
#ifdef _MAC_IMPORT_CODE
|
|
// First let's see just what kind of beast we have?
|
|
// For files with only a data fork and a known mime type
|
|
// proceed with normal mime encoding just as on the PC.
|
|
// For unknown mime types and files with both forks,
|
|
// encode as AppleSingle format.
|
|
if (m_filePath.GetMacFileSize( UFileLocation::eResourceFork) || !pMimeType) {
|
|
m_appleSingle = TRUE;
|
|
m_mimeType = "application/applefile";
|
|
}
|
|
#endif
|
|
|
|
if (!InitEncodeScan( m_appleSingle, m_pMimeFile, m_fileName, m_pInputBuf, kEncodeBufferSz)) {
|
|
return( PR_FALSE);
|
|
}
|
|
|
|
m_state = kEncodeState;
|
|
m_lineLen = 0;
|
|
|
|
// Write out the boundary header
|
|
PRBool bResult = PR_TRUE;
|
|
bResult = m_pOut->WriteStr( "Content-type: ");
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( m_mimeType);
|
|
|
|
#ifdef _MAC_IMPORT_CODE
|
|
// include the type an creator here
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( "; x-mac-type=\"");
|
|
U8 hex[8];
|
|
LongToHexBytes( m_filePath.GetFileType(), hex);
|
|
if (bResult)
|
|
bResult = m_pOut->WriteData( hex, 8);
|
|
LongToHexBytes( m_filePath.GetFileCreator(), hex);
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( "\"; x-mac-creator=\"");
|
|
if (bResult)
|
|
bResult = m_pOut->WriteData( hex, 8);
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( "\"");
|
|
#endif
|
|
|
|
/*
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( gMimeTypeFileName);
|
|
*/
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( ";\x0D\x0A");
|
|
|
|
nsCString fName;
|
|
PRBool trans = TranslateFileName( m_fileName, fName);
|
|
if (bResult)
|
|
bResult = WriteFileName( fName, trans, "name");
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( "Content-transfer-encoding: base64");
|
|
if (bResult)
|
|
bResult = m_pOut->WriteEol();
|
|
if (bResult)
|
|
bResult = m_pOut->WriteStr( "Content-Disposition: attachment;\x0D\x0A");
|
|
if (bResult)
|
|
bResult = WriteFileName( fName, trans, "filename");
|
|
if (bResult)
|
|
bResult = m_pOut->WriteEol();
|
|
|
|
if (!bResult) {
|
|
CleanUp();
|
|
}
|
|
|
|
return( bResult);
|
|
}
|
|
|
|
PRBool nsImportMimeEncode::DoWork( PRBool *pDone)
|
|
{
|
|
*pDone = PR_FALSE;
|
|
switch( m_state) {
|
|
case kNoState:
|
|
return( PR_FALSE);
|
|
break;
|
|
case kStartState:
|
|
return( SetUpEncode());
|
|
break;
|
|
case kEncodeState:
|
|
if (!Scan( pDone)) {
|
|
CleanUp();
|
|
return( PR_FALSE);
|
|
}
|
|
if (*pDone) {
|
|
*pDone = PR_FALSE;
|
|
m_state = kDoneState;
|
|
}
|
|
break;
|
|
case kDoneState:
|
|
CleanUp();
|
|
m_state = kNoState;
|
|
*pDone = PR_TRUE;
|
|
break;
|
|
}
|
|
|
|
return( PR_TRUE);
|
|
}
|
|
|
|
static PRUint8 gBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
PRBool nsImportMimeEncode::ScanBuffer( PRBool *pDone)
|
|
{
|
|
|
|
PRUint32 pos = m_pos;
|
|
PRUint32 start = pos;
|
|
PRUint8 * pChar = m_pBuf + pos;
|
|
PRUint32 max = m_bytesInBuf;
|
|
PRUint8 byte[4];
|
|
PRUint32 lineLen = m_lineLen;
|
|
|
|
while ((pos + 2) < max) {
|
|
// Encode 3 bytes
|
|
byte[0] = gBase64[*pChar >> 2];
|
|
byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
|
|
pChar++;
|
|
byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
|
|
pChar++;
|
|
byte[3] = gBase64[(*pChar) & 0x3F];
|
|
if (!m_pOut->WriteData( byte, 4))
|
|
return( PR_FALSE);
|
|
pos += 3;
|
|
pChar++;
|
|
lineLen += 4;
|
|
if (lineLen > 71) {
|
|
if (!m_pOut->WriteEol())
|
|
return( PR_FALSE);
|
|
lineLen = 0;
|
|
}
|
|
}
|
|
|
|
if ((pos < max) && m_eof) {
|
|
// Get the last few bytes!
|
|
byte[0] = gBase64[*pChar >> 2];
|
|
pos++;
|
|
if (pos < max) {
|
|
byte[1] = gBase64[(((*pChar) & 0x3)<< 4) | (((*(pChar + 1)) & 0xF0) >> 4)];
|
|
pChar++;
|
|
pos++;
|
|
if (pos < max) {
|
|
// Should be dead code!! (Then why is it here doofus?)
|
|
byte[2] = gBase64[(((*pChar) & 0xF) << 2) | (((*(pChar + 1)) & 0xC0) >>6)];
|
|
pChar++;
|
|
byte[3] = gBase64[(*pChar) & 0x3F];
|
|
pos++;
|
|
}
|
|
else {
|
|
byte[2] = gBase64[(((*pChar) & 0xF) << 2)];
|
|
byte[3] = '=';
|
|
}
|
|
}
|
|
else {
|
|
byte[1] = gBase64[(((*pChar) & 0x3)<< 4)];
|
|
byte[2] = '=';
|
|
byte[3] = '=';
|
|
}
|
|
|
|
if (!m_pOut->WriteData( byte, 4))
|
|
return( PR_FALSE);
|
|
if (!m_pOut->WriteEol())
|
|
return( PR_FALSE);
|
|
}
|
|
else if (m_eof) {
|
|
/*
|
|
byte[0] = '=';
|
|
if (!m_pOut->WriteData( byte, 1))
|
|
return( FALSE);
|
|
*/
|
|
if (!m_pOut->WriteEol())
|
|
return( PR_FALSE);
|
|
}
|
|
|
|
m_lineLen = (int) lineLen;
|
|
m_pos = pos;
|
|
m_bytesProcessed += (pos - start);
|
|
return( PR_TRUE);
|
|
}
|
|
|
|
PRBool nsImportMimeEncode::TranslateFileName( nsCString& inFile, nsCString& outFile)
|
|
{
|
|
const PRUint8 * pIn = (const PRUint8 *) (const char *)inFile;
|
|
int len = inFile.Length();
|
|
|
|
while (len) {
|
|
if (!ImportCharSet::IsUSAscii( *pIn))
|
|
break;
|
|
len--;
|
|
pIn++;
|
|
}
|
|
if (len) {
|
|
// non US ascii!
|
|
// assume this string needs translating...
|
|
if (!ImportTranslate::ConvertString( inFile, outFile, PR_TRUE)) {
|
|
outFile = inFile;
|
|
return( PR_FALSE);
|
|
}
|
|
else {
|
|
return( PR_TRUE);
|
|
}
|
|
}
|
|
else {
|
|
outFile = inFile;
|
|
return( PR_FALSE);
|
|
}
|
|
}
|
|
|
|
PRBool nsImportMimeEncode::WriteFileName( nsCString& fName, PRBool wasTrans, const char *pTag)
|
|
{
|
|
int tagNum = 0;
|
|
int idx = 0;
|
|
PRBool result = PR_TRUE;
|
|
int len;
|
|
nsCString numStr;
|
|
|
|
while ((((fName.Length() - idx) + nsCRT::strlen( pTag)) > 70) && result) {
|
|
len = 68 - nsCRT::strlen( pTag) - 5;
|
|
if (wasTrans) {
|
|
if (fName.CharAt( idx + len - 1) == '%')
|
|
len--;
|
|
else if (fName.CharAt( idx + len - 2) == '%')
|
|
len -= 2;
|
|
}
|
|
|
|
if (result)
|
|
result = m_pOut->WriteStr( "\x09");
|
|
if (result)
|
|
result = m_pOut->WriteStr( pTag);
|
|
numStr = "*";
|
|
numStr.AppendInt( tagNum);
|
|
if (result)
|
|
result = m_pOut->WriteStr( (const char *)numStr);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "*=");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "=\"");
|
|
if (result)
|
|
result = m_pOut->WriteData( ((const PRUint8 *)(const char *)fName) + idx, len);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "\x0D\x0A");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "\"\x0D\x0A");
|
|
idx += len;
|
|
tagNum++;
|
|
}
|
|
|
|
if (idx) {
|
|
if ((fName.Length() - idx) > 0) {
|
|
if (result)
|
|
result = m_pOut->WriteStr( "\x09");
|
|
if (result)
|
|
result = m_pOut->WriteStr( pTag);
|
|
numStr = "*";
|
|
numStr.AppendInt( tagNum);
|
|
if (result)
|
|
result = m_pOut->WriteStr( (const char *)numStr);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "*=");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "=\"");
|
|
if (result)
|
|
result = m_pOut->WriteData( ((const PRUint8 *)(const char *)fName) + idx, fName.Length() - idx);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "\x0D\x0A");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "\"\x0D\x0A");
|
|
}
|
|
}
|
|
else {
|
|
if (result)
|
|
result = m_pOut->WriteStr( "\x09");
|
|
if (result)
|
|
result = m_pOut->WriteStr( pTag);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "*=");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "=\"");
|
|
if (result)
|
|
result = m_pOut->WriteStr( (const char *)fName);
|
|
if (wasTrans && result)
|
|
result = m_pOut->WriteStr( "\x0D\x0A");
|
|
else if (result)
|
|
result = m_pOut->WriteStr( "\"\x0D\x0A");
|
|
}
|
|
|
|
return( result);
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
nsIImportMimeEncodeImpl::nsIImportMimeEncodeImpl()
|
|
{
|
|
m_pOut = nsnull;
|
|
m_pEncode = nsnull;
|
|
|
|
NS_INIT_ISUPPORTS();
|
|
}
|
|
|
|
nsIImportMimeEncodeImpl::~nsIImportMimeEncodeImpl()
|
|
{
|
|
if (m_pOut)
|
|
delete m_pOut;
|
|
if (m_pEncode)
|
|
delete m_pEncode;
|
|
}
|
|
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::Create( nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
|
{
|
|
if (aOuter)
|
|
return NS_ERROR_NO_AGGREGATION;
|
|
|
|
nsIImportMimeEncodeImpl *it = new nsIImportMimeEncodeImpl();
|
|
if (it == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF( it);
|
|
nsresult rv = it->QueryInterface( aIID, aResult);
|
|
NS_RELEASE( it);
|
|
return rv;
|
|
}
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(nsIImportMimeEncodeImpl, NS_GET_IID(nsIImportMimeEncode));
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::EncodeFile(nsIFileSpec *inFile, nsIFileSpec *outFile, const char *fileName, const char *mimeType)
|
|
{
|
|
return( Initialize( inFile, outFile, fileName, mimeType));
|
|
}
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::DoWork(PRBool *done, PRBool *_retval)
|
|
{
|
|
if (done && _retval && m_pEncode) {
|
|
*_retval = m_pEncode->DoWork( done);
|
|
return( NS_OK);
|
|
}
|
|
else
|
|
return( NS_ERROR_FAILURE);
|
|
}
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::NumBytesProcessed(PRInt32 *_retval)
|
|
{
|
|
if (m_pEncode && _retval)
|
|
*_retval = m_pEncode->NumBytesProcessed();
|
|
return( NS_OK);
|
|
}
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::DoEncoding(PRBool *_retval)
|
|
{
|
|
if (_retval && m_pEncode) {
|
|
PRBool done = PR_FALSE;
|
|
while (m_pEncode->DoWork( &done) && !done);
|
|
*_retval = done;
|
|
return( NS_OK);
|
|
}
|
|
else
|
|
return( NS_ERROR_FAILURE);
|
|
}
|
|
|
|
NS_METHOD nsIImportMimeEncodeImpl::Initialize(nsIFileSpec *inFile, nsIFileSpec *outFile, const char *fileName, const char *mimeType)
|
|
{
|
|
if (m_pEncode)
|
|
delete m_pEncode;
|
|
if (m_pOut)
|
|
delete m_pOut;
|
|
|
|
m_pOut = new ImportOutFile();
|
|
m_pOut->InitOutFile( outFile);
|
|
|
|
m_pEncode = new nsImportMimeEncode();
|
|
m_pEncode->EncodeFile( inFile, m_pOut, fileName, mimeType);
|
|
|
|
return( NS_OK);
|
|
}
|
|
|