mirror of
https://github.com/voiceip/tinyphone
synced 2026-08-07 02:26:03 -04:00
1114 lines
39 KiB
C++
1114 lines
39 KiB
C++
// StdioFileEx.cpp: implementation of the CStdioFileEx class.
|
||
//
|
||
// Version 1.1 23 August 2003. Incorporated fixes from Dennis Jeryd.
|
||
// Version 1.3 19 February 2005. Incorporated fixes from Howard J Oh and some of my own.
|
||
// Version 1.4 26 February 2005. Fixed stupid screw-up in code from 1.3.
|
||
// Version 1.5 18 November 2005. - Incorporated fixes from Andy Goodwin.
|
||
// - Allows code page to be specified for reading/writing
|
||
// - Properly calculates multibyte buffer size instead of
|
||
// assuming lstrlen(s).
|
||
// - Should handle UTF8 properly.
|
||
// Version 1.6 19 July 2007. - ReadString incorrectly removed \r or \n characters
|
||
// immediately preceding line breaks.
|
||
// Fixed tab problem in these comments! (Perry).
|
||
// Made GetMultiByteStringFromUnicodeString input string const
|
||
// (Perry).
|
||
// Avoided double conversion if code page not set.
|
||
// (Konrad Windszus).
|
||
// Fixed ASSERT in GetUnicodeStringFromMultiByteString
|
||
// (Konrad Windszus).
|
||
// Maximum line length restriction removed. Lines of any length
|
||
// can now be read thanks to C.B. Falconer's fggets (fgoodgets),
|
||
// ably assisted by Ana Sayfa and Dave Kondrad.
|
||
// Substantial code reorganisation and tidying.
|
||
// Use of strlen/lstrlen eliminated. Conversion functions always used
|
||
// to calculate required buffers.
|
||
// Serious, systematic tests are now included with the code.
|
||
// Options included to switch off BOM writing and alter the Unicode
|
||
// filler char.
|
||
// BOM is only stripped off if actually there.
|
||
// UTF-8 BOM is now read and written. UTF-8 conversion works.
|
||
//
|
||
// Copyright David Pritchard 2003-2007. davidpritchard@ctv.es
|
||
//
|
||
// You can use this class freely, but please keep my ego happy
|
||
// by leaving this comment in place.
|
||
//
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
#include "stdafx.h"
|
||
#include "StdioFileEx.h"
|
||
#include "ggets.h"
|
||
|
||
#ifdef _DEBUG
|
||
#undef THIS_FILE
|
||
static char THIS_FILE[] = __FILE__;
|
||
#define new DEBUG_NEW
|
||
#endif
|
||
|
||
const unsigned char UTF8_BOM[] = { unsigned char(0xEF), unsigned char(0xBB), unsigned char(0xBF) };
|
||
|
||
//////////////////////////////////////////////////////////////////////
|
||
// Construction/Destruction
|
||
//////////////////////////////////////////////////////////////////////
|
||
|
||
// Add this flag to write in Unicode. For the moment, out of range of all the Visual Studio 2005 flags
|
||
/*static*/ const UINT CStdioFileEx::modeWriteUnicode = 0x200000;
|
||
|
||
CStdioFileEx::CStdioFileEx() :
|
||
m_bCheckFilePos(true),
|
||
m_bIsUnicodeText(false),
|
||
m_nFileCodePage(-1),
|
||
m_cUnicodeFillerChar(sDEFAULT_UNICODE_FILLER_CHAR),
|
||
m_bWriteBOM(true), // By default, write the BOM
|
||
CStdioFile()
|
||
{
|
||
}
|
||
|
||
// Set the code page for reading/writing
|
||
void CStdioFileEx::SetCodePage(IN const UINT nCodePage)
|
||
{
|
||
m_nFileCodePage = (int)nCodePage;
|
||
}
|
||
|
||
// Set the Unicode filler char - the char written when no conversion is possible for the target multibyte char set
|
||
void CStdioFileEx::SetFillerChar(IN const char cFiller)
|
||
{
|
||
m_cUnicodeFillerChar = cFiller;
|
||
}
|
||
|
||
// Determines whether the byte-order-mark is written at the start of a Unicode file
|
||
void CStdioFileEx::SetWriteBOM(IN const bool bWrite)
|
||
{
|
||
m_bWriteBOM = bWrite;
|
||
}
|
||
|
||
// Determines whether we try to interpret this file as Unicode
|
||
//void CStdioFileEx::SetUnicode(IN const bool bIsUnicode)
|
||
//{
|
||
// m_bIsUnicodeText = bIsUnicode;
|
||
//}
|
||
|
||
BOOL CStdioFileEx::Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError /*=NULL*/)
|
||
{
|
||
// Process any Unicode stuff. This no longer checks for the Unicode BOM. We do this on
|
||
// opening for efficiency.
|
||
ProcessFlags(nOpenFlags);
|
||
|
||
BOOL bOK = CStdioFile::Open(lpszFileName, nOpenFlags, pError);
|
||
|
||
if (bOK)
|
||
{
|
||
// If we are reading, see if it has a BOM. I tried making the Unicode-ness independent of the BOM (i.e. allowed the file to
|
||
// be identified as Unicode by the caller, with the BOM just being used as a check, or thrown away).
|
||
// But for some reason it wouldn't work. I'll no doubt try again at some point.
|
||
// if (!(nOpenFlags & CFile::modeCreate) && (nOpenFlags & CFile::modeRead || nOpenFlags & CFile::modeReadWrite))
|
||
if (!(nOpenFlags & CFile::modeCreate) && !(nOpenFlags & CFile::modeWrite))
|
||
{
|
||
wchar_t cBOMTest;
|
||
wchar_t cBOM = nUNICODE_BOM;
|
||
|
||
Read(&cBOMTest, sizeof(wchar_t));
|
||
// Reset to start of file
|
||
SeekToBegin();
|
||
|
||
// If the first characters are NOT a BOM, reset to start of file
|
||
m_bIsUnicodeText = (wmemcmp(&cBOMTest, &cBOM, 1) == 0);
|
||
if (!m_bIsUnicodeText) {
|
||
char *pChar = (char *)&cBOMTest;
|
||
if (*(pChar + 1) == 0) {
|
||
m_bIsUnicodeText = true;
|
||
}
|
||
}
|
||
m_bCheckFilePos = true;
|
||
}
|
||
}
|
||
|
||
return bOK;
|
||
}
|
||
|
||
BOOL CStdioFileEx::ReadString(CString& rString)
|
||
{
|
||
ASSERT(m_pStream != NULL);
|
||
|
||
BOOL bReadData = FALSE;
|
||
LPTSTR lpsz;
|
||
int nLen = 0;
|
||
|
||
// If at position 0, discard byte-order mark before reading. To optimise reading, we only
|
||
// check this when the m_bCheckFilePos is set (this avoids a call to ftell every time we
|
||
// read a line)
|
||
if (m_bCheckFilePos && GetPosition() == 0)
|
||
{
|
||
m_bReadBOM = false;
|
||
|
||
// Look for Unicode BOM
|
||
if (m_bIsUnicodeText)
|
||
{
|
||
wchar_t cBOMTest;
|
||
wchar_t cBOM = nUNICODE_BOM;
|
||
Read(&cBOMTest, sizeof(wchar_t));
|
||
// If the first characters are NOT a BOM, reset to start of file
|
||
if (wmemcmp(&cBOMTest, &cBOM, 1) != 0)
|
||
{
|
||
SeekToBegin();
|
||
ASSERT(GetPosition() == 0);
|
||
}
|
||
else
|
||
{
|
||
// Set read BOM flag
|
||
m_bReadBOM = true;
|
||
}
|
||
}
|
||
// Look for UTF8 BOM
|
||
else if (CP_UTF8 == m_nFileCodePage)
|
||
{
|
||
BYTE arrUTF8BOMTest[sizeof(UTF8_BOM)];
|
||
Read(arrUTF8BOMTest, sizeof(arrUTF8BOMTest));
|
||
|
||
// If the first characters are NOT a BOM, reset to start of file
|
||
if (memcmp(&arrUTF8BOMTest, UTF8_BOM, sizeof(arrUTF8BOMTest)) != 0)
|
||
{
|
||
SeekToBegin();
|
||
ASSERT(GetPosition() == 0);
|
||
}
|
||
else
|
||
{
|
||
// Set read BOM flag
|
||
m_bReadBOM = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Read Unicode line or multibyte line (implementations
|
||
// differ depending on the compilation)
|
||
if (m_bIsUnicodeText)
|
||
{
|
||
bReadData = ReadUnicodeLine(rString);
|
||
}
|
||
else
|
||
{
|
||
bReadData = ReadMultiByteLine(rString);
|
||
}
|
||
|
||
// Then remove end-of-line character as necessary.
|
||
// fggets keeps the end-of-line confusion level at maximum by stripping the \n
|
||
// from the end of lines, but leaving the \r. Grrrr.
|
||
// Remember that you could quite legitimately have a \r or \n at the end of
|
||
// your line before the actual \r\n line break.
|
||
if (bReadData)
|
||
{
|
||
// Copied from FileTxt.cpp but adapted to use of fgets
|
||
nLen = rString.GetLength();
|
||
|
||
lpsz = rString.GetBuffer(0);
|
||
|
||
// Strip \r from the end
|
||
if (nLen != 0 && (lpsz[nLen - 1] == _T('\r')))
|
||
{
|
||
rString.GetBufferSetLength(nLen - 1);
|
||
}
|
||
|
||
rString.ReleaseBuffer();
|
||
|
||
// Now we've moved on in the file, don't bother to check any more unless the
|
||
// file pointer is moved
|
||
m_bCheckFilePos = false;
|
||
}
|
||
|
||
return bReadData;
|
||
}
|
||
|
||
/*virtual*/ LPTSTR CStdioFileEx::ReadString(LPTSTR lpsz, UINT nMax)
|
||
{
|
||
// Can't really provide compatible behaviour at the moment, so no Unicode handling.
|
||
ASSERT(false);
|
||
|
||
return CStdioFile::ReadString(lpsz, nMax);
|
||
}
|
||
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::WriteString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: void
|
||
// Parameters: LPCTSTR lpsz
|
||
//
|
||
// Purpose: Writes string to file either in Unicode or multibyte, depending on whether the caller specified the
|
||
// CStdioFileEx::modeWriteUnicode flag. Override of base class function.
|
||
// Notes: If writing in Unicode we need to:
|
||
// a) Write the Byte-order-mark at the beginning of the file
|
||
// b) Write all strings in byte-mode
|
||
// - If we were compiled in Unicode, we need to convert Unicode to multibyte if
|
||
// we want to write in multibyte
|
||
// - If we were compiled in multi-byte, we need to convert multibyte to Unicode if
|
||
// we want to write in Unicode.
|
||
// Exceptions: None.
|
||
//
|
||
void CStdioFileEx::WriteString(LPCTSTR lpsz)
|
||
{
|
||
// Write Byte Order Mark if needed
|
||
if (m_bWriteBOM && (!m_pStream || GetPosition() == 0))
|
||
{
|
||
// If writing Unicode and at the start of the file, need to write byte mark
|
||
if (m_nFlags & CStdioFileEx::modeWriteUnicode)
|
||
{
|
||
// If at position 0, write byte-order mark before writing anything else
|
||
wchar_t cBOM = (wchar_t)nUNICODE_BOM;
|
||
CFile::Write(&cBOM, sizeof(wchar_t));
|
||
}
|
||
// Fix by philfar
|
||
// http://www.codeproject.com/file/stdiofileex.asp?forumid=15472&select=1805024&df=100#xx1805024xx
|
||
// otherwise, if we are writing UTF-8 and at the start of the file, need to write UTF-8 byte mark
|
||
else if (m_nFileCodePage == CP_UTF8)
|
||
{
|
||
// If at position 0, write byte-order mark before writing anything else
|
||
CFile::Write(UTF8_BOM, sizeof(UTF8_BOM));
|
||
}
|
||
}
|
||
|
||
// If writing Unicode...
|
||
if (m_nFlags & CStdioFileEx::modeWriteUnicode)
|
||
{
|
||
WriteUnicodeLine(lpsz);
|
||
}
|
||
// Else write multibyte/ANSI
|
||
else
|
||
{
|
||
WriteMultiByteLine(lpsz);
|
||
}
|
||
}
|
||
|
||
UINT CStdioFileEx::ProcessFlags(UINT& nOpenFlags)
|
||
{
|
||
m_bIsUnicodeText = false;
|
||
|
||
// If we have writeUnicode we must have write or writeRead as well
|
||
#ifdef _DEBUG
|
||
if (nOpenFlags & CStdioFileEx::modeWriteUnicode)
|
||
{
|
||
ASSERT(nOpenFlags & CFile::modeWrite || nOpenFlags & CFile::modeReadWrite);
|
||
}
|
||
#endif
|
||
|
||
// Konrad Windszus 05/04/2006: handle case of writing to Unicode (obviously always Unicode)
|
||
if (nOpenFlags & CStdioFileEx::modeWriteUnicode)
|
||
{
|
||
m_bIsUnicodeText = true;
|
||
}
|
||
|
||
// Always use binary mode, for any type of writing
|
||
if (nOpenFlags & CFile::typeText)
|
||
{
|
||
nOpenFlags ^= CFile::typeText;
|
||
}
|
||
nOpenFlags |= CFile::typeBinary;
|
||
|
||
m_nFlags = nOpenFlags;
|
||
|
||
return nOpenFlags;
|
||
}
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::IsFileUnicode()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: bool
|
||
// Parameters: const CString& sFilePath
|
||
//
|
||
// Purpose: Determines whether a file is Unicode by reading the first character and detecting
|
||
// whether it's the Unicode byte marker.
|
||
// Notes: None.
|
||
// Exceptions: None.
|
||
//
|
||
/*static*/ bool CStdioFileEx::IsFileUnicode(const CString& sFilePath)
|
||
{
|
||
CFile file;
|
||
bool bIsUnicode = false;
|
||
wchar_t cFirstChar;
|
||
CFileException exFile;
|
||
|
||
// Open file in binary mode and read first character
|
||
if (file.Open(sFilePath, CFile::typeBinary | CFile::modeRead, &exFile))
|
||
{
|
||
// If byte is Unicode byte-order marker, let's say it's Unicode
|
||
if (file.Read(&cFirstChar, sizeof(wchar_t)) > 0 && cFirstChar == (wchar_t)nUNICODE_BOM)
|
||
{
|
||
bIsUnicode = true;
|
||
}
|
||
|
||
file.Close();
|
||
}
|
||
else
|
||
{
|
||
// Handle error here if you like
|
||
}
|
||
|
||
return bIsUnicode;
|
||
}
|
||
|
||
// Rough character count. Likely to be way out for multibyte files using non-western
|
||
// code pages. Anybody got a better method?
|
||
STDIOEXLONG CStdioFileEx::GetCharCount()
|
||
{
|
||
int nCharSize;
|
||
ULONGLONG nByteCount, nCharCount = 0;
|
||
|
||
if (m_pStream)
|
||
{
|
||
// Get size of chars in file
|
||
nCharSize = m_bIsUnicodeText ? sizeof(wchar_t) : sizeof(char);
|
||
|
||
// If Unicode, remove byte order mark from count
|
||
nByteCount = GetLength();
|
||
|
||
if (m_bIsUnicodeText)
|
||
{
|
||
nByteCount = nByteCount - sizeof(wchar_t);
|
||
}
|
||
|
||
// Calc chars
|
||
nCharCount = (nByteCount / nCharSize);
|
||
}
|
||
|
||
return nCharCount;
|
||
}
|
||
|
||
/*virtual*/ STDIOEXLONG CStdioFileEx::Seek(LONGLONG lOff, UINT nFrom)
|
||
{
|
||
// Note that we should check the file position on the next read
|
||
m_bCheckFilePos = true;
|
||
|
||
return CStdioFile::Seek(lOff, nFrom);
|
||
}
|
||
|
||
|
||
// Get the current users code page
|
||
UINT CStdioFileEx::GetCurrentLocaleCodePage()
|
||
{
|
||
_TCHAR szLocalCodePage[10];
|
||
UINT nLocaleCodePage = 0;
|
||
int nLocaleChars = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, szLocalCodePage, 10);
|
||
|
||
// If OK
|
||
if (nLocaleChars > 0)
|
||
{
|
||
nLocaleCodePage = (UINT)_ttoi(szLocalCodePage);
|
||
ASSERT(nLocaleCodePage > 0);
|
||
}
|
||
else
|
||
{
|
||
ASSERT(false);
|
||
}
|
||
|
||
// O means either: no ANSI code page (Unicode-only locale?) or failed to get locale
|
||
// In the case of Unicode-only locales, what do multibyte apps do? Answers on a postcard.
|
||
return nLocaleCodePage;
|
||
}
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetUnicodeStringFromMultiByteString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: int - number of chars written
|
||
// Parameters: LPCSTR szMultiByteString (IN) Multi-byte input string
|
||
// wchar_t* szUnicodeString (OUT) Unicode outputstring
|
||
// size_t nUnicodeBufferSize (IN) Size of Unicode output buffer in chars
|
||
// UINT nCodePage (IN) Code page used to perform conversion
|
||
// Default = CP_ACP (Get local code page).
|
||
//
|
||
// Purpose: Gets a Unicode string from a MultiByte string.
|
||
// Notes: None.
|
||
// Exceptions: None.
|
||
//
|
||
int CStdioFileEx::GetUnicodeStringFromMultiByteString(IN LPCSTR szMultiByteString, OUT wchar_t* szUnicodeString, IN const size_t nUnicodeBufferSize, IN UINT nCodePage)
|
||
{
|
||
int nCharsWritten = 0;
|
||
|
||
if (szUnicodeString && szMultiByteString)
|
||
{
|
||
// If no code page specified, take default for system
|
||
if (nCodePage == (UINT)-1)
|
||
{
|
||
nCodePage = GetACP();
|
||
}
|
||
|
||
try
|
||
{
|
||
// Zero out buffer first
|
||
memset((void*)szUnicodeString, '\0', sizeof(wchar_t) * nUnicodeBufferSize);
|
||
|
||
// When converting to UTF8, don't set any flags (see Q175392).
|
||
nCharsWritten = MultiByteToWideChar((UINT)nCodePage, (nCodePage == CP_UTF8 ?
|
||
0 : MB_PRECOMPOSED), szMultiByteString, -1, szUnicodeString, (int)nUnicodeBufferSize);
|
||
}
|
||
catch (...)
|
||
{
|
||
// Level 4 compile says this is unreachable code in VS2005. I guess MultiByteToWideChar doesn't throw exceptions.
|
||
// TRACE(_T("Controlled exception in MultiByteToWideChar!\n"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERT(false);
|
||
}
|
||
|
||
// Konrad Windszus 29/3/2006: ASSERT in wrong place!
|
||
// Should have at least the terminator (right?)
|
||
ASSERT(nCharsWritten > 0);
|
||
|
||
// Now fix nCharsWritten to exclude \0 terminator
|
||
if (nCharsWritten > 0)
|
||
{
|
||
nCharsWritten--;
|
||
}
|
||
|
||
return nCharsWritten;
|
||
}
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetRequiredUnicodeLengthFromMultiByteString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: int - number of chars needed
|
||
// Parameters: LPCSTR szMultiByteString (IN) Multi-byte input string
|
||
// UINT nCodePage (IN) Code page of input string
|
||
// Default = CP_ACP (local code page).
|
||
//
|
||
// Purpose: Gets the length required, in wchar_t values (chars) to convert a MultiByte string to a Unicode string.
|
||
// Notes: None.
|
||
// Exceptions: None.
|
||
//
|
||
/*static*/ int CStdioFileEx::GetRequiredUnicodeLengthFromMultiByteString(IN LPCSTR szMultiByteString, IN UINT nCodePage /*=CP_ACP OPTIONAL*/)
|
||
{
|
||
int nCharsNeeded = 0;
|
||
|
||
if (szMultiByteString)
|
||
{
|
||
// If no code page specified, take default for system
|
||
if (nCodePage == (UINT)-1)
|
||
{
|
||
nCodePage = GetACP();
|
||
}
|
||
|
||
try
|
||
{
|
||
// When converting to UTF8, don't set any flags (see Q175392).
|
||
nCharsNeeded = MultiByteToWideChar((UINT)nCodePage, (nCodePage == CP_UTF8 ?
|
||
0 : MB_PRECOMPOSED),
|
||
szMultiByteString,
|
||
-1, // Get the function to work out the length
|
||
NULL, // No output buffer needed
|
||
0 // Ask to be told how many chars we need (includes space for terminator)
|
||
);
|
||
}
|
||
catch (...)
|
||
{
|
||
// Level 4 compile says this is unreachable code in VS2005. I guess MultiByteToWideChar doesn't throw exceptions.
|
||
// TRACE(_T("Controlled exception in MultiByteToWideChar!\n"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERT(false);
|
||
}
|
||
|
||
// Konrad Windszus 29/3/2006: ASSERT in wrong place!
|
||
// Should have at least the terminator (right?). The value returned by MultiByteToWideChar includes the terminator.
|
||
ASSERT(nCharsNeeded > 0);
|
||
|
||
return nCharsNeeded;
|
||
}
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetNewUnicodeStringFromMultiByteString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: int - number of chars written (0 means error)
|
||
// Parameters: LPCSTR szMultiByteString (IN) Multi-byte input string
|
||
// CTemplateSmartPtrArray<wchar_t>&
|
||
// spUnicodeString (IN/OUT) Smart pointer containing default buffer (or NULL)
|
||
// on input, and pointing to buffer used for conversion
|
||
// on output. A newly allocated buffer will be automatically
|
||
// deleted when the smart ptr object is destroyed.
|
||
// This allows a default buffer to be declared and used for
|
||
// most strings. Dynamic allocation is only performed when
|
||
// the default buffer would not be large enough.
|
||
// int nDefaultBufferSize (IN) Size of default buffer in smart ptr (may be 0).
|
||
// UINT nCodePage (IN) Code page used to perform conversion
|
||
// Default = CP_ACP (Get local code page).
|
||
//
|
||
// Purpose: Gets a Unicode string from a MultiByte string. Calculates the buffer for you and
|
||
// allocates it with "new".
|
||
// Notes: It's better to ask this function to allocate the buffer for you, because it will
|
||
// calculate the correct size. If we just take the number of bytes from the multibyte
|
||
// string as the size, we won't be in danger of allocating too little memory, but we
|
||
// may well allocate too much.
|
||
//
|
||
// The use of a smart ptr array combines this flexibility with efficiency. A default buffer can be passed in
|
||
// and used wherever is it sufficient to contain the output string. This avoids lots of unnecessary "new"s and
|
||
// "delete"s when reading or writing large files.
|
||
// Exceptions: None.
|
||
//
|
||
/*static*/ int CStdioFileEx::GetNewUnicodeStringFromMultiByteString(IN LPCSTR szMultiByteString, IN OUT CTemplateSmartPtrArray<wchar_t>& spUnicodeString, IN const int nDefaultBufferSize/*=0*/, IN UINT nCodePage /*=CP_ACP OPTIONAL*/)
|
||
{
|
||
int nActualBufferSize = nDefaultBufferSize;
|
||
|
||
// Calculate the required buffer size and allocate
|
||
int nUnicodeBufferSizeChars = GetRequiredUnicodeLengthFromMultiByteString(szMultiByteString, nCodePage);
|
||
|
||
// If we have enough in the default buffer, don't bother to allocate
|
||
if (nUnicodeBufferSizeChars > nDefaultBufferSize)
|
||
{
|
||
//pszUnicodeString = new wchar_t[nUnicodeBufferSizeChars];
|
||
|
||
// The new buffer will be marked as "owned" by the smart ptr by default, and therefore automatically deleted by the smart ptr
|
||
spUnicodeString.Assign(new wchar_t[nUnicodeBufferSizeChars]);
|
||
|
||
nActualBufferSize = nUnicodeBufferSizeChars;
|
||
}
|
||
|
||
// Call standard
|
||
return GetUnicodeStringFromMultiByteString(szMultiByteString, spUnicodeString.GetBuffer(), nActualBufferSize, nCodePage);
|
||
}
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetMultiByteStringFromUnicodeString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: int - number of chars written. 0 if error.
|
||
// Parameters: wchar_t * szUnicodeString (IN) Unicode input string
|
||
// char* szMultiByteString (OUT) Multibyte output string
|
||
// int nMultiByteBufferSize (IN) Multibyte buffer size
|
||
// UINT nCodePage (IN) Code page used to perform conversion
|
||
// Default = CP_ACP (Get local code page).
|
||
// char cFillerChar (IN) Unicode-to-multibyte filler char
|
||
// Default = #
|
||
//
|
||
// Purpose: Gets a MultiByte string from a Unicode string.
|
||
// Notes: It's better to ask this function to allocate the buffer for you, because it will
|
||
// calculate the correct size. Multibyte code pages will require larger buffers than
|
||
// the normal Western code pages, so we can't just say new char[numchars]!
|
||
// Exceptions: None.
|
||
//
|
||
int CStdioFileEx::GetMultiByteStringFromUnicodeString(IN const wchar_t * szUnicodeString, OUT char* szMultiByteString,
|
||
IN const int nMultiByteBufferSize, IN UINT nCodePage/*=CP_ACP OPTIONAL*/,
|
||
IN char cFillerChar/*=sDEFAULT_UNICODE_FILLER_CHAR OPTIONAL*/)
|
||
{
|
||
BOOL bUsedDefChar = FALSE;
|
||
int nBytesWritten = 0;
|
||
|
||
// Fix by Andy Goodwin: don't do anything if buffer is 0
|
||
if (nMultiByteBufferSize > 0)
|
||
{
|
||
if (szUnicodeString && szMultiByteString)
|
||
{
|
||
// Zero out buffer first
|
||
memset((void*)szMultiByteString, '\0', sizeof(char) * nMultiByteBufferSize);
|
||
|
||
// If no code page specified, take default for system
|
||
if (nCodePage == (UINT)-1)
|
||
{
|
||
nCodePage = (UINT)GetACP();
|
||
}
|
||
|
||
try
|
||
{
|
||
// If writing to UTF8, flags, default char and boolean flag must be NULL
|
||
nBytesWritten = WideCharToMultiByte((UINT)nCodePage,
|
||
(nCodePage == CP_UTF8 ? 0 : WC_COMPOSITECHECK | WC_SEPCHARS), // Flags
|
||
szUnicodeString, -1,
|
||
szMultiByteString,
|
||
nMultiByteBufferSize,
|
||
(nCodePage == CP_UTF8 ? NULL : &cFillerChar), // Filler char
|
||
(nCodePage == CP_UTF8 ? NULL : &bUsedDefChar)); // Did we use filler char?
|
||
|
||
// If no chars were written and the buffer is not 0, error!
|
||
if (nBytesWritten == 0 && nMultiByteBufferSize > 0)
|
||
{
|
||
TRACE1("Error in WideCharToMultiByte: %d\n", ::GetLastError());
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
TRACE0("Controlled exception in WideCharToMultiByte!\n");
|
||
}
|
||
}
|
||
}
|
||
|
||
// Now fix nCharsWritten to exclude \0 terminator
|
||
if (nBytesWritten > 0)
|
||
{
|
||
nBytesWritten = nBytesWritten - sizeof('\0');
|
||
}
|
||
|
||
return nBytesWritten;
|
||
}
|
||
|
||
|
||
|
||
//---------------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetRequiredMultiByteLengthForUnicodeString()
|
||
//
|
||
//---------------------------------------------------------------------------------------------------
|
||
// Returns: int - no of bytes required
|
||
// Parameters: wchar_t * szUnicodeString (IN) String to convert
|
||
// UINT nCodePage=CP_ACP (IN) Code page to which to convert
|
||
//
|
||
// Purpose: Obtains the multi-byte buffer size (in bytes) needed to accommodate a converted Unicode string.
|
||
// Notes: We can't assume that the buffer length is simply equal to the number of characters
|
||
// because that wouldn't accommodate multibyte characters!
|
||
//
|
||
/*static*/ int CStdioFileEx::GetRequiredMultiByteLengthForUnicodeString(IN const wchar_t * szUnicodeString, IN UINT nCodePage /*=CP_ACP OPTIONAL*/)
|
||
{
|
||
int nBytesNeeded = 0;
|
||
|
||
try
|
||
{
|
||
// If no code page specified, take default for system
|
||
if (nCodePage == -1)
|
||
{
|
||
nCodePage = GetACP();
|
||
}
|
||
|
||
// If writing to UTF8, flags, default char and boolean flag must be NULL
|
||
nBytesNeeded = WideCharToMultiByte((UINT)nCodePage,
|
||
(nCodePage == CP_UTF8 ? 0 : WC_COMPOSITECHECK | WC_SEPCHARS), // Flags
|
||
szUnicodeString, -1,
|
||
NULL,
|
||
0, // Calculate required buffer, please! (Includes space for terminator)
|
||
NULL, // Filler char doesn't matter here
|
||
NULL);
|
||
}
|
||
catch (...)
|
||
{
|
||
// TRACE(_T("Controlled exception in WideCharToMultiByte!\n"));
|
||
// Gives us "unreachable code" error compiling on level 4
|
||
}
|
||
|
||
return nBytesNeeded;
|
||
}
|
||
|
||
|
||
// --------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetNewMultiByteStringFromUnicodeString()
|
||
//
|
||
// --------------------------------------------------------------------------------------------
|
||
// Returns: int - number of chars written. 0 if error.
|
||
// Parameters: wchar_t * szUnicodeString (IN) Unicode input string
|
||
// CTemplateSmartPtrArray<char>&
|
||
// spMultiByteString (IN/OUT) Smart pointer containing default buffer (or NULL)
|
||
// on input, and pointing to buffer used for conversion
|
||
// on output. A newly allocated buffer will be automatically
|
||
// deleted when the smart ptr object is destroyed.
|
||
// This allows a default buffer to be declared and used for
|
||
// most strings. Dynamic allocation is only performed when
|
||
// the default buffer would not be large enough.
|
||
// int nDefaultBufferSize (IN) Size of default buffer in smart ptr (may be 0).
|
||
// UINT nCodePage (IN) Code page used to perform conversion
|
||
// Default = CP_ACP (Get local code page).
|
||
// char cFillerChar (IN) Unicode-to-multibyte filler char
|
||
// Default = #
|
||
//
|
||
// Purpose: Gets a MultiByte string from a Unicode string. Calculates the buffer for you and
|
||
// allocates it with new.
|
||
// Notes: It's better to ask this function to allocate the buffer for you, because it will
|
||
// calculate the correct size. Multibyte code pages will require larger buffers than
|
||
// the normal Western code pages, so we can't just say new char[numchars]!
|
||
//
|
||
// The use of a smart ptr array combines this flexibility with efficiency. A default buffer can be passed in
|
||
// and used wherever is it sufficient to contain the output string. This avoids lots of unnecessary "new"s and
|
||
// "delete"s when reading or writing large files.
|
||
// Exceptions: None.
|
||
//
|
||
/*static*/ int CStdioFileEx::GetNewMultiByteStringFromUnicodeString(IN const wchar_t * szUnicodeString, IN OUT CTemplateSmartPtrArray<char>& spMultiByteString, IN const int nDefaultBufferSize/*=0*/,
|
||
IN UINT nCodePage /*=CP_ACP OPTIONAL*/, IN char cFillerChar/*=sDEFAULT_UNICODE_FILLER_CHAR OPTIONAL*/)
|
||
{
|
||
int nActualBufferSize = nDefaultBufferSize;
|
||
|
||
// Calculate the required buffer size and allocate
|
||
int nMultibyteBufferSizeBytes = GetRequiredMultiByteLengthForUnicodeString(szUnicodeString, nCodePage);
|
||
|
||
// If we have enough in the default buffer, don't bother to allocate
|
||
if (nMultibyteBufferSizeBytes > nDefaultBufferSize)
|
||
{
|
||
// The new buffer will be marked as "owned" by the smart ptr by default, and therefore automatically deleted by the smart ptr
|
||
spMultiByteString.Assign(new char[nMultibyteBufferSizeBytes]);
|
||
|
||
nActualBufferSize = nMultibyteBufferSizeBytes;
|
||
}
|
||
|
||
// Call standard
|
||
return GetMultiByteStringFromUnicodeString(szUnicodeString, spMultiByteString.GetBuffer(), nActualBufferSize, nCodePage, cFillerChar);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------------------------------
|
||
//
|
||
// CStdioFileEx::GetNewUTF8StringFromUnicodeString()
|
||
//
|
||
//---------------------------------------------------------------------------------------------------
|
||
// Returns: bool - true if successful, false if it fails.
|
||
// Parameters: const wchar_t* szUnicodeString (IN) Input Unicode string
|
||
// unsigned char*& pszUTF8String (OUT) Receives a ptr. If the function returns
|
||
// successfully.
|
||
// the ptr points to the output string
|
||
//
|
||
// Purpose: Does conversion from Unicode to UTF8. Allocates memory for the output string
|
||
// Notes: Culled from http://www.bytemycode.com/snippets/snippet/438/
|
||
// Contributed by Dean
|
||
//
|
||
/*static*/ /*bool CStdioFileEx::GetNewUTF8StringFromUnicodeString( IN const wchar_t* szUnicodeString, OUT unsigned char*& pszUTF8String )
|
||
{
|
||
bool bConvertedOK = false;
|
||
const wchar_t* w;
|
||
|
||
// Calculate length needed for output string, taking account
|
||
// of the variable number of bytes needed to represent each
|
||
// Unicode character in UTF8
|
||
int len = 0;
|
||
for ( w = szUnicodeString; *w; w++ )
|
||
{
|
||
if ( *w < 0հ080 ) len++;
|
||
|
||
else if ( *w < 0հ800 ) len += 2;
|
||
|
||
else len += 3;
|
||
}
|
||
|
||
//unsigned char* szOut = ( unsigned char* )malloc( len+1 );
|
||
pszUTF8String = new char[len+1];
|
||
|
||
if ( pszUTF8String != NULL )
|
||
{
|
||
int i = 0;
|
||
|
||
for ( w = szUnicodeString; *w; w++ )
|
||
{
|
||
// Handle ASCII chars
|
||
if ( *w < 0հ080 )
|
||
{
|
||
pszUTF8String[i++] = ( char ) *w;
|
||
}
|
||
else if ( *w < 0հ800 )
|
||
{
|
||
pszUTF8String[i++] = 0xc0 | (( *w ) >> 6 );
|
||
pszUTF8String[i++] = 0ո0 | (( *w ) & 0ճf );
|
||
}
|
||
else
|
||
{
|
||
pszUTF8String[i++] = 0xe0 | (( *w ) >> 12 );
|
||
pszUTF8String[i++] = 0ո0 | (( ( *w ) >> 6 ) & 0ճf );
|
||
pszUTF8String[i++] = 0ո0 | (( *w ) & 0ճf );
|
||
}
|
||
}
|
||
|
||
pszUTF8String[ i ] = \0;
|
||
|
||
bConvertedOK = true;
|
||
}
|
||
|
||
//return ( char* )szOut;
|
||
return bConvertedOK;
|
||
}*/
|
||
|
||
/**********************************************************************************/
|
||
/* Reading */
|
||
/**********************************************************************************/
|
||
#ifdef _UNICODE
|
||
// Read Unicode in Unicode compilation
|
||
BOOL CStdioFileEx::ReadUnicodeLine(OUT CString& sOutputLine)
|
||
{
|
||
BOOL bReadData = FALSE;
|
||
wchar_t* pszUnicodeString = (wchar_t*)&m_arrUnicodeDefaultBuffer;
|
||
bool bNeedToDelete = false;
|
||
|
||
try
|
||
{
|
||
bReadData = (FGGETS_OK == fggets<wchar_t>(&pszUnicodeString, m_pStream, bNeedToDelete, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE));
|
||
|
||
if (bReadData)
|
||
{
|
||
sOutputLine = (CString)pszUnicodeString;
|
||
}
|
||
else
|
||
{
|
||
sOutputLine.Empty();
|
||
}
|
||
}
|
||
// Ensure we always clean up, no matter what
|
||
FINALLY(if (bNeedToDelete) DELETE_SAFE_ARRAY(pszUnicodeString); )
|
||
|
||
return bReadData;
|
||
}
|
||
|
||
// Read Multibyte in Unicode compilation
|
||
BOOL CStdioFileEx::ReadMultiByteLine(OUT CString& sOutputLine)
|
||
{
|
||
BOOL bReadData = FALSE;
|
||
char * pszMultiByteString = (char*)&m_arrMultibyteDefaultBuffer;;
|
||
int nChars = 0;
|
||
bool bNeedToDelete = false;
|
||
|
||
try
|
||
{
|
||
// Read the string -- the function dynamically allocates the necessary memory according
|
||
// to the line length
|
||
bReadData = (FGGETS_OK == fggets<char>(&pszMultiByteString, m_pStream, bNeedToDelete, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE));
|
||
|
||
if (bReadData)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<wchar_t> spUnicodeString((wchar_t*)&m_arrUnicodeDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Use all-in-one allocation and conversion function. Avoid _mbslen and such like since they're unreliable
|
||
// with UTF8
|
||
nChars = GetNewUnicodeStringFromMultiByteString(pszMultiByteString, spUnicodeString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage);
|
||
|
||
if (nChars > 0)
|
||
{
|
||
sOutputLine = (CString)spUnicodeString.GetBuffer();
|
||
}
|
||
}
|
||
|
||
// Empty the string if we failed to read anything
|
||
if (nChars == 0)
|
||
{
|
||
sOutputLine.Empty();
|
||
}
|
||
}
|
||
// Ensure we always clean up, no matter what
|
||
FINALLY(if (bNeedToDelete) DELETE_SAFE_ARRAY(pszMultiByteString); )
|
||
|
||
return bReadData;
|
||
}
|
||
|
||
#else
|
||
|
||
// Read Unicode in Multibyte compilation
|
||
BOOL CStdioFileEx::ReadUnicodeLine(OUT CString& sOutputLine)
|
||
{
|
||
BOOL bReadData = FALSE;
|
||
wchar_t* pszUnicodeString = (wchar_t*)&m_arrUnicodeDefaultBuffer;
|
||
bool bNeedToDelete = false;
|
||
int nChars = 0;
|
||
|
||
try
|
||
{
|
||
bReadData = (FGGETS_OK == fggets<wchar_t>(&pszUnicodeString, m_pStream, bNeedToDelete, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE));
|
||
|
||
if (bReadData)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<char> spMultiByteString((char*)&m_arrMultibyteDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Call all-in-one function to calculate required buffer size and allocate
|
||
nChars = GetNewMultiByteStringFromUnicodeString(pszUnicodeString, spMultiByteString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage, m_cUnicodeFillerChar);
|
||
|
||
if (nChars > 0)
|
||
{
|
||
sOutputLine = (CString)spMultiByteString.GetBuffer();
|
||
}
|
||
}
|
||
|
||
// Empty the string if we failed to read anything
|
||
if (nChars == 0)
|
||
{
|
||
sOutputLine.Empty();
|
||
}
|
||
}
|
||
// Ensure we always clean up, no matter what
|
||
FINALLY(if (bNeedToDelete) DELETE_SAFE_ARRAY(pszUnicodeString); )
|
||
|
||
return bReadData;
|
||
}
|
||
|
||
// Read Multibyte in Multibyte compilation
|
||
BOOL CStdioFileEx::ReadMultiByteLine(OUT CString& sOutputLine)
|
||
{
|
||
BOOL bReadData = FALSE;
|
||
char * pszMultiByteString = (char*)&m_arrMultibyteDefaultBuffer;;
|
||
int nChars = 0;
|
||
UINT nLocaleCodePage = 0;
|
||
bool bNeedToDelete = false;
|
||
|
||
try
|
||
{
|
||
// Read multibyte from file
|
||
bReadData = (FGGETS_OK == fggets<char>(&pszMultiByteString, m_pStream, bNeedToDelete, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE));
|
||
|
||
if (bReadData)
|
||
{
|
||
// Convert to CString
|
||
sOutputLine = (CString)pszMultiByteString;
|
||
|
||
// Now see if we've got to convert to another code page. Get the current code page
|
||
nLocaleCodePage = GetCurrentLocaleCodePage();
|
||
|
||
// If we got it OK...
|
||
if (nLocaleCodePage > 0)
|
||
{
|
||
// If file code page does not match the system code page (and we have a code page!),
|
||
// we need to do a double conversion!
|
||
// Konrad Windszus 29/3/2006: Do nothing if we haven't set a code page
|
||
if (m_nFileCodePage > 0 && nLocaleCodePage != (UINT)m_nFileCodePage)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<wchar_t> spUnicodeString((wchar_t*)&m_arrUnicodeDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Use all-in-one allocation and conversion function. Avoid _mbslen and such like since they're unreliable
|
||
// with UTF8
|
||
nChars = GetNewUnicodeStringFromMultiByteString(sOutputLine, spUnicodeString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage);
|
||
|
||
// Convert back to multibyte using the system code page
|
||
// (This doesn't really confer huge advantages except to avoid "mangling" of non-convertible special
|
||
// characters. So, if a file in the E.European code page is displayed on a system using the
|
||
// western European code page, special accented characters which the system cannot display will be
|
||
// replaced by the default character (a hash or something), rather than being incorrectly mapped to
|
||
// other, western European accented characters).
|
||
if (nChars > 0)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<char> spMultiByteString((char*)&m_arrMultibyteDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Call all-in-one function to calculate required buffer size and allocate
|
||
nChars = GetNewMultiByteStringFromUnicodeString(spUnicodeString.GetBuffer(), spMultiByteString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, nLocaleCodePage, m_cUnicodeFillerChar);
|
||
|
||
sOutputLine = (CString)spMultiByteString.GetBuffer();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Empty the string if we failed to read anything
|
||
if (!bReadData)
|
||
{
|
||
sOutputLine.Empty();
|
||
}
|
||
|
||
}
|
||
// Ensure we always clean up, no matter what
|
||
FINALLY(if (bNeedToDelete) DELETE_SAFE_ARRAY(pszMultiByteString); )
|
||
|
||
return bReadData;
|
||
}
|
||
#endif
|
||
|
||
/**********************************************************************************/
|
||
/* Writing */
|
||
/**********************************************************************************/
|
||
#ifdef _UNICODE
|
||
|
||
// Unicode in Unicode -- no conversion needed
|
||
void CStdioFileEx::WriteUnicodeLine(IN LPCTSTR sInputLine)
|
||
{
|
||
// Write in byte mode
|
||
CFile::Write(sInputLine, (UINT)(wcslen(sInputLine) * sizeof(wchar_t)));
|
||
}
|
||
|
||
// Multibyte/ANSI in Unicode -- have to convert to Multibyte, taking into account the desired code page
|
||
void CStdioFileEx::WriteMultiByteLine(IN LPCTSTR sInputLine)
|
||
{
|
||
int nCharsWritten = 0;
|
||
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<char> spMultiByteString((char*)&m_arrMultibyteDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Call all-in-one function to calculate required buffer size and allocate
|
||
nCharsWritten = GetNewMultiByteStringFromUnicodeString(sInputLine, spMultiByteString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage, m_cUnicodeFillerChar);
|
||
|
||
if (nCharsWritten > 0)
|
||
{
|
||
// Do byte-mode write using actual chars written (fix by Howard J Oh)
|
||
CFile::Write((const void*)spMultiByteString.GetBuffer(),
|
||
nCharsWritten * sizeof(char));
|
||
}
|
||
}
|
||
|
||
#else
|
||
// Writing Unicode in Multibyte, need to convert to Unicode
|
||
void CStdioFileEx::WriteUnicodeLine(IN LPCTSTR sInputLine)
|
||
{
|
||
int nCharsWritten = 0;
|
||
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<wchar_t> spUnicodeString((wchar_t*)&m_arrUnicodeDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Use all-in-one allocation and conversion function. Avoid _mbslen and such like since they're unreliable
|
||
// with UTF8
|
||
nCharsWritten = GetNewUnicodeStringFromMultiByteString(sInputLine, spUnicodeString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage);
|
||
|
||
if (nCharsWritten > 0)
|
||
{
|
||
// Do byte-mode write using actual chars written (fix by Howard J Oh)
|
||
CFile::Write((const void*)spUnicodeString.GetBuffer(), nCharsWritten * sizeof(wchar_t));
|
||
}
|
||
else
|
||
{
|
||
ASSERT(false);
|
||
}
|
||
|
||
// If a buffer was dynamically allocated, it gets deleted by the smart ptr, even on an exception
|
||
}
|
||
|
||
// Writing Multibyte in Multibyte, no conversion needed, unless the code page differs
|
||
void CStdioFileEx::WriteMultiByteLine(IN LPCTSTR sInputLine)
|
||
{
|
||
UINT nLocaleCodePage = 0;
|
||
int nUnicodeCharsWritten = 0;
|
||
int nMultiByteCharsWritten = 0;
|
||
|
||
// Get the current code page
|
||
nLocaleCodePage = GetCurrentLocaleCodePage();
|
||
|
||
// if file code page does not match the system code page (and we have a code page!),
|
||
// we need to do a double conversion!
|
||
// Konrad Windszus 29/3/2006: Do nothing if we haven't set a code page
|
||
if (nLocaleCodePage > 0 && m_nFileCodePage > 0 && nLocaleCodePage != (UINT)m_nFileCodePage)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<wchar_t> spUnicodeString((wchar_t*)&m_arrUnicodeDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Use all-in-one allocation and conversion function. Avoid _mbslen and such like since they're unreliable
|
||
// with UTF8
|
||
nUnicodeCharsWritten = GetNewUnicodeStringFromMultiByteString(sInputLine, spUnicodeString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, nLocaleCodePage);
|
||
|
||
// Convert back to multibyte using the file code page
|
||
// (Note that you can't reliably read a non-Unicode file written in code page A on a system using a code page B,
|
||
// modify the file and write it back using code page A, unless you disable all this double-conversion code.
|
||
// In effect, you have to choose between a mangled character display and mangled file writing).
|
||
if (nUnicodeCharsWritten > 0)
|
||
{
|
||
// Assign default buffer to take care of 99% of cases. Not owned by smart ptr array, so won't be deleted
|
||
CTemplateSmartPtrArray<char> spMultiByteString((char*)&m_arrMultibyteDefaultBuffer, bTEMPLATESMARTPTR_NOTOWNED);
|
||
|
||
// Call all-in-one function to calculate required buffer size and allocate
|
||
nMultiByteCharsWritten = GetNewMultiByteStringFromUnicodeString(
|
||
spUnicodeString.GetBuffer(), spMultiByteString, nSTDIOFILEEX_DEFAULT_BUFFER_SIZE, m_nFileCodePage, m_cUnicodeFillerChar);
|
||
|
||
// Do byte-mode write. This avoids annoying "interpretation" of \n's as \r\n
|
||
CFile::Write((const void*)spMultiByteString.GetBuffer(), nMultiByteCharsWritten * sizeof(char));
|
||
|
||
// If a Unicode buffer was dynamically allocated, it now gets deleted by the smart ptr, even on an exception
|
||
}
|
||
|
||
// If a multibyte buffer was dynamically allocated, it now gets deleted by the smart ptr, even on an exception
|
||
}
|
||
else
|
||
{
|
||
// Do byte-mode write. This avoids annoying "interpretation" of \n's as \r\n
|
||
// Use strlen because we want a straightforward byte-for-byte copy. Characters are irrelevant.
|
||
// strlen always counts bytes.
|
||
CFile::Write((const void*)sInputLine, strlen((const char*)sInputLine) * sizeof(char));
|
||
}
|
||
}
|
||
|
||
#endif
|