wxwidgets/src/common/fs_mem.cpp
Vadim Zeitlin 39bab48dee Fix dereferencing invalid iterator in wxMemoryFSHandlerBase
Don't assume that m_findIter is always valid initially, i.e. after
FindFirst() is called, as this is not the case if the memory FS is
empty, i.e. which no files had been added to it yet.

This also allows to simplify the iteration logic, as we don't need to
check m_findArgument (which, in turn, obviates the need to clear it when
we reach the end of the iteration) and can just use m_findIter directly.

Closes #18416.
2019-06-10 18:07:57 +02:00

273 lines
6.7 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/fs_mem.cpp
// Purpose: in-memory file system
// Author: Vaclav Slavik
// Copyright: (c) 2000 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_FILESYSTEM && wxUSE_STREAMS
#include "wx/fs_mem.h"
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/wxcrtvararg.h"
#if wxUSE_GUI
#include "wx/image.h"
#endif // wxUSE_GUI
#endif
#include "wx/mstream.h"
// represents a file entry in wxMemoryFS
class wxMemoryFSFile
{
public:
wxMemoryFSFile(const void *data, size_t len, const wxString& mime)
{
m_Data = new char[len];
memcpy(m_Data, data, len);
m_Len = len;
m_MimeType = mime;
InitTime();
}
wxMemoryFSFile(const wxMemoryOutputStream& stream, const wxString& mime)
{
m_Len = stream.GetSize();
m_Data = new char[m_Len];
stream.CopyTo(m_Data, m_Len);
m_MimeType = mime;
InitTime();
}
virtual ~wxMemoryFSFile()
{
delete[] m_Data;
}
char *m_Data;
size_t m_Len;
wxString m_MimeType;
#if wxUSE_DATETIME
wxDateTime m_Time;
#endif // wxUSE_DATETIME
private:
void InitTime()
{
#if wxUSE_DATETIME
m_Time = wxDateTime::Now();
#endif // wxUSE_DATETIME
}
wxDECLARE_NO_COPY_CLASS(wxMemoryFSFile);
};
#if wxUSE_BASE
//--------------------------------------------------------------------------------
// wxMemoryFSHandler
//--------------------------------------------------------------------------------
wxMemoryFSHash wxMemoryFSHandlerBase::m_Hash;
wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler()
{
}
wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase()
{
// as only one copy of FS handler is supposed to exist, we may silently
// delete static data here. (There is no way how to remove FS handler from
// wxFileSystem other than releasing _all_ handlers.)
WX_CLEAR_HASH_MAP(wxMemoryFSHash, m_Hash);
}
bool wxMemoryFSHandlerBase::CanOpen(const wxString& location)
{
return GetProtocol(location) == "memory";
}
wxFSFile * wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs),
const wxString& location)
{
wxMemoryFSHash::const_iterator i = m_Hash.find(GetRightLocation(location));
if ( i == m_Hash.end() )
return NULL;
const wxMemoryFSFile * const obj = i->second;
return new wxFSFile
(
new wxMemoryInputStream(obj->m_Data, obj->m_Len),
location,
obj->m_MimeType,
GetAnchor(location)
#if wxUSE_DATETIME
, obj->m_Time
#endif // wxUSE_DATETIME
);
}
wxString wxMemoryFSHandlerBase::FindFirst(const wxString& url, int flags)
{
if ( (flags & wxDIR) && !(flags & wxFILE) )
{
// we only store files, not directories, so we don't risk finding
// anything
return wxString();
}
const wxString spec = GetRightLocation(url);
if ( spec.find_first_of("?*") == wxString::npos )
{
// simple case: there are no wildcard characters so we can return
// either 0 or 1 results and we can find the potential match quickly
return m_Hash.count(spec) ? url : wxString();
}
//else: deal with wildcards in FindNext()
m_findArgument = spec;
m_findIter = m_Hash.begin();
return FindNext();
}
wxString wxMemoryFSHandlerBase::FindNext()
{
while ( m_findIter != m_Hash.end() )
{
const wxString& path = m_findIter->first;
// advance m_findIter first as we need to do it anyhow, whether it
// matches or not
++m_findIter;
if ( path.Matches(m_findArgument) )
return "memory:" + path;
}
return wxString();
}
bool wxMemoryFSHandlerBase::CheckDoesntExist(const wxString& filename)
{
if ( m_Hash.count(filename) )
{
wxLogError(_("Memory VFS already contains file '%s'!"), filename);
return false;
}
return true;
}
/*static*/
void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
const wxString& textdata,
const wxString& mimetype)
{
const wxCharBuffer buf(textdata.To8BitData());
AddFileWithMimeType(filename, buf.data(), buf.length(), mimetype);
}
/*static*/
void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
const void *binarydata, size_t size,
const wxString& mimetype)
{
if ( !CheckDoesntExist(filename) )
return;
m_Hash[filename] = new wxMemoryFSFile(binarydata, size, mimetype);
}
/*static*/
void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
const wxString& textdata)
{
AddFileWithMimeType(filename, textdata, wxEmptyString);
}
/*static*/
void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
const void *binarydata, size_t size)
{
AddFileWithMimeType(filename, binarydata, size, wxEmptyString);
}
/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename)
{
wxMemoryFSHash::iterator i = m_Hash.find(filename);
if ( i == m_Hash.end() )
{
wxLogError(_("Trying to remove file '%s' from memory VFS, "
"but it is not loaded!"),
filename);
return;
}
delete i->second;
m_Hash.erase(i);
}
#endif // wxUSE_BASE
#if wxUSE_GUI
#if wxUSE_IMAGE
/*static*/ void
wxMemoryFSHandler::AddFile(const wxString& filename,
const wxImage& image,
wxBitmapType type)
{
if ( !CheckDoesntExist(filename) )
return;
wxMemoryOutputStream mems;
if ( image.IsOk() && image.SaveFile(mems, type) )
{
m_Hash[filename] = new wxMemoryFSFile
(
mems,
wxImage::FindHandler(type)->GetMimeType()
);
}
else
{
wxLogError(_("Failed to store image '%s' to memory VFS!"), filename);
}
}
/*static*/ void
wxMemoryFSHandler::AddFile(const wxString& filename,
const wxBitmap& bitmap,
wxBitmapType type)
{
wxImage img = bitmap.ConvertToImage();
AddFile(filename, img, type);
}
#endif // wxUSE_IMAGE
#endif // wxUSE_GUI
#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP