From ca405352e0507a8020555f5d3064082dadc80211 Mon Sep 17 00:00:00 2001 From: Viachaslau Lisouski Date: Fri, 15 Dec 2023 09:07:39 +0100 Subject: [PATCH] Add wxFileSystemHandler for "data" scheme This notably allows embedding images directly in HTML. Closes #24138. --- Makefile.in | 19 +++++ build/bakefiles/files.bkl | 2 + build/cmake/files.cmake | 2 + build/files | 2 + build/msw/makefile.gcc | 16 ++++ build/msw/makefile.vc | 16 ++++ build/msw/wx_base.vcxproj | 2 + build/msw/wx_base.vcxproj.filters | 6 ++ docs/doxygen/overviews/filesystem.h | 4 + include/wx/fs_data.h | 31 +++++++ interface/wx/fs_data.h | 31 +++++++ src/common/fs_data.cpp | 126 ++++++++++++++++++++++++++++ tests/allheaders.h | 1 + tests/filesys/filesystest.cpp | 49 ++++++++++- 14 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 include/wx/fs_data.h create mode 100644 interface/wx/fs_data.h create mode 100644 src/common/fs_data.cpp diff --git a/Makefile.in b/Makefile.in index b3ec7f42600f..67bdae4306ad 100644 --- a/Makefile.in +++ b/Makefile.in @@ -603,6 +603,7 @@ ALL_BASE_HEADERS = \ wx/lzmastream.h \ wx/localedefs.h \ wx/uilocale.h \ + wx/fs_data.h \ $(BASE_PLATFORM_HDR) \ wx/fs_inet.h \ wx/protocol/file.h \ @@ -789,6 +790,7 @@ ALL_PORTS_BASE_HEADERS = \ wx/lzmastream.h \ wx/localedefs.h \ wx/uilocale.h \ + wx/fs_data.h \ wx/unix/app.h \ wx/unix/apptbase.h \ wx/unix/apptrait.h \ @@ -925,6 +927,7 @@ ALL_BASE_SOURCES = \ src/common/secretstore.cpp \ src/common/lzmastream.cpp \ src/common/uilocale.cpp \ + src/common/fs_data.cpp \ src/common/fdiodispatcher.cpp \ src/common/selectdispatcher.cpp \ src/unix/appunix.cpp \ @@ -1130,6 +1133,7 @@ MONODLL_OBJECTS = \ monodll_common_secretstore.o \ monodll_lzmastream.o \ monodll_common_uilocale.o \ + monodll_fs_data.o \ $(__BASE_PLATFORM_SRC_OBJECTS) \ monodll_event.o \ monodll_fs_mem.o \ @@ -1289,6 +1293,7 @@ MONOLIB_OBJECTS = \ monolib_common_secretstore.o \ monolib_lzmastream.o \ monolib_common_uilocale.o \ + monolib_fs_data.o \ $(__BASE_PLATFORM_SRC_OBJECTS_1) \ monolib_event.o \ monolib_fs_mem.o \ @@ -1417,6 +1422,7 @@ BASEDLL_OBJECTS = \ basedll_common_secretstore.o \ basedll_lzmastream.o \ basedll_common_uilocale.o \ + basedll_fs_data.o \ $(__BASE_PLATFORM_SRC_OBJECTS_2) \ basedll_event.o \ basedll_fs_mem.o \ @@ -1527,6 +1533,7 @@ BASELIB_OBJECTS = \ baselib_common_secretstore.o \ baselib_lzmastream.o \ baselib_common_uilocale.o \ + baselib_fs_data.o \ $(__BASE_PLATFORM_SRC_OBJECTS_3) \ baselib_event.o \ baselib_fs_mem.o \ @@ -14966,6 +14973,9 @@ monodll_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(MONODLL_ODEP) monodll_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp +monodll_fs_data.o: $(srcdir)/src/common/fs_data.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/common/fs_data.cpp + monodll_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -19712,6 +19722,9 @@ monolib_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(MONOLIB_ODEP) monolib_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp +monolib_fs_data.o: $(srcdir)/src/common/fs_data.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/common/fs_data.cpp + monolib_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -24458,6 +24471,9 @@ basedll_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(BASEDLL_ODEP) basedll_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp +basedll_fs_data.o: $(srcdir)/src/common/fs_data.cpp $(BASEDLL_ODEP) + $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/common/fs_data.cpp + basedll_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(BASEDLL_ODEP) $(CXXC) -c -o $@ $(BASEDLL_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp @@ -24938,6 +24954,9 @@ baselib_lzmastream.o: $(srcdir)/src/common/lzmastream.cpp $(BASELIB_ODEP) baselib_common_uilocale.o: $(srcdir)/src/common/uilocale.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/common/uilocale.cpp +baselib_fs_data.o: $(srcdir)/src/common/fs_data.cpp $(BASELIB_ODEP) + $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/common/fs_data.cpp + baselib_unix_mimetype.o: $(srcdir)/src/unix/mimetype.cpp $(BASELIB_ODEP) $(CXXC) -c -o $@ $(BASELIB_CXXFLAGS) $(srcdir)/src/unix/mimetype.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index ec7c3637fcef..ba64fd032a5d 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -580,6 +580,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/secretstore.cpp src/common/lzmastream.cpp src/common/uilocale.cpp + src/common/fs_data.cpp src/common/event.cpp @@ -755,6 +756,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/lzmastream.h wx/localedefs.h wx/uilocale.h + wx/fs_data.h diff --git a/build/cmake/files.cmake b/build/cmake/files.cmake index d04334668e5b..691d5e744ef8 100644 --- a/build/cmake/files.cmake +++ b/build/cmake/files.cmake @@ -492,6 +492,7 @@ set(BASE_CMN_SRC src/generic/fswatcherg.cpp src/common/lzmastream.cpp src/common/uilocale.cpp + src/common/fs_data.cpp ) set(BASE_AND_GUI_CMN_SRC @@ -669,6 +670,7 @@ set(BASE_CMN_HDR wx/lzmastream.h wx/localedefs.h wx/uilocale.h + wx/fs_data.h ) set(NET_UNIX_SRC diff --git a/build/files b/build/files index a25c4205448b..730b5c812442 100644 --- a/build/files +++ b/build/files @@ -455,6 +455,7 @@ BASE_CMN_SRC = src/common/filtfind.cpp src/common/fmapbase.cpp src/common/fs_arc.cpp + src/common/fs_data.cpp src/common/fs_filter.cpp src/common/hash.cpp src/common/hashmap.cpp @@ -571,6 +572,7 @@ BASE_CMN_HDR = wx/fontenc.h wx/fontmap.h wx/fs_arc.h + wx/fs_data.h wx/fs_filter.h wx/fs_mem.h wx/fs_zip.h diff --git a/build/msw/makefile.gcc b/build/msw/makefile.gcc index 80cb9d684dba..1c91477dc5f1 100644 --- a/build/msw/makefile.gcc +++ b/build/msw/makefile.gcc @@ -498,6 +498,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_common_secretstore.o \ $(OBJS)\monodll_lzmastream.o \ $(OBJS)\monodll_common_uilocale.o \ + $(OBJS)\monodll_fs_data.o \ $(OBJS)\monodll_basemsw.o \ $(OBJS)\monodll_crashrpt.o \ $(OBJS)\monodll_debughlp.o \ @@ -659,6 +660,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_common_secretstore.o \ $(OBJS)\monolib_lzmastream.o \ $(OBJS)\monolib_common_uilocale.o \ + $(OBJS)\monolib_fs_data.o \ $(OBJS)\monolib_basemsw.o \ $(OBJS)\monolib_crashrpt.o \ $(OBJS)\monolib_debughlp.o \ @@ -808,6 +810,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_common_secretstore.o \ $(OBJS)\basedll_lzmastream.o \ $(OBJS)\basedll_common_uilocale.o \ + $(OBJS)\basedll_fs_data.o \ $(OBJS)\basedll_basemsw.o \ $(OBJS)\basedll_crashrpt.o \ $(OBJS)\basedll_debughlp.o \ @@ -938,6 +941,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_common_secretstore.o \ $(OBJS)\baselib_lzmastream.o \ $(OBJS)\baselib_common_uilocale.o \ + $(OBJS)\baselib_fs_data.o \ $(OBJS)\baselib_basemsw.o \ $(OBJS)\baselib_crashrpt.o \ $(OBJS)\baselib_debughlp.o \ @@ -7235,6 +7239,9 @@ $(OBJS)\monodll_lzmastream.o: ../../src/common/lzmastream.cpp $(OBJS)\monodll_common_uilocale.o: ../../src/common/uilocale.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monodll_fs_data.o: ../../src/common/fs_data.cpp + $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monodll_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(MONODLL_CXXFLAGS) $(CPPDEPS) $< @@ -9826,6 +9833,9 @@ $(OBJS)\monolib_lzmastream.o: ../../src/common/lzmastream.cpp $(OBJS)\monolib_common_uilocale.o: ../../src/common/uilocale.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\monolib_fs_data.o: ../../src/common/fs_data.cpp + $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\monolib_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(MONOLIB_CXXFLAGS) $(CPPDEPS) $< @@ -12417,6 +12427,9 @@ $(OBJS)\basedll_lzmastream.o: ../../src/common/lzmastream.cpp $(OBJS)\basedll_common_uilocale.o: ../../src/common/uilocale.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\basedll_fs_data.o: ../../src/common/fs_data.cpp + $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\basedll_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(BASEDLL_CXXFLAGS) $(CPPDEPS) $< @@ -12759,6 +12772,9 @@ $(OBJS)\baselib_lzmastream.o: ../../src/common/lzmastream.cpp $(OBJS)\baselib_common_uilocale.o: ../../src/common/uilocale.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\baselib_fs_data.o: ../../src/common/fs_data.cpp + $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\baselib_basemsw.o: ../../src/msw/basemsw.cpp $(CXX) -c -o $@ $(BASELIB_CXXFLAGS) $(CPPDEPS) $< diff --git a/build/msw/makefile.vc b/build/msw/makefile.vc index a86e81109b02..8bb1f4ebf5d5 100644 --- a/build/msw/makefile.vc +++ b/build/msw/makefile.vc @@ -534,6 +534,7 @@ MONODLL_OBJECTS = \ $(OBJS)\monodll_common_secretstore.obj \ $(OBJS)\monodll_lzmastream.obj \ $(OBJS)\monodll_common_uilocale.obj \ + $(OBJS)\monodll_fs_data.obj \ $(OBJS)\monodll_basemsw.obj \ $(OBJS)\monodll_crashrpt.obj \ $(OBJS)\monodll_debughlp.obj \ @@ -704,6 +705,7 @@ MONOLIB_OBJECTS = \ $(OBJS)\monolib_common_secretstore.obj \ $(OBJS)\monolib_lzmastream.obj \ $(OBJS)\monolib_common_uilocale.obj \ + $(OBJS)\monolib_fs_data.obj \ $(OBJS)\monolib_basemsw.obj \ $(OBJS)\monolib_crashrpt.obj \ $(OBJS)\monolib_debughlp.obj \ @@ -862,6 +864,7 @@ BASEDLL_OBJECTS = \ $(OBJS)\basedll_common_secretstore.obj \ $(OBJS)\basedll_lzmastream.obj \ $(OBJS)\basedll_common_uilocale.obj \ + $(OBJS)\basedll_fs_data.obj \ $(OBJS)\basedll_basemsw.obj \ $(OBJS)\basedll_crashrpt.obj \ $(OBJS)\basedll_debughlp.obj \ @@ -1002,6 +1005,7 @@ BASELIB_OBJECTS = \ $(OBJS)\baselib_common_secretstore.obj \ $(OBJS)\baselib_lzmastream.obj \ $(OBJS)\baselib_common_uilocale.obj \ + $(OBJS)\baselib_fs_data.obj \ $(OBJS)\baselib_basemsw.obj \ $(OBJS)\baselib_crashrpt.obj \ $(OBJS)\baselib_debughlp.obj \ @@ -7692,6 +7696,9 @@ $(OBJS)\monodll_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(OBJS)\monodll_common_uilocale.obj: ..\..\src\common\uilocale.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\uilocale.cpp +$(OBJS)\monodll_fs_data.obj: ..\..\src\common\fs_data.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\common\fs_data.cpp + $(OBJS)\monodll_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONODLL_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -10283,6 +10290,9 @@ $(OBJS)\monolib_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(OBJS)\monolib_common_uilocale.obj: ..\..\src\common\uilocale.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\uilocale.cpp +$(OBJS)\monolib_fs_data.obj: ..\..\src\common\fs_data.cpp + $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\common\fs_data.cpp + $(OBJS)\monolib_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(MONOLIB_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -12874,6 +12884,9 @@ $(OBJS)\basedll_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(OBJS)\basedll_common_uilocale.obj: ..\..\src\common\uilocale.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\common\uilocale.cpp +$(OBJS)\basedll_fs_data.obj: ..\..\src\common\fs_data.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\common\fs_data.cpp + $(OBJS)\basedll_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASEDLL_CXXFLAGS) ..\..\src\msw\basemsw.cpp @@ -13216,6 +13229,9 @@ $(OBJS)\baselib_lzmastream.obj: ..\..\src\common\lzmastream.cpp $(OBJS)\baselib_common_uilocale.obj: ..\..\src\common\uilocale.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\common\uilocale.cpp +$(OBJS)\baselib_fs_data.obj: ..\..\src\common\fs_data.cpp + $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\common\fs_data.cpp + $(OBJS)\baselib_basemsw.obj: ..\..\src\msw\basemsw.cpp $(CXX) /c /nologo /TP /Fo$@ $(BASELIB_CXXFLAGS) ..\..\src\msw\basemsw.cpp diff --git a/build/msw/wx_base.vcxproj b/build/msw/wx_base.vcxproj index f7ae10368814..ec67b604be08 100644 --- a/build/msw/wx_base.vcxproj +++ b/build/msw/wx_base.vcxproj @@ -622,6 +622,7 @@ $(IntDir)common_%(Filename).obj $(IntDir)common_%(Filename).obj + @@ -841,6 +842,7 @@ + diff --git a/build/msw/wx_base.vcxproj.filters b/build/msw/wx_base.vcxproj.filters index fc5b55840e38..f0068f642784 100644 --- a/build/msw/wx_base.vcxproj.filters +++ b/build/msw/wx_base.vcxproj.filters @@ -123,6 +123,9 @@ Common Sources + + Common Sources + Common Sources @@ -535,6 +538,9 @@ Common Headers + + Common Headers + Common Headers diff --git a/docs/doxygen/overviews/filesystem.h b/docs/doxygen/overviews/filesystem.h index 5a83c9741321..ea0cd30c93d9 100644 --- a/docs/doxygen/overviews/filesystem.h +++ b/docs/doxygen/overviews/filesystem.h @@ -73,6 +73,10 @@ The following virtual file system handlers are part of wxWidgets so far: A handler for archives such as zip and tar. Include file is wx/fs_arc.h. URLs examples: "archive.zip#zip:filename", "archive.tar.gz#gzip:#tar:filename". +@li @b wxDataSchemeFSHandler: + A handler for accessing data inlined in URI according to RFC 2397. + URI example: "data:text/plain;base64,d3hXaWRnZXRzIGV4YW1wbGU=". + Include file is wx/fs_data.h. @li @b wxFilterFSHandler: A handler for compression schemes such as gzip. Header is wx/fs_filter.h. URLs are in the form, e.g.: diff --git a/include/wx/fs_data.h b/include/wx/fs_data.h new file mode 100644 index 000000000000..eea524a42501 --- /dev/null +++ b/include/wx/fs_data.h @@ -0,0 +1,31 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/fs_data.h +// Purpose: DATA scheme file system. +// Author: Vyacheslav Lisovski +// Copyright: (c) 2023 Vyacheslav Lisovski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_FS_DATA_H_ +#define _WX_FS_DATA_H_ + +#include "wx/defs.h" + +#if wxUSE_FILESYSTEM + +#include "wx/filesys.h" + +// ---------------------------------------------------------------------------- +// wxDataSchemeFSHandler +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxDataSchemeFSHandler : public wxFileSystemHandler +{ +public: + virtual bool CanOpen(const wxString& location) override; + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location) override; +}; + +#endif // wxUSE_FILESYSTEM + +#endif // _WX_FS_DATA_H_ diff --git a/interface/wx/fs_data.h b/interface/wx/fs_data.h new file mode 100644 index 000000000000..4d6a9f907b55 --- /dev/null +++ b/interface/wx/fs_data.h @@ -0,0 +1,31 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/fs_data.h +// Purpose: DATA scheme file system +// Author: Vyacheslav Lisovski +// Copyright: (c) 2023 Vyacheslav Lisovski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/** + @class wxDataSchemeFSHandler + + File system handler for "data" URI scheme (RFC 2397). + URI syntax: @c "data:[][;base64],". + + The handler makes the data, included (encoded) into URI, available for + components that use the wxFileSystem infrastructure. + + To make available for usage it should be registered somewhere within an + initialization procedure: + @code + wxFileSystem::AddHandler(new wxDataSchemeFSHandler); + @endcode + + @since 3.3.0 +*/ + +class wxDataSchemeFSHandler : public wxFileSystemHandler +{ +public: + wxDataSchemeFSHandler(); +}; diff --git a/src/common/fs_data.cpp b/src/common/fs_data.cpp new file mode 100644 index 000000000000..4eb8b3560200 --- /dev/null +++ b/src/common/fs_data.cpp @@ -0,0 +1,126 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_data.cpp +// Purpose: DATA scheme file system +// Author: Vyacheslav Lisovski +// Copyright: (c) 2023 Vyacheslav Lisovski +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#if wxUSE_FILESYSTEM + +#include "wx/fs_data.h" + +#include "wx/base64.h" +#include "wx/filesys.h" +#include "wx/mstream.h" +#include "wx/sstream.h" +#include "wx/uri.h" + +namespace +{ + +// This stream holds the buffer and deletes when destroyed +class wxBufferedMemoryInputStream : public wxMemoryInputStream +{ +public: + wxBufferedMemoryInputStream(const wxMemoryBuffer& buffer) : + wxMemoryInputStream(buffer.GetData(), buffer.GetDataLen()), + m_buffer{buffer} + { + } + +private: + wxMemoryBuffer m_buffer; +}; + +// URL syntax: data:[][;base64], +int GetMetadata(const wxString& location, wxString& mediatype, bool& isBase64) +{ + int dataPos = location.Find(','); + if (dataPos > 0) + { + const int hdrPos = location.Find(':'); + if (hdrPos > 0) + { + wxString metadata(location, hdrPos + 1, dataPos - hdrPos - 1); + + int encPos = metadata.Find(';', true); + + if (encPos > 0) + { + auto encoding = metadata.Right(metadata.Len() - encPos - 1); + if (encoding.IsSameAs("base64", false)) + { + isBase64 = true; + } + else + { + encPos = metadata.Len(); + } + } + else + encPos = metadata.Len(); + + mediatype = metadata.Left(encPos); + } + ++dataPos; + } + return dataPos; +} + +} // anonymous namespace + +// ---------------------------------------------------------------------------- +// wxDataSchemeFSHandler +// ---------------------------------------------------------------------------- + +bool wxDataSchemeFSHandler::CanOpen(const wxString& location) +{ + return GetProtocol(location).IsSameAs("data", false); +} + +wxFSFile* wxDataSchemeFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), + const wxString& location) +{ + wxString mediatype; + bool isBase64 = false; + int dataPos = GetMetadata(location, mediatype, isBase64); + + if (dataPos < 0) + return nullptr; + + if (mediatype.IsEmpty()) + mediatype = "text/plain"; + + wxInputStream* stream = nullptr; + if (isBase64) + { +#if wxUSE_BASE64 + stream = new wxBufferedMemoryInputStream( + wxBase64Decode(location.Right(location.Len() - dataPos))); +#endif // wxUSE_BASE64 + } + else + { + stream = new wxStringInputStream( + wxURI::Unescape(location.Right(location.Len() - dataPos))); + } + + if (stream) + { + return new wxFSFile(stream, + "", + mediatype, + "" +#if wxUSE_DATETIME + , wxDateTime::Now() +#endif // wxUSE_DATETIME + ); + } + + return nullptr; +} + +#endif // wxUSE_FILESYSTEM diff --git a/tests/allheaders.h b/tests/allheaders.h index 2bd780326d2d..01368c927ecf 100644 --- a/tests/allheaders.h +++ b/tests/allheaders.h @@ -152,6 +152,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/filesys/filesystest.cpp b/tests/filesys/filesystest.cpp index 85aaae0317a7..ceea56cf63eb 100644 --- a/tests/filesys/filesystest.cpp +++ b/tests/filesys/filesystest.cpp @@ -1,7 +1,7 @@ /////////////////////////////////////////////////////////////////////////////// // Name: tests/filesys/filesys.cpp // Purpose: wxFileSystem unit test -// Author: Vaclav Slavik +// Author: Vaclav Slavik, Vyacheslav Lisovski // Created: 2004-03-28 // Copyright: (c) 2004 Vaclav Slavik /////////////////////////////////////////////////////////////////////////////// @@ -21,7 +21,9 @@ #if wxUSE_FILESYSTEM +#include "wx/fs_data.h" #include "wx/fs_mem.h" +#include "wx/sstream.h" #include @@ -177,6 +179,51 @@ TEST_CASE("wxFileSystem::UnicodeFileNameToUrlConversion", "[filesys][url][filena CHECK( filename.SameAs(wxFileName::URLToFileName(url)) ); } +TEST_CASE("wxFileSystem::DataSchemeFSHandler", "[filesys][dataschemefshandler][openfile]") +{ + // Install wxDataSchemeFSHandler just for the duration of this test. + class AutoDataSchemeFSHandler + { + public: + AutoDataSchemeFSHandler() : m_handler(new wxDataSchemeFSHandler()) + { + wxFileSystem::AddHandler(m_handler.get()); + } + ~AutoDataSchemeFSHandler() + { + wxFileSystem::RemoveHandler(m_handler.get()); + } + private: + std::unique_ptr const m_handler; + } autoDataSchemeFSHandler; + + wxFileSystem fs; + + const struct wxTestCaseData + { + const char *info, *input, *result1, *result2; + } testData[] = + { + { "Testing minimal URI with data", + "data:,the%20data", "text/plain", "the data" }, + { "Testing base64 encoded", + "data:x-t1/x-s1;base64,SGVsbG8sIFdvcmxkIQ==", "x-t1/x-s1", "Hello, World!" }, + { "Testing complex media type", + "data:image/svg+xml;utf8,", "image/svg+xml;utf8", "" } + }; + + for ( const auto& dataItem : testData ) + { + INFO(dataItem.info); + std::unique_ptr file(fs.OpenFile(dataItem.input)); + CHECK(file->GetMimeType() == dataItem.result1); + + wxStringOutputStream sos; + sos.Write(*file->GetStream()); + CHECK(sos.GetString () == dataItem.result2); + } +} + // Test that using FindFirst() after removing a previously found URL works: // this used to be broken, see https://github.com/wxWidgets/wxWidgets/issues/18744 TEST_CASE("wxFileSystem::MemoryFSHandler", "[filesys][memoryfshandler][find]")