Files
wxWidgets/src/common/textfile.cpp
Vadim Zeitlin 830f8f11bc 1. changed all "wxMBConv& conv" parameters to "const wxMBConv&"
2. this allows to use wxConvAuto() instead of wxConvUTF8 as default value
   for this parameter in the classes which read text from the file: wxConvAuto
   automatically recognizes the BOM at the start of file and uses the correct
   conversion
3. don't use Windows for UTF-7 conversions as there is no way to make it
   fail on invalid UTF-7 strings; use our own wxMBConvUtf7 instead


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38570 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2006-04-05 14:37:47 +00:00

234 lines
6.6 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/textfile.cpp
// Purpose: implementation of wxTextFile class
// Author: Vadim Zeitlin
// Modified by:
// Created: 03.04.98
// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// headers
// ============================================================================
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#if !wxUSE_FILE || !wxUSE_TEXTBUFFER
#undef wxUSE_TEXTFILE
#define wxUSE_TEXTFILE 0
#endif // wxUSE_FILE
#if wxUSE_TEXTFILE
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/file.h"
#include "wx/log.h"
#endif
#include "wx/textfile.h"
#include "wx/filename.h"
#include "wx/buffer.h"
// ============================================================================
// wxTextFile class implementation
// ============================================================================
wxTextFile::wxTextFile(const wxString& strFileName)
: wxTextBuffer(strFileName)
{
}
// ----------------------------------------------------------------------------
// file operations
// ----------------------------------------------------------------------------
bool wxTextFile::OnExists() const
{
return wxFile::Exists(m_strBufferName);
}
bool wxTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode)
{
wxFile::OpenMode FileOpenMode;
switch ( OpenMode )
{
default:
wxFAIL_MSG( _T("unknown open mode in wxTextFile::Open") );
// fall through
case ReadAccess :
FileOpenMode = wxFile::read;
break;
case WriteAccess :
FileOpenMode = wxFile::write;
break;
}
return m_file.Open(strBufferName.c_str(), FileOpenMode);
}
bool wxTextFile::OnClose()
{
return m_file.Close();
}
bool wxTextFile::OnRead(const wxMBConv& conv)
{
// file should be opened and we must be in it's beginning
wxASSERT( m_file.IsOpened() && m_file.Tell() == 0 );
// read the entire file in memory: this is not the most efficient thing to
// do but there is no good way to avoid it in Unicode build because if we
// read the file block by block we can't convert each block to Unicode
// separately (the last multibyte char in the block might be only partially
// read and so the conversion would fail) and, as the file contents is kept
// in memory by wxTextFile anyhow, it shouldn't be a big problem to read
// the file entirely
const size_t bufSize = (size_t)(m_file.Length() + 4 /* for trailing NULs */ );
size_t bufPos = 0;
wxCharBuffer buf(bufSize - 1 /* it adds 1 internally */);
char block[1024];
for ( bool eof = false; !eof; )
{
// try to read up to the size of the entire block
ssize_t nRead = m_file.Read(block, WXSIZEOF(block));
if ( nRead == wxInvalidOffset )
{
// read error (error message already given in wxFile::Read)
return false;
}
if ( nRead == 0 )
break;
// this shouldn't happen but don't overwrite the buffer if it does
wxCHECK_MSG( bufPos + nRead <= bufSize, false,
_T("read more than file length?") );
// append to the buffer
memcpy(buf.data() + bufPos, block, nRead);
bufPos += nRead;
}
const wxString str(buf, conv, bufPos);
// this doesn't risk to happen in ANSI build
#if wxUSE_UNICODE
if ( bufSize > 4 && str.empty() )
{
wxLogError(_("Failed to convert file contents to Unicode."));
return false;
}
#endif // wxUSE_UNICODE
free(buf.release()); // we don't need this memory any more
// now break the buffer in lines
// last processed character, we need to know if it was a CR or not
wxChar chLast = '\0';
// the beginning of the current line, changes inside the loop
wxString::const_iterator lineStart = str.begin();
const wxString::const_iterator end = str.end();
for ( wxString::const_iterator p = lineStart; p != end; p++ )
{
const wxChar ch = *p;
switch ( ch )
{
case '\n':
// could be a DOS or Unix EOL
if ( chLast == '\r' )
{
AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos);
}
else // bare '\n', Unix style
{
AddLine(wxString(lineStart, p), wxTextFileType_Unix);
}
lineStart = p + 1;
break;
case '\r':
if ( chLast == '\r' )
{
// Mac empty line
AddLine(wxEmptyString, wxTextFileType_Mac);
lineStart = p + 1;
}
//else: we don't know what this is yet -- could be a Mac EOL or
// start of DOS EOL so wait for next char
break;
default:
if ( chLast == '\r' )
{
// Mac line termination
AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac);
lineStart = p;
}
}
chLast = ch;
}
// anything in the last line?
if ( lineStart != end )
{
// add unterminated last line
AddLine(wxString(lineStart, end), wxTextFileType_None);
}
return true;
}
bool wxTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv)
{
wxFileName fn = m_strBufferName;
// We do NOT want wxPATH_NORM_CASE here, or the case will not
// be preserved.
if ( !fn.IsAbsolute() )
fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE |
wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG);
wxTempFile fileTmp(fn.GetFullPath());
if ( !fileTmp.IsOpened() ) {
wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str());
return false;
}
size_t nCount = GetLineCount();
for ( size_t n = 0; n < nCount; n++ ) {
fileTmp.Write(GetLine(n) +
GetEOL(typeNew == wxTextFileType_None ? GetLineType(n)
: typeNew),
conv);
}
// replace the old file with this one
return fileTmp.Commit();
}
#endif // wxUSE_TEXTFILE