X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/466e87bd8c80937ca21e8471dc45ed49480675b6..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/fileconf.cpp diff --git a/src/common/fileconf.cpp b/src/common/fileconf.cpp index 1503ece182..ab3c4a0f49 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); @@ -344,7 +346,7 @@ void wxFileConfig::Init() // It's not an error if (one of the) file(s) doesn't exist. // parse the global file - if ( m_fnGlobalFile.FileExists() ) + if ( m_fnGlobalFile.IsOk() && m_fnGlobalFile.FileExists() ) { wxTextFile fileGlobal(m_fnGlobalFile.GetFullPath()); @@ -360,7 +362,7 @@ void wxFileConfig::Init() } // parse the local file - if ( m_fnLocalFile.FileExists() ) + if ( m_fnLocalFile.IsOk() && m_fnLocalFile.FileExists() ) { wxTextFile fileLocal(m_fnLocalFile.GetFullPath()); if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) ) @@ -435,70 +437,59 @@ 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(), &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; - memText.AddLine(line); + // notice that we throw away the original EOL kind here, maybe we + // should preserve it? + memText.AddLine(wxString(s, e)); - str = str.Mid(posLineStart + EOLLen); + if ( *e == '\0' ) + break; - posLineStart = str.Find(pEOL); - } + // skip the second EOL byte if it's a DOS one + if ( *e == '\r' && e[1] == '\n' ) + ++e; - // also add whatever we have left in the translated string. - if ( !str.empty() ) - memText.AddLine(str); + s = e; + } // Finally we can parse it all. Parse(memText, true /* local */); @@ -536,15 +527,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 +552,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 @@ -728,7 +720,7 @@ wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) // change current group size_t n; m_pCurrentGroup = m_pRootGroup; - for ( n = 0; n < aParts.Count(); n++ ) { + for ( n = 0; n < aParts.GetCount(); n++ ) { wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]); if ( pNextGroup == NULL ) { @@ -743,7 +735,7 @@ wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) // recombine path parts in one variable m_strPath.Empty(); - for ( n = 0; n < aParts.Count(); n++ ) { + for ( n = 0; n < aParts.GetCount(); n++ ) { m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; } @@ -767,7 +759,7 @@ bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const { - if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) { + if ( size_t(lIndex) < m_pCurrentGroup->Groups().GetCount() ) { str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name(); return true; } @@ -783,7 +775,7 @@ bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const { - if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) { + if ( size_t(lIndex) < m_pCurrentGroup->Entries().GetCount() ) { str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name(); return true; } @@ -793,10 +785,10 @@ bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const { - size_t n = m_pCurrentGroup->Entries().Count(); + size_t n = m_pCurrentGroup->Entries().GetCount(); if ( bRecursive ) { wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + size_t nSubgroups = m_pCurrentGroup->Groups().GetCount(); for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; n += GetNumberOfEntries(true); @@ -809,10 +801,10 @@ size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const { - size_t n = m_pCurrentGroup->Groups().Count(); + size_t n = m_pCurrentGroup->Groups().GetCount(); if ( bRecursive ) { wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + size_t nSubgroups = m_pCurrentGroup->Groups().GetCount(); for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; n += GetNumberOfGroups(true); @@ -915,6 +907,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 +988,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 +1076,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 +1165,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()); @@ -1339,12 +1357,12 @@ wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent, wxFileConfigGroup::~wxFileConfigGroup() { // entries - size_t n, nCount = m_aEntries.Count(); + size_t n, nCount = m_aEntries.GetCount(); for ( n = 0; n < nCount; n++ ) delete m_aEntries[n]; // subgroups - nCount = m_aSubgroups.Count(); + nCount = m_aSubgroups.GetCount(); for ( n = 0; n < nCount; n++ ) delete m_aSubgroups[n]; } @@ -1507,7 +1525,7 @@ void wxFileConfigGroup::UpdateGroupAndSubgroupsLines() // also update all subgroups as they have this groups name in their lines - const size_t nCount = m_aSubgroups.Count(); + const size_t nCount = m_aSubgroups.GetCount(); for ( size_t n = 0; n < nCount; n++ ) { m_aSubgroups[n]->UpdateGroupAndSubgroupsLines(); @@ -1548,11 +1566,11 @@ 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, - hi = m_aEntries.Count(); + hi = m_aEntries.GetCount(); int res; wxFileConfigEntry *pEntry; @@ -1561,9 +1579,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,11 +1596,11 @@ wxFileConfigGroup::FindEntry(const wxChar *szName) const } wxFileConfigGroup * -wxFileConfigGroup::FindSubgroup(const wxChar *szName) const +wxFileConfigGroup::FindSubgroup(const wxString& name) const { size_t i, lo = 0, - hi = m_aSubgroups.Count(); + hi = m_aSubgroups.GetCount(); int res; wxFileConfigGroup *pGroup; @@ -1591,9 +1609,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 +1662,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; } @@ -1673,7 +1691,7 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) : wxEmptyString ); // delete all entries... - size_t nCount = pGroup->m_aEntries.Count(); + size_t nCount = pGroup->m_aEntries.GetCount(); wxLogTrace(FILECONF_TRACE_MASK, _T("Removing %lu entries"), (unsigned long)nCount ); @@ -1692,7 +1710,7 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) } // ...and subgroups of this subgroup - nCount = pGroup->m_aSubgroups.Count(); + nCount = pGroup->m_aSubgroups.GetCount(); wxLogTrace( FILECONF_TRACE_MASK, _T("Removing %lu subgroups"), (unsigned long)nCount ); @@ -1726,11 +1744,11 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) // our last entry is being deleted, so find the last one which // stays by going back until we find a subgroup or reach the // group line - const size_t nSubgroups = m_aSubgroups.Count(); + const size_t nSubgroups = m_aSubgroups.GetCount(); m_pLastGroup = NULL; for ( wxFileConfigLineList *pl = pLine->Prev(); - pl && pl != m_pLine && !m_pLastGroup; + pl && !m_pLastGroup; pl = pl->Prev() ) { // does this line belong to our subgroup? @@ -1744,6 +1762,9 @@ bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) break; } } + + if ( pl == m_pLine ) + break; } } @@ -1762,9 +1783,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 @@ -1781,7 +1802,7 @@ bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) // go back until we find another entry or reach the group's line wxFileConfigEntry *pNewLast = NULL; - size_t n, nEntries = m_aEntries.Count(); + size_t n, nEntries = m_aEntries.GetCount(); wxFileConfigLineList *pl; for ( pl = pLine->Prev(); pl != m_pLine; pl = pl->Prev() ) { // is it our subgroup? @@ -1917,18 +1938,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 } @@ -1939,47 +1960,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