1// 2// This file is part of the aMule Project. 3// 4// Copyright (c) 2006-2011 aMule Team ( admin@amule.org / http://www.amule.org ) 5// 6// Any parts of this program derived from the xMule, lMule or eMule project, 7// or contributed by third-party developers are copyrighted by their 8// respective authors. 9// 10// This program is free software; you can redistribute it and/or modify 11// it under the terms of the GNU General Public License as published by 12// the Free Software Foundation; either version 2 of the License, or 13// (at your option) any later version. 14// 15// This program is distributed in the hope that it will be useful, 16// but WITHOUT ANY WARRANTY; without even the implied warranty of 17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18// GNU General Public License for more details. 19// 20// You should have received a copy of the GNU General Public License 21// along with this program; if not, write to the Free Software 22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23// 24 25#include "TextFile.h" 26#include "Path.h" 27 28#include <wx/textbuf.h> 29 30 31//! The maximum number of chars read at once in GetNextLine 32const size_t TXTBUF_SIZE = 1024; 33 34 35CTextFile::CTextFile() 36{ 37} 38 39 40bool CTextFile::Open(const wxString& path, EOpenMode mode) 41{ 42 return Open(CPath(path), mode); 43} 44 45 46bool CTextFile::Open(const CPath& path, EOpenMode mode) 47{ 48 // wxFFile doesn't call close itself, but asserts instead. 49 Close(); 50 51 m_mode = mode; 52 53 if (mode == read) { 54 if (path.FileExists()) { 55 m_file.Open(path.GetRaw(), wxT("r")); 56 } 57 } else if (mode == write) { 58 m_file.Open(path.GetRaw(), wxT("w")); 59 } else { 60 wxFAIL; 61 } 62 63 return IsOpened(); 64} 65 66 67CTextFile::~CTextFile() 68{ 69} 70 71 72bool CTextFile::IsOpened() const 73{ 74 return m_file.IsOpened(); 75} 76 77 78bool CTextFile::Eof() const 79{ 80 // This is needed because feof will crash if the 81 // underlying FILE pointer is NULL, as is the 82 // case when the file is closed. 83 return m_file.IsOpened() ? m_file.Eof() : true; 84} 85 86 87bool CTextFile::Close() 88{ 89 return m_file.Close(); 90} 91 92 93wxString CTextFile::GetNextLine(EReadTextFile flags, const wxMBConv& conv, bool* result) 94{ 95 wxCHECK_MSG(m_file.IsOpened(), wxEmptyString, wxT("Trying to read from closed file.")); 96 wxCHECK_MSG(!m_file.Eof(), wxEmptyString, wxT("Trying to read past EOF")); 97 wxCHECK_MSG((m_mode == read), wxEmptyString, wxT("Trying to read from non-readable file.")); 98 99 bool is_filtered = false; 100 101 wxString line; 102 char buffer[TXTBUF_SIZE]; 103 104 // Loop until EOF (fgets will then return NULL) or a newline is read. 105 while (fgets(buffer, TXTBUF_SIZE, m_file.fp())) { 106 // Filters must be first applied here to avoid unnecessary CPU usage. 107 108 if (line.IsEmpty()) { 109 if (buffer[0] == '\0') { 110 // Empty line. 111 break; 112 } else if (flags & txtIgnoreComments) { 113 int i = 0; 114 char t = buffer[i]; 115 while (t) { 116 if ((t == ' ') || (t == '\t')) { 117 ++i; 118 t = buffer[i]; 119 } else { 120 is_filtered = (buffer[i] == '#'); 121 break; 122 } 123 } 124 } 125 } 126 127 if (!is_filtered) { 128 // NB: The majority of the time spent by this function is 129 // spent converting the multibyte string to wide-char. 130 line += conv.cMB2WC(buffer); 131 132 // Remove any newlines, carriage returns, etc. 133 if (line.Length() && (line.Last() == wxT('\n'))) { 134 if ((line.Length() > 1)) { 135 if (line[line.Length() - 2] == wxT('\r')) { 136 // Carriage return + newline 137 line.RemoveLast(2); 138 } else { 139 // Only a newline. 140 line.RemoveLast(1); 141 } 142 } else { 143 // Empty line 144 line.Clear(); 145 } 146 147 // We've read an entire line. 148 break; 149 } 150 } else { 151 // Filtered line. 152 break; 153 } 154 } 155 156 if (!is_filtered) { 157 if (flags & txtStripWhitespace) { 158 line = line.Strip(wxString::both); 159 } 160 161 if ((flags & txtIgnoreEmptyLines) && line.IsEmpty()) { 162 is_filtered = true; 163 } 164 } 165 166 if (result) { 167 *result = !is_filtered; 168 } 169 170 return line; 171} 172 173 174bool CTextFile::WriteLine(const wxString& line, const wxMBConv& conv) 175{ 176 wxCHECK_MSG(m_file.IsOpened(), false, wxT("Trying to read from closed file.")); 177 wxCHECK_MSG((m_mode == write), false, wxT("Trying to read from non-readable file.")); 178 179 // Ensures that use of newlines/carriage-returns matches the OS 180 wxString result = wxTextBuffer::Translate(line); 181 182 // Only add line-breaks between lines, as otherwise the number of 183 // lines would grow as the result of the addition of an empty line, 184 // at the end of the file. 185 if (m_file.Tell() > 0) { 186 result = wxTextBuffer::GetEOL() + result; 187 } 188 189 wxCharBuffer strBuffer = conv.cWC2MB(result); 190 if (strBuffer) { 191 const size_t length = strlen(strBuffer); 192 193 return (m_file.Write(strBuffer, length) == length); 194 } 195 196 return false; 197} 198 199 200wxArrayString CTextFile::ReadLines(EReadTextFile flags, const wxMBConv& conv) 201{ 202 wxArrayString lines; 203 204 while (!Eof()) { 205 bool result = true; 206 207 wxString line = GetNextLine(flags, conv, &result); 208 209 if (result) { 210 lines.Add(line); 211 } 212 } 213 214 return lines; 215} 216 217 218bool CTextFile::WriteLines(const wxArrayString& lines, const wxMBConv& conv) 219{ 220 bool result = true; 221 222 for (size_t i = 0; i < lines.GetCount(); ++i) { 223 result &= WriteLine(lines[i], conv); 224 } 225 226 return result; 227} 228 229