mirror of
https://github.com/voiceip/tinyphone
synced 2026-08-07 02:26:03 -04:00
1115 lines
39 KiB
C++
1115 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
|