// // This file is part of the aMule Project. // // Copyright (c) 2006-2011 aMule Team ( admin@amule.org / http://www.amule.org ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #include "TextFile.h" #include "Path.h" #include //! The maximum number of chars read at once in GetNextLine const size_t TXTBUF_SIZE = 1024; CTextFile::CTextFile() { } bool CTextFile::Open(const wxString& path, EOpenMode mode) { return Open(CPath(path), mode); } bool CTextFile::Open(const CPath& path, EOpenMode mode) { // wxFFile doesn't call close itself, but asserts instead. Close(); m_mode = mode; if (mode == read) { if (path.FileExists()) { m_file.Open(path.GetRaw(), wxT("r")); } } else if (mode == write) { m_file.Open(path.GetRaw(), wxT("w")); } else { wxFAIL; } return IsOpened(); } CTextFile::~CTextFile() { } bool CTextFile::IsOpened() const { return m_file.IsOpened(); } bool CTextFile::Eof() const { // This is needed because feof will crash if the // underlying FILE pointer is NULL, as is the // case when the file is closed. return m_file.IsOpened() ? m_file.Eof() : true; } bool CTextFile::Close() { return m_file.Close(); } wxString CTextFile::GetNextLine(EReadTextFile flags, const wxMBConv& conv, bool* result) { wxCHECK_MSG(m_file.IsOpened(), wxEmptyString, wxT("Trying to read from closed file.")); wxCHECK_MSG(!m_file.Eof(), wxEmptyString, wxT("Trying to read past EOF")); wxCHECK_MSG((m_mode == read), wxEmptyString, wxT("Trying to read from non-readable file.")); bool is_filtered = false; wxString line; char buffer[TXTBUF_SIZE]; // Loop until EOF (fgets will then return NULL) or a newline is read. while (fgets(buffer, TXTBUF_SIZE, m_file.fp())) { // Filters must be first applied here to avoid unnecessary CPU usage. if (line.IsEmpty()) { if (buffer[0] == '\0') { // Empty line. break; } else if (flags & txtIgnoreComments) { int i = 0; char t = buffer[i]; while (t) { if ((t == ' ') || (t == '\t')) { ++i; t = buffer[i]; } else { is_filtered = (buffer[i] == '#'); break; } } } } if (!is_filtered) { // NB: The majority of the time spent by this function is // spent converting the multibyte string to wide-char. line += conv.cMB2WC(buffer); // Remove any newlines, carriage returns, etc. if (line.Length() && (line.Last() == wxT('\n'))) { if ((line.Length() > 1)) { if (line[line.Length() - 2] == wxT('\r')) { // Carriage return + newline line.RemoveLast(2); } else { // Only a newline. line.RemoveLast(1); } } else { // Empty line line.Clear(); } // We've read an entire line. break; } } else { // Filtered line. break; } } if (!is_filtered) { if (flags & txtStripWhitespace) { line = line.Strip(wxString::both); } if ((flags & txtIgnoreEmptyLines) && line.IsEmpty()) { is_filtered = true; } } if (result) { *result = !is_filtered; } return line; } bool CTextFile::WriteLine(const wxString& line, const wxMBConv& conv) { wxCHECK_MSG(m_file.IsOpened(), false, wxT("Trying to read from closed file.")); wxCHECK_MSG((m_mode == write), false, wxT("Trying to read from non-readable file.")); // Ensures that use of newlines/carriage-returns matches the OS wxString result = wxTextBuffer::Translate(line); // Only add line-breaks between lines, as otherwise the number of // lines would grow as the result of the addition of an empty line, // at the end of the file. if (m_file.Tell() > 0) { result = wxTextBuffer::GetEOL() + result; } wxCharBuffer strBuffer = conv.cWC2MB(result); if (strBuffer) { const size_t length = strlen(strBuffer); return (m_file.Write(strBuffer, length) == length); } return false; } wxArrayString CTextFile::ReadLines(EReadTextFile flags, const wxMBConv& conv) { wxArrayString lines; while (!Eof()) { bool result = true; wxString line = GetNextLine(flags, conv, &result); if (result) { lines.Add(line); } } return lines; } bool CTextFile::WriteLines(const wxArrayString& lines, const wxMBConv& conv) { bool result = true; for (size_t i = 0; i < lines.GetCount(); ++i) { result &= WriteLine(lines[i], conv); } return result; }