| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // 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 Howard J Oh and some of my own.
- //
- // Copyright David Pritchard 2003-2005. [email protected]
- //
- // You can use this class freely, but please keep my ego happy
- // by leaving this comment in place.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "StdioFileEx.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- /*static*/ const UINT CStdioFileEx::modeWriteUnicode = 0x20000; // Add this flag to write in Unicode
- CStdioFileEx::CStdioFileEx(): CStdioFile()
- {
- m_bIsUnicodeText = false;
- }
- CStdioFileEx::CStdioFileEx(LPCTSTR lpszFileName,UINT nOpenFlags)
- :CStdioFile(lpszFileName, ProcessFlags(lpszFileName, nOpenFlags))
- {
- }
- BOOL CStdioFileEx::Open(LPCTSTR lpszFileName,UINT nOpenFlags,CFileException* pError /*=NULL*/)
- {
- // Process any Unicode stuff
- ProcessFlags(lpszFileName, nOpenFlags);
- return CStdioFile::Open(lpszFileName, nOpenFlags, pError);
- }
- BOOL CStdioFileEx::ReadString(CString& rString)
- {
- BOOL bReadData;
- LPTSTR lpsz;
- int nLen = 0; //, nMultiByteBufferLength = 0, nChars = 0;
- CString sTemp;
- // If at position 0, discard byte-order mark before reading
- if (!m_pStream || (GetPosition() == 0 && m_bIsUnicodeText))
- {
- wchar_t cDummy;
- Read(&cDummy, sizeof(wchar_t));
- }
- // If compiled for Unicode
- #ifdef _UNICODE
- // Do standard stuff -- both ANSI and Unicode cases seem to work OK
- bReadData = CStdioFile::ReadString(rString);
- #else
- if (!m_bIsUnicodeText)
- {
- // Do standard stuff -- read ANSI in ANSI
- bReadData = CStdioFile::ReadString(rString);
- }
- else
- {
- const int nMAX_LINE_CHARS = 4096;
- wchar_t* pszUnicodeString = new wchar_t[nMAX_LINE_CHARS];
- char* pszMultiByteString= new char[nMAX_LINE_CHARS];
- // Read as Unicode, convert to ANSI; fixed by Dennis Jeryd 6/8/03
- bReadData = (NULL != fgetws(pszUnicodeString, nMAX_LINE_CHARS, m_pStream));
- if (GetMultiByteStringFromUnicodeString(pszUnicodeString, pszMultiByteString, nMAX_LINE_CHARS))
- {
- rString = (CString)pszMultiByteString;
- }
- if (pszUnicodeString)
- {
- delete pszUnicodeString;
- }
- if (pszMultiByteString)
- {
- delete pszMultiByteString;
- }
- }
- #endif
- // Then remove end-of-line character if in Unicode text mode
- if (bReadData)
- {
- // Copied from FileTxt.cpp but adapted to Unicode and then adapted for end-of-line being just '\r'.
- nLen = rString.GetLength();
- if (nLen > 1 && rString.Mid(nLen-2) == sNEWLINE)
- {
- rString.GetBufferSetLength(nLen-2);
- }
- else
- {
- lpsz = rString.GetBuffer(0);
- if (nLen != 0 && (lpsz[nLen-1] == _T('\r') || lpsz[nLen-1] == _T('\n')))
- {
- rString.GetBufferSetLength(nLen-1);
- }
- }
- }
- return bReadData;
- }
- // --------------------------------------------------------------------------------------------
- //
- // 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)
- {
- // 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
- if (!m_pStream || GetPosition() == 0)
- {
- wchar_t cBOM = (wchar_t)nUNICODE_BOM;
- CFile::Write(&cBOM, sizeof(wchar_t));
- }
- }
- // If compiled in Unicode...
- #ifdef _UNICODE
- // If writing Unicode, no conversion needed
- if (m_nFlags & CStdioFileEx::modeWriteUnicode)
- {
- // Write in byte mode
- CFile::Write(lpsz, lstrlen(lpsz) * sizeof(wchar_t));
- }
- // Else if we don't want to write Unicode, need to convert
- else
- {
- int nChars = lstrlen(lpsz) + 1; // Why plus 1? Because yes
- int nBufferSize = nChars * sizeof(char);
- wchar_t* pszUnicodeString = new wchar_t[nChars];
- char * pszMultiByteString= new char[nChars];
- int nCharsWritten = 0;
- // Copy string to Unicode buffer
- lstrcpy(pszUnicodeString, lpsz);
- // Get multibyte string
- nCharsWritten =
- GetMultiByteStringFromUnicodeString(pszUnicodeString, pszMultiByteString, ( short ) nBufferSize, GetACP());
-
- if (nCharsWritten > 0)
- {
- // CFile::Write((const void*)pszMultiByteString, lstrlen(lpsz));
- // Do byte-mode write using actual chars written (fix by Howard J Oh)
- CFile::Write((const void*)pszMultiByteString,
- nCharsWritten*sizeof(char));
- }
- if (pszUnicodeString && pszMultiByteString)
- {
- delete [] pszUnicodeString;
- delete [] pszMultiByteString;
- }
- }
- // Else if *not* compiled in Unicode
- #else
- // If writing Unicode, need to convert
- if (m_nFlags & CStdioFileEx::modeWriteUnicode)
- {
- int nChars = lstrlen(lpsz) + 1; // Why plus 1? Because yes
- wchar_t* pszUnicodeString = new wchar_t[nChars];
- char * pszMultiByteString= new char[nChars];
- int nCharsWritten = 0;
-
- // Copy string to multibyte buffer
- lstrcpy(pszMultiByteString, lpsz);
- nCharsWritten =
- GetUnicodeStringFromMultiByteString(pszMultiByteString,
- pszUnicodeString, nChars, GetACP());
-
- if (nCharsWritten > 0)
- {
- // CFile::Write(pszUnicodeString, lstrlen(lpsz) * sizeof(wchar_t));
- // Write in byte mode. Write actual number of chars written * bytes (fix by Howard J Oh)
- CFile::Write(pszUnicodeString, nCharsWritten*sizeof(wchar_t));
- }
- else
- {
- ASSERT(false);
- }
- if (pszUnicodeString && pszMultiByteString)
- {
- delete [] pszUnicodeString;
- delete [] pszMultiByteString;
- }
- }
- // Else if we don't want to write Unicode, no conversion needed
- else
- {
- // Do standard stuff
- //CStdioFile::WriteString(lpsz);
-
- // Do byte-mode write. This avoids annoying "interpretation" of \n's as \r\n
- CFile::Write((const void*)lpsz, lstrlen(lpsz)*sizeof(char));
- }
- #endif
- }
- UINT CStdioFileEx::ProcessFlags(const CString& sFilePath, 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
- // If reading in text mode and not creating... ; fixed by Dennis Jeryd 6/8/03
- if (nOpenFlags & CFile::typeText && !(nOpenFlags & CFile::modeCreate) && !(nOpenFlags & CFile::modeWrite ))
- {
- m_bIsUnicodeText = IsFileUnicode(sFilePath);
- // If it's Unicode, switch to binary mode
- if (m_bIsUnicodeText)
- {
- 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;
- }
- unsigned long CStdioFileEx::GetCharCount()
- {
- int nCharSize;
- unsigned long 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 = (long)GetLength();
-
- if (m_bIsUnicodeText)
- {
- nByteCount = nByteCount - sizeof(wchar_t);
- }
- // Calc chars
- nCharCount = (nByteCount / nCharSize);
- }
- return nCharCount;
- }
- // --------------------------------------------------------------------------------------------
- //
- // CStdioFileEx::GetUnicodeStringFromMultiByteString()
- //
- // --------------------------------------------------------------------------------------------
- // Returns: int - num. of chars written (0 means error)
- // Parameters: char * szMultiByteString (IN) Multi-byte input string
- // wchar_t* szUnicodeString (OUT) Unicode outputstring
- // int& nUnicodeBufferSize (IN/OUT) Size of Unicode output buffer(IN)
- // Actual bytes written to buffer (OUT)
- // UINT nCodePage (IN) Code page used to perform conversion
- // Default = -1 (Get local code page).
- //
- // Purpose: Gets a Unicode string from a MultiByte string.
- // Notes: None.
- // Exceptions: None.
- //
- int CStdioFileEx::GetUnicodeStringFromMultiByteString(IN char * szMultiByteString, OUT wchar_t* szUnicodeString, IN OUT int& nUnicodeBufferSize, IN UINT nCodePage)
- {
- int nCharsWritten = 0;
-
- if (szUnicodeString && szMultiByteString)
- {
- // If no code page specified, take default for system
- if (nCodePage == -1)
- {
- nCodePage = GetACP();
- }
- try
- {
- // Zero out buffer first. NB: nUnicodeBufferSize is NUMBER OF CHARS, NOT BYTES!
- memset((void*)szUnicodeString, '\0', sizeof(wchar_t) *
- nUnicodeBufferSize);
- nCharsWritten = MultiByteToWideChar(nCodePage,MB_PRECOMPOSED,szMultiByteString,-1,szUnicodeString,nUnicodeBufferSize);
- }
- catch(...)
- {
- TRACE(_T("Controlled exception in MultiByteToWideChar!\n"));
- }
- }
- // Now fix nCharsWritten
- if (nCharsWritten > 0)
- {
- nCharsWritten--;
- }
-
- ASSERT(nCharsWritten > 0);
- return nCharsWritten;
- }
- // --------------------------------------------------------------------------------------------
- //
- // CStdioFileEx::GetMultiByteStringFromUnicodeString()
- //
- // --------------------------------------------------------------------------------------------
- // Returns: int - number of characters written. 0 means error
- // Parameters: wchar_t * szUnicodeString (IN) Unicode input string
- // char* szMultiByteString (OUT) Multibyte output string
- // short nMultiByteBufferSize (IN) Multibyte buffer size
- // UINT nCodePage (IN) Code page used to perform conversion
- // Default = -1 (Get local code page).
- //
- // Purpose: Gets a MultiByte string from a Unicode string
- // Notes: None.
- // Exceptions: None.
- //
- int CStdioFileEx::GetMultiByteStringFromUnicodeString(wchar_t * szUnicodeString, char* szMultiByteString,
- short nMultiByteBufferSize, UINT nCodePage)
- {
- BOOL bUsedDefChar = FALSE;
- int nCharsWritten = 0;
- if (szUnicodeString && szMultiByteString)
- {
- // Zero out buffer first
- memset((void*)szMultiByteString, '\0', nMultiByteBufferSize);
-
- // If no code page specified, take default for system
- if (nCodePage == -1)
- {
- nCodePage = GetACP();
- }
- try
- {
- nCharsWritten = WideCharToMultiByte(nCodePage, WC_COMPOSITECHECK | WC_SEPCHARS,
- szUnicodeString,-1, szMultiByteString, nMultiByteBufferSize, sDEFAULT_UNICODE_FILLER_CHAR, &bUsedDefChar);
- }
- catch(...)
- {
- TRACE(_T("Controlled exception in WideCharToMultiByte!\n"));
- }
- }
- // Now fix nCharsWritten
- if (nCharsWritten > 0)
- {
- nCharsWritten--;
- }
-
- return nCharsWritten;
- }
|