X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6ad0a7d52fc2a0ec7a434d1c7edb6e00d09853a4..e887bad5f3a10f5b0c1f173c34c694dda283d0cf:/src/common/fileconf.cpp diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 0c3912dbdb..07da5e6ff2 100644 --- a/src/common/fileconf.cpp +++ b/src/common/fileconf.cpp @@ -42,6 +42,8 @@ #include "wx/fileconf.h" #include "wx/filefn.h" +#include "wx/base64.h" + #include "wx/stdpaths.h" #if defined(__WXMAC__) @@ -222,12 +224,12 @@ public: bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); } // find entry/subgroup (NULL if not found) - wxFileConfigGroup *FindSubgroup(const wxChar *szName) const; - wxFileConfigEntry *FindEntry (const wxChar *szName) const; + wxFileConfigGroup *FindSubgroup(const wxString& name) const; + wxFileConfigEntry *FindEntry (const wxString& name) const; // delete entry/subgroup, return false if doesn't exist - bool DeleteSubgroupByName(const wxChar *szName); - bool DeleteEntry(const wxChar *szName); + bool DeleteSubgroupByName(const wxString& name); + bool DeleteEntry(const wxString& name); // create new entry/subgroup returning pointer to newly created element wxFileConfigGroup *AddSubgroup(const wxString& strName); @@ -370,7 +372,16 @@ void wxFileConfig::Init() } else { - wxLogWarning(_("can't open user configuration file '%s'."), m_fnLocalFile.GetFullPath().c_str() ); + const wxString path = m_fnLocalFile.GetFullPath(); + wxLogWarning(_("can't open user configuration file '%s'."), + path.c_str()); + + if ( m_fnLocalFile.FileExists() ) + { + wxLogWarning(_("Changes won't be saved to avoid overwriting the existing file \"%s\""), + path.c_str()); + m_fnLocalFile.Clear(); + } } } @@ -435,71 +446,61 @@ wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv) m_linesTail = NULL; // read the entire stream contents in memory - wxString str; - { - static const size_t chunkLen = 1024; + wxWxCharBuffer cbuf; + static const size_t chunkLen = 1024; - wxMemoryBuffer buf(chunkLen); - do - { - inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); - buf.UngetAppendBuf(inStream.LastRead()); + wxMemoryBuffer buf(chunkLen); + do + { + inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); + buf.UngetAppendBuf(inStream.LastRead()); - const wxStreamError err = inStream.GetLastError(); + const wxStreamError err = inStream.GetLastError(); - if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) - { - wxLogError(_("Error reading config options.")); - break; - } + if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) + { + wxLogError(_("Error reading config options.")); + break; } - while ( !inStream.Eof() ); + } + while ( !inStream.Eof() ); #if wxUSE_UNICODE - size_t len; - str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len); - if ( !len && buf.GetDataLen() ) - { - wxLogError(_("Failed to read config options.")); - } + size_t len; + cbuf = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen() + 1, &len); + if ( !len && buf.GetDataLen() ) + { + wxLogError(_("Failed to read config options.")); + } #else // !wxUSE_UNICODE - // no need for conversion - str.assign((char *)buf.GetData(), buf.GetDataLen()); + // no need for conversion + cbuf = wxCharBuffer::CreateNonOwned((char *)buf.GetData()); #endif // wxUSE_UNICODE/!wxUSE_UNICODE - } - - // translate everything to the current (platform-dependent) line - // termination character - str = wxTextBuffer::Translate(str); + // now break it into lines wxMemoryText memText; - - // Now we can add the text to the memory text. To do this we extract line - // by line from the translated string, until we've reached the end. - // - // VZ: all this is horribly inefficient, we should do the translation on - // the fly in one pass saving both memory and time (TODO) - - const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault); - const size_t EOLLen = wxStrlen(pEOL); - - int posLineStart = str.Find(pEOL); - while ( posLineStart != -1 ) + for ( const wxChar *s = cbuf; ; ++s ) { - wxString line(str.Left(posLineStart)); + const wxChar *e = s; + while ( *e != '\0' && *e != '\n' && *e != '\r' ) + ++e; + + // notice that we throw away the original EOL kind here, maybe we + // should preserve it? + if ( e != s ) + memText.AddLine(wxString(s, e)); - memText.AddLine(line); + if ( *e == '\0' ) + break; - str = str.Mid(posLineStart + EOLLen); + // skip the second EOL byte if it's a DOS one + if ( *e == '\r' && e[1] == '\n' ) + ++e; - posLineStart = str.Find(pEOL); + s = e; } - // also add whatever we have left in the translated string. - if ( !str.empty() ) - memText.AddLine(str); - // Finally we can parse it all. Parse(memText, true /* local */); @@ -536,15 +537,16 @@ wxFileConfig::~wxFileConfig() void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) { - const wxChar *pStart; - const wxChar *pEnd; - wxString strLine; size_t nLineCount = buffer.GetLineCount(); for ( size_t n = 0; n < nLineCount; n++ ) { - strLine = buffer[n]; + wxString strLine = buffer[n]; + // FIXME-UTF8: rewrite using iterators, without this buffer + wxWxCharBuffer buf(strLine.c_str()); + const wxChar *pStart; + const wxChar *pEnd; // add the line to linked list if ( bLocal ) @@ -560,7 +562,7 @@ void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) // skip leading spaces - for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) + for ( pStart = buf; wxIsspace(*pStart); pStart++ ) ; // skip blank/comment lines @@ -915,6 +917,22 @@ bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const return str.ToLong(pl); } +#if wxUSE_BASE64 + +bool wxFileConfig::DoReadBinary(const wxString& key, wxMemoryBuffer* buf) const +{ + wxCHECK_MSG( buf, false, _T("NULL buffer") ); + + wxString str; + if ( !Read(key, &str) ) + return false; + + *buf = wxBase64Decode(str.ToAscii()); + return true; +} + +#endif // wxUSE_BASE64 + bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue) { wxConfigPathChanger path(this, key); @@ -980,6 +998,15 @@ bool wxFileConfig::DoWriteLong(const wxString& key, long lValue) return Write(key, wxString::Format(_T("%ld"), lValue)); } +#if wxUSE_BASE64 + +bool wxFileConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf) +{ + return Write(key, wxBase64Encode(buf)); +} + +#endif // wxUSE_BASE64 + bool wxFileConfig::Flush(bool /* bCurrentOnly */) { if ( !IsDirty() || !m_fnLocalFile.GetFullPath() ) @@ -1059,7 +1086,7 @@ bool wxFileConfig::Save(wxOutputStream& os, const wxMBConv& conv) bool wxFileConfig::RenameEntry(const wxString& oldName, const wxString& newName) { - wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), + wxASSERT_MSG( oldName.find(wxCONFIG_PATH_SEPARATOR) == wxString::npos, _T("RenameEntry(): paths are not supported") ); // check that the entry exists @@ -1148,7 +1175,8 @@ bool wxFileConfig::DeleteAll() if ( m_fnLocalFile.IsOk() ) { - if ( m_fnLocalFile.FileExists() && wxRemove(m_fnLocalFile.GetFullPath()) == -1 ) + if ( m_fnLocalFile.FileExists() && + !wxRemoveFile(m_fnLocalFile.GetFullPath()) ) { wxLogSysError(_("can't delete user configuration file '%s'"), m_fnLocalFile.GetFullPath().c_str()); @@ -1548,7 +1576,7 @@ wxString wxFileConfigGroup::GetFullName() const // use binary search because the array is sorted wxFileConfigEntry * -wxFileConfigGroup::FindEntry(const wxChar *szName) const +wxFileConfigGroup::FindEntry(const wxString& name) const { size_t i, lo = 0, @@ -1561,9 +1589,9 @@ wxFileConfigGroup::FindEntry(const wxChar *szName) const pEntry = m_aEntries[i]; #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pEntry->Name(), szName); + res = pEntry->Name().compare(name); #else - res = wxStricmp(pEntry->Name(), szName); + res = pEntry->Name().CmpNoCase(name); #endif if ( res > 0 ) @@ -1578,7 +1606,7 @@ wxFileConfigGroup::FindEntry(const wxChar *szName) const } wxFileConfigGroup * -wxFileConfigGroup::FindSubgroup(const wxChar *szName) const +wxFileConfigGroup::FindSubgroup(const wxString& name) const { size_t i, lo = 0, @@ -1591,9 +1619,9 @@ wxFileConfigGroup::FindSubgroup(const wxChar *szName) const pGroup = m_aSubgroups[i]; #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pGroup->Name(), szName); + res = pGroup->Name().compare(name); #else - res = wxStricmp(pGroup->Name(), szName); + res = pGroup->Name().CmpNoCase(name); #endif if ( res > 0 ) @@ -1644,9 +1672,9 @@ wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName) delete several of them. */ -bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName) +bool wxFileConfigGroup::DeleteSubgroupByName(const wxString& name) { - wxFileConfigGroup * const pGroup = FindSubgroup(szName); + wxFileConfigGroup * const pGroup = FindSubgroup(name); return pGroup ? DeleteSubgroup(pGroup) : false; } @@ -1765,9 +1793,9 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) return true; } -bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) +bool wxFileConfigGroup::DeleteEntry(const wxString& name) { - wxFileConfigEntry *pEntry = FindEntry(szName); + wxFileConfigEntry *pEntry = FindEntry(name); if ( !pEntry ) { // entry doesn't exist, nothing to do @@ -1920,18 +1948,18 @@ void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser) int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2) { #if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); + return p1->Name().compare(p2->Name()); #else - return wxStricmp(p1->Name(), p2->Name()); + return p1->Name().CmpNoCase(p2->Name()); #endif } int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) { #if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); + return p1->Name().compare(p2->Name()); #else - return wxStricmp(p1->Name(), p2->Name()); + return p1->Name().CmpNoCase(p2->Name()); #endif } @@ -1942,47 +1970,66 @@ int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) // undo FilterOutValue static wxString FilterInValue(const wxString& str) { - wxString strResult; - strResult.Alloc(str.Len()); + wxString strResult; + if ( str.empty() ) + return strResult; - bool bQuoted = !str.empty() && str[0] == '"'; + strResult.reserve(str.length()); - for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { - if ( str[n] == wxT('\\') ) { - switch ( str[++n].GetValue() ) { - case wxT('n'): - strResult += wxT('\n'); - break; + wxString::const_iterator i = str.begin(); + const bool bQuoted = *i == '"'; + if ( bQuoted ) + ++i; - case wxT('r'): - strResult += wxT('\r'); - break; + for ( const wxString::const_iterator end = str.end(); i != end; ++i ) + { + if ( *i == wxT('\\') ) + { + if ( ++i == end ) + { + wxLogWarning(_("trailing backslash ignored in '%s'"), str.c_str()); + break; + } - case wxT('t'): - strResult += wxT('\t'); - break; + switch ( (*i).GetValue() ) + { + case wxT('n'): + strResult += wxT('\n'); + break; - case wxT('\\'): - strResult += wxT('\\'); - break; + case wxT('r'): + strResult += wxT('\r'); + break; - case wxT('"'): - strResult += wxT('"'); - break; - } - } - else { - if ( str[n] != wxT('"') || !bQuoted ) - strResult += str[n]; - else if ( n != str.Len() - 1 ) { - wxLogWarning(_("unexpected \" at position %d in '%s'."), - n, str.c_str()); - } - //else: it's the last quote of a quoted string, ok + case wxT('t'): + strResult += wxT('\t'); + break; + + case wxT('\\'): + strResult += wxT('\\'); + break; + + case wxT('"'): + strResult += wxT('"'); + break; + } + } + else // not a backslash + { + if ( *i != wxT('"') || !bQuoted ) + { + strResult += *i; + } + else if ( i != end - 1 ) + { + wxLogWarning(_("unexpected \" at position %d in '%s'."), + i - str.begin(), str.c_str()); + } + //else: it's the last quote of a quoted string, ok + } } - } - return strResult; + return strResult; } // quote the string before writing it to file