1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/fs_mem.cpp
3 // Purpose:     in-memory file system
4 // Author:      Vaclav Slavik
5 // Copyright:   (c) 2000 Vaclav Slavik
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 #include "wx/wxprec.h"
10 
11 #ifdef __BORLANDC__
12     #pragma hdrstop
13 #endif
14 
15 #if wxUSE_FILESYSTEM && wxUSE_STREAMS
16 
17 #include "wx/fs_mem.h"
18 
19 #ifndef WX_PRECOMP
20     #include "wx/intl.h"
21     #include "wx/log.h"
22     #include "wx/wxcrtvararg.h"
23     #if wxUSE_GUI
24         #include "wx/image.h"
25     #endif // wxUSE_GUI
26 #endif
27 
28 #include "wx/mstream.h"
29 
30 // represents a file entry in wxMemoryFS
31 class wxMemoryFSFile
32 {
33 public:
wxMemoryFSFile(const void * data,size_t len,const wxString & mime)34     wxMemoryFSFile(const void *data, size_t len, const wxString& mime)
35     {
36         m_Data = new char[len];
37         memcpy(m_Data, data, len);
38         m_Len = len;
39         m_MimeType = mime;
40         InitTime();
41     }
42 
wxMemoryFSFile(const wxMemoryOutputStream & stream,const wxString & mime)43     wxMemoryFSFile(const wxMemoryOutputStream& stream, const wxString& mime)
44     {
45         m_Len = stream.GetSize();
46         m_Data = new char[m_Len];
47         stream.CopyTo(m_Data, m_Len);
48         m_MimeType = mime;
49         InitTime();
50     }
51 
~wxMemoryFSFile()52     virtual ~wxMemoryFSFile()
53     {
54         delete[] m_Data;
55     }
56 
57     char *m_Data;
58     size_t m_Len;
59     wxString m_MimeType;
60 #if wxUSE_DATETIME
61     wxDateTime m_Time;
62 #endif // wxUSE_DATETIME
63 
64 private:
InitTime()65     void InitTime()
66     {
67 #if wxUSE_DATETIME
68         m_Time = wxDateTime::Now();
69 #endif // wxUSE_DATETIME
70     }
71 
72     wxDECLARE_NO_COPY_CLASS(wxMemoryFSFile);
73 };
74 
75 #if wxUSE_BASE
76 
77 
78 //--------------------------------------------------------------------------------
79 // wxMemoryFSHandler
80 //--------------------------------------------------------------------------------
81 
82 
83 wxMemoryFSHash wxMemoryFSHandlerBase::m_Hash;
84 
85 
wxMemoryFSHandlerBase()86 wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler()
87 {
88 }
89 
~wxMemoryFSHandlerBase()90 wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase()
91 {
92     // as only one copy of FS handler is supposed to exist, we may silently
93     // delete static data here. (There is no way how to remove FS handler from
94     // wxFileSystem other than releasing _all_ handlers.)
95     WX_CLEAR_HASH_MAP(wxMemoryFSHash, m_Hash);
96 }
97 
CanOpen(const wxString & location)98 bool wxMemoryFSHandlerBase::CanOpen(const wxString& location)
99 {
100     return GetProtocol(location) == "memory";
101 }
102 
OpenFile(wxFileSystem & WXUNUSED (fs),const wxString & location)103 wxFSFile * wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs),
104                                            const wxString& location)
105 {
106     wxMemoryFSHash::const_iterator i = m_Hash.find(GetRightLocation(location));
107     if ( i == m_Hash.end() )
108         return NULL;
109 
110     const wxMemoryFSFile * const obj = i->second;
111 
112     return new wxFSFile
113                (
114                     new wxMemoryInputStream(obj->m_Data, obj->m_Len),
115                     location,
116                     obj->m_MimeType,
117                     GetAnchor(location)
118 #if wxUSE_DATETIME
119                     , obj->m_Time
120 #endif // wxUSE_DATETIME
121                );
122 }
123 
FindFirst(const wxString & url,int flags)124 wxString wxMemoryFSHandlerBase::FindFirst(const wxString& url, int flags)
125 {
126     if ( (flags & wxDIR) && !(flags & wxFILE) )
127     {
128         // we only store files, not directories, so we don't risk finding
129         // anything
130         return wxString();
131     }
132 
133     const wxString spec = GetRightLocation(url);
134     if ( spec.find_first_of("?*") == wxString::npos )
135     {
136         // simple case: there are no wildcard characters so we can return
137         // either 0 or 1 results and we can find the potential match quickly
138         return m_Hash.count(spec) ? url : wxString();
139     }
140     //else: deal with wildcards in FindNext()
141 
142     m_findArgument = spec;
143     m_findIter = m_Hash.begin();
144 
145     return FindNext();
146 }
147 
FindNext()148 wxString wxMemoryFSHandlerBase::FindNext()
149 {
150     // m_findArgument is used to indicate that search is in progress, we reset
151     // it to empty string after iterating over all elements
152     while ( !m_findArgument.empty() )
153     {
154         // test for the match before (possibly) clearing m_findArgument below
155         const bool found = m_findIter->first.Matches(m_findArgument);
156 
157         // advance m_findIter first as we need to do it anyhow, whether it
158         // matches or not
159         const wxMemoryFSHash::const_iterator current = m_findIter;
160 
161         if ( ++m_findIter == m_Hash.end() )
162             m_findArgument.clear();
163 
164         if ( found )
165             return "memory:" + current->first;
166     }
167 
168     return wxString();
169 }
170 
CheckDoesntExist(const wxString & filename)171 bool wxMemoryFSHandlerBase::CheckDoesntExist(const wxString& filename)
172 {
173     if ( m_Hash.count(filename) )
174     {
175         wxLogError(_("Memory VFS already contains file '%s'!"), filename);
176         return false;
177     }
178 
179     return true;
180 }
181 
182 
183 /*static*/
AddFileWithMimeType(const wxString & filename,const wxString & textdata,const wxString & mimetype)184 void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
185                                                 const wxString& textdata,
186                                                 const wxString& mimetype)
187 {
188     const wxCharBuffer buf(textdata.To8BitData());
189 
190     AddFileWithMimeType(filename, buf.data(), buf.length(), mimetype);
191 }
192 
193 
194 /*static*/
AddFileWithMimeType(const wxString & filename,const void * binarydata,size_t size,const wxString & mimetype)195 void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename,
196                                                 const void *binarydata, size_t size,
197                                                 const wxString& mimetype)
198 {
199     if ( !CheckDoesntExist(filename) )
200         return;
201 
202     m_Hash[filename] = new wxMemoryFSFile(binarydata, size, mimetype);
203 }
204 
205 /*static*/
AddFile(const wxString & filename,const wxString & textdata)206 void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
207                                     const wxString& textdata)
208 {
209     AddFileWithMimeType(filename, textdata, wxEmptyString);
210 }
211 
212 
213 /*static*/
AddFile(const wxString & filename,const void * binarydata,size_t size)214 void wxMemoryFSHandlerBase::AddFile(const wxString& filename,
215                                     const void *binarydata, size_t size)
216 {
217     AddFileWithMimeType(filename, binarydata, size, wxEmptyString);
218 }
219 
220 
221 
RemoveFile(const wxString & filename)222 /*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename)
223 {
224     wxMemoryFSHash::iterator i = m_Hash.find(filename);
225     if ( i == m_Hash.end() )
226     {
227         wxLogError(_("Trying to remove file '%s' from memory VFS, "
228                      "but it is not loaded!"),
229                    filename);
230         return;
231     }
232 
233     delete i->second;
234     m_Hash.erase(i);
235 }
236 
237 #endif // wxUSE_BASE
238 
239 #if wxUSE_GUI
240 
241 #if wxUSE_IMAGE
242 /*static*/ void
AddFile(const wxString & filename,const wxImage & image,wxBitmapType type)243 wxMemoryFSHandler::AddFile(const wxString& filename,
244                            const wxImage& image,
245                            wxBitmapType type)
246 {
247     if ( !CheckDoesntExist(filename) )
248         return;
249 
250     wxMemoryOutputStream mems;
251     if ( image.IsOk() && image.SaveFile(mems, type) )
252     {
253         m_Hash[filename] = new wxMemoryFSFile
254                                (
255                                     mems,
256                                     wxImage::FindHandler(type)->GetMimeType()
257                                );
258     }
259     else
260     {
261         wxLogError(_("Failed to store image '%s' to memory VFS!"), filename);
262     }
263 }
264 
265 /*static*/ void
AddFile(const wxString & filename,const wxBitmap & bitmap,wxBitmapType type)266 wxMemoryFSHandler::AddFile(const wxString& filename,
267                            const wxBitmap& bitmap,
268                            wxBitmapType type)
269 {
270     wxImage img = bitmap.ConvertToImage();
271     AddFile(filename, img, type);
272 }
273 
274 #endif // wxUSE_IMAGE
275 
276 #endif // wxUSE_GUI
277 
278 
279 #endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP
280