Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nscore.h"
#include "nsString.h"
#include "prio.h"
#include "nsNetUtil.h"
#include "nsISeekableStream.h"
#include "nsMsgUtils.h"
#include "ImportOutFile.h"
#include "ImportCharSet.h"
#include "ImportDebug.h"
/*
#ifdef _MAC
#define kMacNoCreator '????'
#define kMacTextFile 'TEXT'
#else
#define kMacNoCreator 0
#define kMacTextFile 0
#endif
*/
ImportOutFile::ImportOutFile() {
m_ownsFileAndBuffer = false;
m_pos = 0;
m_pBuf = nullptr;
m_bufSz = 0;
m_pTrans = nullptr;
m_pTransOut = nullptr;
m_pTransBuf = nullptr;
}
ImportOutFile::ImportOutFile(nsIFile* pFile, uint8_t* pBuf, uint32_t sz) {
m_pTransBuf = nullptr;
m_pTransOut = nullptr;
m_pTrans = nullptr;
m_ownsFileAndBuffer = false;
InitOutFile(pFile, pBuf, sz);
}
ImportOutFile::~ImportOutFile() {
if (m_ownsFileAndBuffer) {
Flush();
delete[] m_pBuf;
}
delete m_pTrans;
delete m_pTransOut;
delete[] m_pTransBuf;
}
bool ImportOutFile::Set8bitTranslator(nsImportTranslator* pTrans) {
if (!Flush()) return false;
m_engaged = false;
m_pTrans = pTrans;
m_supports8to7 = pTrans->Supports8bitEncoding();
return true;
}
bool ImportOutFile::End8bitTranslation(bool* pEngaged, nsCString& useCharset,
nsCString& encoding) {
if (!m_pTrans) return false;
bool bResult = Flush();
if (m_supports8to7 && m_pTransOut) {
if (bResult) bResult = m_pTrans->FinishConvertToFile(m_pTransOut);
if (bResult) bResult = Flush();
}
if (m_supports8to7) {
m_pTrans->GetCharset(useCharset);
m_pTrans->GetEncoding(encoding);
} else
useCharset.Truncate();
*pEngaged = m_engaged;
delete m_pTrans;
m_pTrans = nullptr;
delete m_pTransOut;
m_pTransOut = nullptr;
delete[] m_pTransBuf;
m_pTransBuf = nullptr;
return bResult;
}
bool ImportOutFile::InitOutFile(nsIFile* pFile, uint32_t bufSz) {
if (!bufSz) bufSz = 32 * 1024;
if (!m_pBuf) m_pBuf = new uint8_t[bufSz];
if (!m_outputStream) {
nsresult rv;
rv = MsgNewBufferedFileOutputStream(
getter_AddRefs(m_outputStream), pFile,
PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, 0644);
if (NS_FAILED(rv)) {
IMPORT_LOG0("Couldn't create outfile\n");
delete[] m_pBuf;
m_pBuf = nullptr;
return false;
}
}
m_pFile = pFile;
m_ownsFileAndBuffer = true;
m_pos = 0;
m_bufSz = bufSz;
return true;
}
void ImportOutFile::InitOutFile(nsIFile* pFile, uint8_t* pBuf, uint32_t sz) {
m_ownsFileAndBuffer = false;
m_pFile = pFile;
m_pBuf = pBuf;
m_bufSz = sz;
m_pos = 0;
}
bool ImportOutFile::Flush(void) {
if (!m_pos) return true;
uint32_t transLen;
bool duddleyDoWrite = false;
// handle translations if appropriate
if (m_pTrans) {
if (m_engaged && m_supports8to7) {
// Markers can get confused by this crap!!!
// TLR: FIXME: Need to update the markers based on
// the difference between the translated len and untranslated len
if (!m_pTrans->ConvertToFile(m_pBuf, m_pos, m_pTransOut, &transLen))
return false;
if (!m_pTransOut->Flush()) return false;
// now update our buffer...
if (transLen < m_pos) {
memcpy(m_pBuf, m_pBuf + transLen, m_pos - transLen);
}
m_pos -= transLen;
} else if (m_engaged) {
// does not actually support translation!
duddleyDoWrite = true;
} else {
// should we engage?
uint8_t* pChar = m_pBuf;
uint32_t len = m_pos;
while (len) {
if (!ImportCharSet::IsUSAscii(*pChar)) break;
pChar++;
len--;
}
if (len) {
m_engaged = true;
if (m_supports8to7) {
// allocate our translation output buffer and file...
m_pTransBuf = new uint8_t[m_bufSz];
m_pTransOut = new ImportOutFile(m_pFile, m_pTransBuf, m_bufSz);
return Flush();
} else
duddleyDoWrite = true;
} else {
duddleyDoWrite = true;
}
}
} else
duddleyDoWrite = true;
if (duddleyDoWrite) {
uint32_t written = 0;
nsresult rv =
m_outputStream->Write((const char*)m_pBuf, (int32_t)m_pos, &written);
if (NS_FAILED(rv) || ((uint32_t)written != m_pos)) return false;
m_pos = 0;
}
return true;
}
bool ImportOutFile::WriteU8NullTerm(const uint8_t* pSrc, bool includeNull) {
while (*pSrc) {
if (m_pos >= m_bufSz) {
if (!Flush()) return false;
}
*(m_pBuf + m_pos) = *pSrc;
m_pos++;
pSrc++;
}
if (includeNull) {
if (m_pos >= m_bufSz) {
if (!Flush()) return false;
}
*(m_pBuf + m_pos) = 0;
m_pos++;
}
return true;
}
bool ImportOutFile::SetMarker(int markerID) {
if (!Flush()) {
return false;
}
if (markerID < kMaxMarkers) {
int64_t pos = 0;
if (m_outputStream) {
// do we need to flush for the seek to give us the right pos?
m_outputStream->Flush();
nsresult rv;
nsCOMPtr<nsISeekableStream> seekStream =
do_QueryInterface(m_outputStream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Tell(&pos);
if (NS_FAILED(rv)) {
IMPORT_LOG0("*** Error, Tell failed on output stream\n");
return false;
}
}
m_markers[markerID] = (uint32_t)pos + m_pos;
}
return true;
}
void ImportOutFile::ClearMarker(int markerID) {
if (markerID < kMaxMarkers) m_markers[markerID] = 0;
}
bool ImportOutFile::WriteStrAtMarker(int markerID, const char* pStr) {
if (markerID >= kMaxMarkers) return false;
if (!Flush()) return false;
int64_t pos;
m_outputStream->Flush();
nsresult rv;
nsCOMPtr<nsISeekableStream> seekStream =
do_QueryInterface(m_outputStream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Tell(&pos);
if (NS_FAILED(rv)) return false;
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET,
(int32_t)m_markers[markerID]);
if (NS_FAILED(rv)) return false;
uint32_t written;
rv = m_outputStream->Write(pStr, strlen(pStr), &written);
if (NS_FAILED(rv)) return false;
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, pos);
if (NS_FAILED(rv)) return false;
return true;
}