#include "wx/fileconf.h"
#include "wx/filefn.h"
+#include "wx/base64.h"
+
#include "wx/stdpaths.h"
#if defined(__WXMAC__)
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);
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 */);
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 )
// skip leading spaces
- for ( pStart = strLine; wxIsspace(*pStart); pStart++ )
+ for ( pStart = buf; wxIsspace(*pStart); pStart++ )
;
// skip blank/comment lines
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);
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() )
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
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());
// 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,
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 )
}
wxFileConfigGroup *
-wxFileConfigGroup::FindSubgroup(const wxChar *szName) const
+wxFileConfigGroup::FindSubgroup(const wxString& name) const
{
size_t i,
lo = 0,
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 )
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;
}
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?
break;
}
}
+
+ if ( pl == m_pLine )
+ break;
}
}
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
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
}
// 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