├── .gitattributes
├── .gitignore
├── Import
├── Vlpp.Linux.cpp
├── Vlpp.Windows.cpp
├── Vlpp.cpp
└── Vlpp.h
├── LICENSE.md
├── README.md
├── Release
├── CodegenConfig.xml
├── IncludeOnly
│ ├── VlppOS.Linux.cpp
│ ├── VlppOS.Windows.cpp
│ ├── VlppOS.cpp
│ └── VlppOS.h
├── VlppOS.Linux.cpp
├── VlppOS.Windows.cpp
├── VlppOS.cpp
└── VlppOS.h
├── Source
├── Encoding
│ ├── Base64Encoding.cpp
│ ├── Base64Encoding.h
│ ├── CharFormat
│ │ ├── BomEncoding.cpp
│ │ ├── BomEncoding.h
│ │ ├── CharFormat.Linux.cpp
│ │ ├── CharFormat.Windows.cpp
│ │ ├── CharFormat.cpp
│ │ ├── CharFormat.h
│ │ ├── MbcsEncoding.cpp
│ │ ├── MbcsEncoding.h
│ │ ├── UtfEncoding.cpp
│ │ └── UtfEncoding.h
│ ├── Encoding.cpp
│ ├── Encoding.h
│ ├── LzwEncoding.cpp
│ └── LzwEncoding.h
├── FileSystem.Linux.cpp
├── FileSystem.Windows.cpp
├── FileSystem.cpp
├── FileSystem.h
├── HttpUtility.Windows.cpp
├── HttpUtility.h
├── Locale.Linux.cpp
├── Locale.Windows.cpp
├── Locale.cpp
├── Locale.h
├── Stream
│ ├── Accessor.cpp
│ ├── Accessor.h
│ ├── BroadcastStream.cpp
│ ├── BroadcastStream.h
│ ├── CacheStream.cpp
│ ├── CacheStream.h
│ ├── EncodingStream.cpp
│ ├── EncodingStream.h
│ ├── FileStream.cpp
│ ├── FileStream.h
│ ├── Interfaces.h
│ ├── MemoryStream.cpp
│ ├── MemoryStream.h
│ ├── MemoryWrapperStream.cpp
│ ├── MemoryWrapperStream.h
│ ├── RecorderStream.cpp
│ ├── RecorderStream.h
│ └── Serialization.h
├── Threading.Linux.cpp
├── Threading.Windows.cpp
├── Threading.cpp
└── Threading.h
├── TODO.md
└── Test
├── Linux
├── Main.cpp
├── makefile
└── vmake
├── Source
├── TestFileSystem.cpp
├── TestLocale.cpp
├── TestLocaleString.cpp
├── TestSerialization.cpp
├── TestStream.cpp
├── TestStreamBase64.cpp
├── TestStreamEncoding.cpp
├── TestStreamLzw.cpp
├── TestStreamReaderWriter.cpp
└── TestThread.cpp
└── UnitTest
├── UnitTest.sln
└── UnitTest
├── Main.cpp
├── UnitTest.vcxproj
└── UnitTest.vcxproj.filters
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | #Vczh Libraries
5 | .Output/
6 | Test/Output/
7 | Test/Linux/Coverage/
8 | Tools/*.exe
9 | Tools/*.dll
10 |
11 | # User-specific files
12 | */**/.vs/
13 | *.suo
14 | *.user
15 | *.sln.docstates
16 |
17 | # Build results
18 |
19 | */**/[Dd]ebugNoReflection/
20 | */**/[Dd]ebug/
21 | */**/[Rr]elease/
22 | */**/x64/
23 | */**/build/
24 | */**/[Bb]in/
25 | */**/[Oo]bj/
26 |
27 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
28 | !packages/*/build/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | *_i.c
35 | *_p.c
36 | *.ilk
37 | *.meta
38 | *.obj
39 | *.pch
40 | *.pdb
41 | *.pgc
42 | *.pgd
43 | *.rsp
44 | *.sbr
45 | *.tlb
46 | *.tli
47 | *.tlh
48 | *.tmp
49 | *.tmp_proj
50 | *.log
51 | *.vspscc
52 | *.vssscc
53 | .builds
54 | *.pidb
55 | *.log
56 | *.scc
57 |
58 | # Visual C++ cache files
59 | ipch/
60 | *.aps
61 | *.ncb
62 | *.opensdf
63 | *.sdf
64 | *.cachefile
65 | *.VC.db
66 | *.VC.db-*
67 | *.VC.opendb
68 | *.VC.VC.opendb
69 |
70 | # Visual Studio profiler
71 | *.psess
72 | *.vsp
73 | *.vspx
74 |
75 | # Guidance Automation Toolkit
76 | *.gpState
77 |
78 | # ReSharper is a .NET coding add-in
79 | _ReSharper*/
80 | *.[Rr]e[Ss]harper
81 |
82 | # TeamCity is a build add-in
83 | _TeamCity*
84 |
85 | # DotCover is a Code Coverage Tool
86 | *.dotCover
87 |
88 | # NCrunch
89 | *.ncrunch*
90 | .*crunch*.local.xml
91 |
92 | # Installshield output folder
93 | [Ee]xpress/
94 |
95 | # DocProject is a documentation generator add-in
96 | DocProject/buildhelp/
97 | DocProject/Help/*.HxT
98 | DocProject/Help/*.HxC
99 | DocProject/Help/*.hhc
100 | DocProject/Help/*.hhk
101 | DocProject/Help/*.hhp
102 | DocProject/Help/Html2
103 | DocProject/Help/html
104 |
105 | # Click-Once directory
106 | publish/
107 |
108 | # Publish Web Output
109 | *.Publish.xml
110 |
111 | # NuGet Packages Directory
112 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
113 | #packages/
114 |
115 | # Windows Azure Build Output
116 | csx
117 | *.build.csdef
118 |
119 | # Windows Store app package directory
120 | AppPackages/
121 |
122 | # Others
123 | sql/
124 | *.Cache
125 | ClientBin/
126 | [Ss]tyle[Cc]op.*
127 | ~$*
128 | *~
129 | *.dbmdl
130 | *.[Pp]ublish.xml
131 | *.pfx
132 | *.publishsettings
133 |
134 | # RIA/Silverlight projects
135 | Generated_Code/
136 |
137 | # Backup & report files from converting an old project file to a newer
138 | # Visual Studio version. Backup files are not needed, because we have git ;-)
139 | _UpgradeReport_Files/
140 | Backup*/
141 | UpgradeLog*.XML
142 | UpgradeLog*.htm
143 |
144 | # SQL Server files
145 | App_Data/*.mdf
146 | App_Data/*.ldf
147 |
148 |
149 | #LightSwitch generated files
150 | GeneratedArtifacts/
151 | _Pvt_Extensions/
152 | ModelManifest.xml
153 |
154 | # =========================
155 | # Windows detritus
156 | # =========================
157 |
158 | # Windows image file caches
159 | Thumbs.db
160 | ehthumbs.db
161 |
162 | # Folder config file
163 | Desktop.ini
164 |
165 | # Recycle Bin used on file shares
166 | $RECYCLE.BIN/
167 |
168 | # Mac desktop service store files
169 | .DS_Store
170 |
--------------------------------------------------------------------------------
/Import/Vlpp.Linux.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
3 | DEVELOPER: Zihan Chen(vczh)
4 | ***********************************************************************/
5 | #include "Vlpp.h"
6 |
7 | /***********************************************************************
8 | .\CONSOLE.LINUX.CPP
9 | ***********************************************************************/
10 | /***********************************************************************
11 | Author: Zihan Chen (vczh)
12 | Licensed under https://github.com/vczh-libraries/License
13 | ***********************************************************************/
14 |
15 | #include
16 | #include
17 |
18 | #ifndef VCZH_GCC
19 | static_assert(false, "Do not build this file for Windows applications.");
20 | #endif
21 |
22 | namespace vl
23 | {
24 | namespace console
25 | {
26 |
27 | /***********************************************************************
28 | Console
29 | ***********************************************************************/
30 |
31 | void Console::Write(const wchar_t* string, vint length)
32 | {
33 | std::wstring s(string, string + length);
34 | std::wcout << s << std::ends;
35 | }
36 |
37 | WString Console::Read()
38 | {
39 | std::wstring s;
40 | std::getline(std::wcin, s, L'\n');
41 | return s.c_str();
42 | }
43 |
44 | void Console::SetColor(bool red, bool green, bool blue, bool light)
45 | {
46 | int color = (blue ? 1 : 0) * 4 + (green ? 1 : 0) * 2 + (red ? 1 : 0);
47 | if (light)
48 | wprintf(L"\x1B[00;3%dm", color);
49 | else
50 | wprintf(L"\x1B[01;3%dm", color);
51 | }
52 |
53 | void Console::SetTitle(const WString& string)
54 | {
55 | }
56 | }
57 | }
58 |
59 |
60 | /***********************************************************************
61 | .\PRIMITIVES\DATETIME.LINUX.CPP
62 | ***********************************************************************/
63 | /***********************************************************************
64 | Author: Zihan Chen (vczh)
65 | Licensed under https://github.com/vczh-libraries/License
66 | ***********************************************************************/
67 |
68 | #include
69 | #include
70 | #include
71 |
72 | #ifndef VCZH_GCC
73 | static_assert(false, "Do not build this file for Windows applications.");
74 | #endif
75 |
76 | namespace vl
77 | {
78 |
79 | /***********************************************************************
80 | DateTime
81 | ***********************************************************************/
82 |
83 | class LinuxDateTimeImpl : public Object, public virtual IDateTimeImpl
84 | {
85 | public:
86 |
87 | static void TimeToOSInternal(time_t timer, vint milliseconds, vuint64_t& osInternal)
88 | {
89 | osInternal = (vuint64_t)timer * 1000 + milliseconds;
90 | }
91 |
92 | static void OSInternalToTime(vuint64_t osInternal, time_t& timer, vint& milliseconds)
93 | {
94 | timer = (time_t)(osInternal / 1000);
95 | milliseconds = (vint)(osInternal % 1000);
96 | }
97 |
98 | static vuint64_t ConvertTMTToOSInternal(tm* timeinfo, vint milliseconds)
99 | {
100 | time_t timer = mktime(timeinfo);
101 | vuint64_t osInternal;
102 | TimeToOSInternal(timer, milliseconds, osInternal);
103 | return osInternal;
104 | }
105 |
106 | static DateTime ConvertTMToDateTime(tm* timeinfo, vint milliseconds)
107 | {
108 | time_t timer = mktime(timeinfo);
109 | DateTime dt;
110 | dt.year = timeinfo->tm_year + 1900;
111 | dt.month = timeinfo->tm_mon + 1;
112 | dt.day = timeinfo->tm_mday;
113 | dt.dayOfWeek = timeinfo->tm_wday;
114 | dt.hour = timeinfo->tm_hour;
115 | dt.minute = timeinfo->tm_min;
116 | dt.second = timeinfo->tm_sec;
117 | dt.milliseconds = milliseconds;
118 |
119 | // in Linux and macOS, filetime will be mktime(t) * 1000 + gettimeofday().tv_usec / 1000
120 | TimeToOSInternal(timer, milliseconds, dt.osInternal);
121 | dt.osMilliseconds = dt.osInternal;
122 | return dt;
123 | }
124 |
125 | DateTime FromDateTime(vint _year, vint _month, vint _day, vint _hour, vint _minute, vint _second, vint _milliseconds) override
126 | {
127 | tm timeinfo;
128 | memset(&timeinfo, 0, sizeof(timeinfo));
129 | timeinfo.tm_year = _year - 1900;
130 | timeinfo.tm_mon = _month - 1;
131 | timeinfo.tm_mday = _day;
132 | timeinfo.tm_hour = _hour;
133 | timeinfo.tm_min = _minute;
134 | timeinfo.tm_sec = _second;
135 | timeinfo.tm_isdst = -1;
136 | return ConvertTMToDateTime(&timeinfo, _milliseconds);
137 | }
138 |
139 | DateTime FromOSInternal(vuint64_t osInternal) override
140 | {
141 | time_t timer;
142 | vint milliseconds;
143 | OSInternalToTime(osInternal, timer, milliseconds);
144 |
145 | tm* timeinfo = localtime(&timer);
146 | return ConvertTMToDateTime(timeinfo, milliseconds);
147 | }
148 |
149 | vuint64_t LocalTime() override
150 | {
151 | struct timeval tv;
152 | gettimeofday(&tv, nullptr);
153 | tm* timeinfo = localtime(&tv.tv_sec);
154 | return ConvertTMTToOSInternal(timeinfo, tv.tv_usec / 1000);
155 | }
156 |
157 | vuint64_t UtcTime() override
158 | {
159 | struct timeval tv;
160 | gettimeofday(&tv, nullptr);
161 | tm* timeinfo = gmtime(&tv.tv_sec);
162 | return ConvertTMTToOSInternal(timeinfo, tv.tv_usec / 1000);
163 | }
164 |
165 | vuint64_t LocalToUtcTime(vuint64_t osInternal) override
166 | {
167 | time_t timer;
168 | vint milliseconds;
169 | OSInternalToTime(osInternal, timer, milliseconds);
170 |
171 | tm* timeinfo = gmtime(&timer);
172 | return ConvertTMTToOSInternal(timeinfo, milliseconds);
173 | }
174 |
175 | vuint64_t UtcToLocalTime(vuint64_t osInternal) override
176 | {
177 | time_t timer;
178 | vint milliseconds;
179 | OSInternalToTime(osInternal, timer, milliseconds);
180 |
181 | time_t localTimer = mktime(localtime(&timer));
182 | time_t utcTimer = mktime(gmtime(&timer));
183 | timer += localTimer - utcTimer;
184 |
185 | TimeToOSInternal(timer, milliseconds, osInternal);
186 | return osInternal;
187 | }
188 |
189 | vuint64_t Forward(vuint64_t osInternal, vuint64_t milliseconds) override
190 | {
191 | return osInternal + milliseconds;
192 | }
193 |
194 | vuint64_t Backward(vuint64_t osInternal, vuint64_t milliseconds) override
195 | {
196 | return osInternal - milliseconds;
197 | }
198 | };
199 |
200 | LinuxDateTimeImpl osDateTimeImpl;
201 |
202 | IDateTimeImpl* GetOSDateTimeImpl()
203 | {
204 | return &osDateTimeImpl;
205 | }
206 | }
207 |
208 |
209 | /***********************************************************************
210 | .\STRINGS\CONVERSION.LINUX.CPP
211 | ***********************************************************************/
212 | /***********************************************************************
213 | Author: Zihan Chen (vczh)
214 | Licensed under https://github.com/vczh-libraries/License
215 | ***********************************************************************/
216 |
217 | #include
218 | #include
219 | #include
220 |
221 | namespace vl
222 | {
223 | /***********************************************************************
224 | String Conversions (buffer walkthrough)
225 | ***********************************************************************/
226 |
227 | vint _wtoa(const wchar_t* w, char* a, vint chars)
228 | {
229 | return wcstombs(a, w, chars - 1) + 1;
230 | }
231 |
232 | vint _atow(const char* a, wchar_t* w, vint chars)
233 | {
234 | return mbstowcs(w, a, chars - 1) + 1;
235 | }
236 | }
237 |
238 |
239 | /***********************************************************************
240 | .\UNITTEST\UNITTEST.LINUX.CPP
241 | ***********************************************************************/
242 | /***********************************************************************
243 | Author: Zihan Chen (vczh)
244 | Licensed under https://github.com/vczh-libraries/License
245 | ***********************************************************************/
246 |
247 |
248 | #ifndef VCZH_GCC
249 | static_assert(false, "Do not build this file for Windows applications.");
250 | #endif
251 |
252 | namespace vl
253 | {
254 | namespace unittest
255 | {
256 | /***********************************************************************
257 | UnitTest
258 | ***********************************************************************/
259 |
260 | bool UnitTest::IsDebuggerAttached()
261 | {
262 | return false;
263 | }
264 | }
265 | }
266 |
267 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | See https://github.com/vczh-libraries/License/blob/master/README.md for the detail.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VlppOS
2 |
3 | **Minimum Operator System Construction.**
4 |
5 | ## License
6 |
7 | This project is licensed under [the License repo](https://github.com/vczh-libraries/License).
8 |
9 | Source code in this repo is for reference only, please use the source code in [the Release repo](https://github.com/vczh-libraries/Release).
10 |
11 | You are welcome to contribute to this repo by opening pull requests.
12 |
13 | ## Document
14 |
15 | For **Gaclib**: click [here](http://vczh-libraries.github.io/doc/current/home.html)
16 |
17 | For **VlppOS**: click [here](http://vczh-libraries.github.io/doc/current/vlppos/home.html)
18 |
19 | ## Unit Test
20 |
21 | For **Windows**, open `Test/UnitTest/UnitTest.sln`, and run the `UnitTest` project.
22 |
23 | For **Linux**, use `Test/Linux/makefile` to build and run the unit test project.
24 |
--------------------------------------------------------------------------------
/Release/CodegenConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/Release/IncludeOnly/VlppOS.Linux.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
3 | DEVELOPER: Zihan Chen(vczh)
4 | ***********************************************************************/
5 | #include "VlppOS.h"
6 | #include "Vlpp.h"
7 |
8 | #include "..\..\Source\FileSystem.Linux.cpp"
9 | #include "..\..\Source\Locale.Linux.cpp"
10 | #include "..\..\Source\Threading.Linux.cpp"
11 | #include "..\..\Source\Encoding\CharFormat\CharFormat.Linux.cpp"
12 |
--------------------------------------------------------------------------------
/Release/IncludeOnly/VlppOS.Windows.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
3 | DEVELOPER: Zihan Chen(vczh)
4 | ***********************************************************************/
5 | #include "VlppOS.h"
6 | #include "Vlpp.h"
7 |
8 | #include "..\..\Source\FileSystem.Windows.cpp"
9 | #include "..\..\Source\HttpUtility.Windows.cpp"
10 | #include "..\..\Source\Locale.Windows.cpp"
11 | #include "..\..\Source\Threading.Windows.cpp"
12 | #include "..\..\Source\Encoding\CharFormat\CharFormat.Windows.cpp"
13 |
--------------------------------------------------------------------------------
/Release/IncludeOnly/VlppOS.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
3 | DEVELOPER: Zihan Chen(vczh)
4 | ***********************************************************************/
5 | #include "VlppOS.h"
6 |
7 | #include "..\..\Source\FileSystem.cpp"
8 | #include "..\..\Source\Locale.cpp"
9 | #include "..\..\Source\Threading.cpp"
10 | #include "..\..\Source\Encoding\Base64Encoding.cpp"
11 | #include "..\..\Source\Encoding\Encoding.cpp"
12 | #include "..\..\Source\Encoding\LzwEncoding.cpp"
13 | #include "..\..\Source\Encoding\CharFormat\BomEncoding.cpp"
14 | #include "..\..\Source\Encoding\CharFormat\CharFormat.cpp"
15 | #include "..\..\Source\Encoding\CharFormat\MbcsEncoding.cpp"
16 | #include "..\..\Source\Encoding\CharFormat\UtfEncoding.cpp"
17 | #include "..\..\Source\Stream\Accessor.cpp"
18 | #include "..\..\Source\Stream\BroadcastStream.cpp"
19 | #include "..\..\Source\Stream\CacheStream.cpp"
20 | #include "..\..\Source\Stream\EncodingStream.cpp"
21 | #include "..\..\Source\Stream\FileStream.cpp"
22 | #include "..\..\Source\Stream\MemoryStream.cpp"
23 | #include "..\..\Source\Stream\MemoryWrapperStream.cpp"
24 | #include "..\..\Source\Stream\RecorderStream.cpp"
25 |
--------------------------------------------------------------------------------
/Release/IncludeOnly/VlppOS.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
3 | DEVELOPER: Zihan Chen(vczh)
4 | ***********************************************************************/
5 | #include "Vlpp.h"
6 |
7 | #include "..\..\Source\HttpUtility.h"
8 | #include "..\..\Source\Locale.h"
9 | #include "..\..\Source\Threading.h"
10 | #include "..\..\Source\Stream\Interfaces.h"
11 | #include "..\..\Source\Encoding\Encoding.h"
12 | #include "..\..\Source\Encoding\Base64Encoding.h"
13 | #include "..\..\Source\Encoding\CharFormat\BomEncoding.h"
14 | #include "..\..\Source\Encoding\CharFormat\MbcsEncoding.h"
15 | #include "..\..\Source\Encoding\CharFormat\UtfEncoding.h"
16 | #include "..\..\Source\Encoding\CharFormat\CharFormat.h"
17 | #include "..\..\Source\Encoding\LzwEncoding.h"
18 | #include "..\..\Source\FileSystem.h"
19 | #include "..\..\Source\Stream\BroadcastStream.h"
20 | #include "..\..\Source\Stream\CacheStream.h"
21 | #include "..\..\Source\Stream\EncodingStream.h"
22 | #include "..\..\Source\Stream\FileStream.h"
23 | #include "..\..\Source\Stream\MemoryStream.h"
24 | #include "..\..\Source\Stream\Accessor.h"
25 | #include "..\..\Source\Stream\MemoryWrapperStream.h"
26 | #include "..\..\Source\Stream\RecorderStream.h"
27 | #include "..\..\Source\Stream\Serialization.h"
28 |
--------------------------------------------------------------------------------
/Source/Encoding/Base64Encoding.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "Base64Encoding.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | const char8_t Utf8Base64Codes[] = u8"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13 |
14 | /***********************************************************************
15 | Utf8Base64Encoder
16 | ***********************************************************************/
17 |
18 | void Utf8Base64Encoder::WriteBytesToCharArray(uint8_t* fromBytes, char8_t(&toChars)[Base64CycleChars], vint bytes)
19 | {
20 | switch (bytes)
21 | {
22 | case 1:
23 | {
24 | toChars[0] = Utf8Base64Codes[fromBytes[0] >> 2];
25 | toChars[1] = Utf8Base64Codes[(fromBytes[0] % (1 << 2)) << 4];
26 | toChars[2] = u8'=';
27 | toChars[3] = u8'=';
28 | }
29 | break;
30 | case 2:
31 | {
32 | toChars[0] = Utf8Base64Codes[fromBytes[0] >> 2];
33 | toChars[1] = Utf8Base64Codes[((fromBytes[0] % (1 << 2)) << 4) | (fromBytes[1] >> 4)];
34 | toChars[2] = Utf8Base64Codes[(fromBytes[1] % (1 << 4)) << 2];
35 | toChars[3] = u8'=';
36 | }
37 | break;
38 | case 3:
39 | {
40 | toChars[0] = Utf8Base64Codes[fromBytes[0] >> 2];
41 | toChars[1] = Utf8Base64Codes[((fromBytes[0] % (1 << 2)) << 4) | (fromBytes[1] >> 4)];
42 | toChars[2] = Utf8Base64Codes[((fromBytes[1] % (1 << 4)) << 2) | (fromBytes[2] >> 6)];
43 | toChars[3] = Utf8Base64Codes[fromBytes[2] % (1 << 6)];
44 | }
45 | break;
46 | default:
47 | CHECK_FAIL(L"vl::stream::Utf8Base64Encoder::WriteBytesToCharArray(uint8_t*, char8_t(&)[Base64CycleChars], vint)#Parameter bytes should be 1, 2 or 3.");
48 | }
49 | }
50 |
51 | bool Utf8Base64Encoder::WriteCycle(uint8_t*& reading, vint& _size)
52 | {
53 | if (_size <= 0) return false;
54 | vint bytes = _size < Base64CycleBytes ? _size : Base64CycleBytes;
55 |
56 | char8_t chars[Base64CycleChars];
57 | WriteBytesToCharArray(reading, chars, bytes);
58 | vint writtenBytes = stream->Write(chars, Base64CycleChars);
59 | CHECK_ERROR(writtenBytes == Base64CycleChars, L"vl::stream::Utf8Base64Encoder::WriteCycle(uint8_t*&, vint&)#The underlying stream failed to accept enough base64 characters.");
60 |
61 | reading += bytes;
62 | _size -= bytes;
63 | return true;
64 | }
65 |
66 | bool Utf8Base64Encoder::WriteCache(uint8_t*& reading, vint& _size)
67 | {
68 | if (cacheSize > 0 || _size < Base64CycleBytes)
69 | {
70 | vint copiedBytes = Base64CycleBytes - cacheSize;
71 | if (copiedBytes > _size) copiedBytes = _size;
72 | if (copiedBytes > 0)
73 | {
74 | memcpy(cache + cacheSize, reading, copiedBytes);
75 | reading += copiedBytes;
76 | _size -= copiedBytes;
77 | cacheSize += copiedBytes;
78 | }
79 | }
80 |
81 | if (cacheSize == 0) return _size > 0;
82 | if (cacheSize == Base64CycleBytes)
83 | {
84 | uint8_t* cacheReading = cache;
85 | return WriteCycle(cacheReading, cacheSize);
86 | }
87 | return true;
88 | }
89 |
90 | vint Utf8Base64Encoder::Write(void* _buffer, vint _size)
91 | {
92 | uint8_t* reading = (uint8_t*)_buffer;
93 |
94 | // flush cache if any
95 | if (!WriteCache(reading, _size)) goto FINISHED_WRITING;
96 |
97 | // run Base64 encoding
98 | while (_size >= Base64CycleBytes)
99 | {
100 | if (!WriteCycle(reading, _size)) goto FINISHED_WRITING;
101 | }
102 |
103 | // run the last Base64 encoding cycle and wrote a postfix to cache
104 | WriteCache(reading, _size);
105 |
106 | FINISHED_WRITING:
107 | return reading - (uint8_t*)_buffer;
108 | }
109 |
110 | void Utf8Base64Encoder::Close()
111 | {
112 | if (cacheSize > 0)
113 | {
114 | char8_t chars[Base64CycleChars];
115 | WriteBytesToCharArray(cache, chars, cacheSize);
116 | vint writtenBytes = stream->Write(chars, Base64CycleChars);
117 | CHECK_ERROR(writtenBytes == Base64CycleChars, L"vl::stream::Utf8Base64Encoder::Close()#The underlying stream failed to accept enough base64 characters.");
118 |
119 | cacheSize = 0;
120 | }
121 | EncoderBase::Close();
122 | }
123 |
124 | /***********************************************************************
125 | Utf8Base64Decoder
126 | ***********************************************************************/
127 |
128 | vint Utf8Base64Decoder::ReadBytesFromCharArray(char8_t(&fromChars)[Base64CycleChars], uint8_t* toBytes)
129 | {
130 | uint8_t nums[Base64CycleChars];
131 | for (vint i = 0; i < Base64CycleChars; i++)
132 | {
133 | char8_t c = fromChars[i];
134 | if (u8'A' <= c && c <= u8'Z') nums[i] = c - u8'A';
135 | else if (u8'a' <= c && c <= u8'z') nums[i] = c - u8'a' + 26;
136 | else if (u8'0' <= c && c <= u8'9') nums[i] = c - u8'0' + 52;
137 | else switch (c)
138 | {
139 | case '+':nums[i] = 62; break;
140 | case '/':nums[i] = 63; break;
141 | case '=':nums[i] = 0; break;
142 | default:
143 | CHECK_FAIL(L"vl::stream::Utf8Base64Decoder::ReadBytesFromCharArray(char(&)[Base64CycleChars], uint8_t*)#Illegal Base64 character.");
144 | }
145 | }
146 |
147 | toBytes[0] = (nums[0] << 2) | (nums[1] >> 4);
148 | if (fromChars[2] == u8'=') return 1;
149 | toBytes[1] = ((nums[1] % (1 << 4)) << 4) | (nums[2] >> 2);
150 | if (fromChars[3] == u8'=') return 2;
151 | toBytes[2] = ((nums[2] % (1 << 2)) << 6) | nums[3];
152 | return 3;
153 | }
154 |
155 | vint Utf8Base64Decoder::ReadCycle(uint8_t*& writing, vint& _size)
156 | {
157 | char8_t chars[Base64CycleChars];
158 | vint readChars = stream->Read((void*)chars, Base64CycleChars);
159 | if (readChars == 0) return 0;
160 | CHECK_ERROR(readChars == Base64CycleChars, L"vl::stream::Utf8Base64Decoder::ReadCycle(uint8_t*&, vint&)#The underlying stream failed to provide enough base64 characters.");
161 |
162 | vint readBytes = ReadBytesFromCharArray(chars, writing);
163 | writing += readBytes;
164 | _size -= readBytes;
165 | return readBytes;
166 | }
167 |
168 | void Utf8Base64Decoder::ReadCache(uint8_t*& writing, vint& _size)
169 | {
170 | if (cacheSize > 0)
171 | {
172 | vint copiedBytes = cacheSize;
173 | if (copiedBytes > _size) copiedBytes = _size;
174 | if (copiedBytes > 0)
175 | {
176 | memcpy(writing, cache, copiedBytes);
177 | writing += copiedBytes;
178 | _size -= copiedBytes;
179 | cacheSize -= copiedBytes;
180 | if (cacheSize > 0)
181 | {
182 | memmove(cache, cache + copiedBytes, cacheSize);
183 | }
184 | }
185 | }
186 | }
187 |
188 | vint Utf8Base64Decoder::Read(void* _buffer, vint _size)
189 | {
190 | uint8_t* writing = (uint8_t*)_buffer;
191 |
192 | // write cache to buffer if any
193 | ReadCache(writing, _size);
194 |
195 | // run Base64 decoding
196 | while (_size >= Base64CycleBytes)
197 | {
198 | if (ReadCycle(writing, _size) == 0) goto FINISHED_READING;
199 | }
200 |
201 | // run the last Base64 decoding cycle and write a prefix to buffer
202 | if (_size > 0)
203 | {
204 | uint8_t* cacheWriting = cache;
205 | vint temp = 0;
206 | if ((cacheSize = ReadCycle(cacheWriting, temp)) == 0) goto FINISHED_READING;
207 | ReadCache(writing, _size);
208 | }
209 | FINISHED_READING:
210 | return writing - (uint8_t*)_buffer;
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/Source/Encoding/Base64Encoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_BASE64ENCODING
7 | #define VCZH_STREAM_ENCODING_BASE64ENCODING
8 |
9 | #include "Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | constexpr const vint Base64CycleBytes = 3;
16 | constexpr const vint Base64CycleChars = 4;
17 |
18 | /***********************************************************************
19 | Utf8Base64Encoder
20 | ***********************************************************************/
21 |
22 | class Utf8Base64Encoder : public EncoderBase
23 | {
24 | protected:
25 | uint8_t cache[Base64CycleBytes];
26 | vint cacheSize = 0;
27 |
28 | void WriteBytesToCharArray(uint8_t* fromBytes, char8_t(&toChars)[Base64CycleChars], vint bytes);
29 | bool WriteCycle(uint8_t*& reading, vint& _size);
30 | bool WriteCache(uint8_t*& reading, vint& _size);
31 | public:
32 | vint Write(void* _buffer, vint _size) override;
33 | void Close() override;
34 | };
35 |
36 | /***********************************************************************
37 | Utf8Base64Decoder
38 | ***********************************************************************/
39 |
40 | class Utf8Base64Decoder : public DecoderBase
41 | {
42 | protected:
43 | uint8_t cache[Base64CycleBytes];
44 | vint cacheSize = 0;
45 |
46 | vint ReadBytesFromCharArray(char8_t(&fromChars)[Base64CycleChars], uint8_t* toBytes);
47 | vint ReadCycle(uint8_t*& writing, vint& _size);
48 | void ReadCache(uint8_t*& writing, vint& _size);
49 | public:
50 | vint Read(void* _buffer, vint _size) override;
51 | };
52 | }
53 | }
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/BomEncoding.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "BomEncoding.h"
7 | #include "CharFormat.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | BomEncoder
15 | ***********************************************************************/
16 |
17 | BomEncoder::BomEncoder(Encoding _encoding)
18 | :encoding(_encoding)
19 | ,encoder(0)
20 | {
21 | switch(encoding)
22 | {
23 | case Mbcs:
24 | encoder=new MbcsEncoder;
25 | break;
26 | case Utf8:
27 | encoder=new Utf8Encoder;
28 | break;
29 | case Utf16:
30 | encoder=new Utf16Encoder;
31 | break;
32 | case Utf16BE:
33 | encoder=new Utf16BEEncoder;
34 | break;
35 | }
36 | }
37 |
38 | BomEncoder::~BomEncoder()
39 | {
40 | Close();
41 | }
42 |
43 | void BomEncoder::Setup(IStream* _stream)
44 | {
45 | switch(encoding)
46 | {
47 | case Mbcs:
48 | break;
49 | case Utf8:
50 | _stream->Write((void*)"\xEF\xBB\xBF", 3);
51 | break;
52 | case Utf16:
53 | _stream->Write((void*)"\xFF\xFE", 2);
54 | break;
55 | case Utf16BE:
56 | _stream->Write((void*)"\xFE\xFF", 2);
57 | break;
58 | }
59 | encoder->Setup(_stream);
60 | }
61 |
62 | void BomEncoder::Close()
63 | {
64 | if(encoder)
65 | {
66 | encoder->Close();
67 | delete encoder;
68 | encoder=0;
69 | }
70 | }
71 |
72 | vint BomEncoder::Write(void* _buffer, vint _size)
73 | {
74 | return encoder->Write(_buffer, _size);
75 | }
76 |
77 | /***********************************************************************
78 | BomDecoder
79 | ***********************************************************************/
80 |
81 | BomDecoder::BomStream::BomStream(IStream* _stream, char* _bom, vint _bomLength)
82 | :stream(_stream)
83 | ,bomPosition(0)
84 | ,bomLength(_bomLength)
85 | {
86 | memcpy(bom, _bom, bomLength);
87 | }
88 |
89 | bool BomDecoder::BomStream::CanRead()const
90 | {
91 | return IsAvailable();
92 | }
93 |
94 | bool BomDecoder::BomStream::CanWrite()const
95 | {
96 | return false;
97 | }
98 |
99 | bool BomDecoder::BomStream::CanSeek()const
100 | {
101 | return false;
102 | }
103 |
104 | bool BomDecoder::BomStream::CanPeek()const
105 | {
106 | return false;
107 | }
108 |
109 | bool BomDecoder::BomStream::IsLimited()const
110 | {
111 | return stream!=0 && stream->IsLimited();
112 | }
113 |
114 | bool BomDecoder::BomStream::IsAvailable()const
115 | {
116 | return stream!=0 && stream->IsAvailable();
117 | }
118 |
119 | void BomDecoder::BomStream::Close()
120 | {
121 | stream=0;
122 | }
123 |
124 | pos_t BomDecoder::BomStream::Position()const
125 | {
126 | return IsAvailable()?bomPosition+stream->Position():-1;
127 | }
128 |
129 | pos_t BomDecoder::BomStream::Size()const
130 | {
131 | return -1;
132 | }
133 |
134 | void BomDecoder::BomStream::Seek(pos_t _size)
135 | {
136 | CHECK_FAIL(L"BomDecoder::BomStream::Seek(pos_t)#Operation not supported.");
137 | }
138 |
139 | void BomDecoder::BomStream::SeekFromBegin(pos_t _size)
140 | {
141 | CHECK_FAIL(L"BomDecoder::BomStream::SeekFromBegin(pos_t)#Operation not supported.");
142 | }
143 |
144 | void BomDecoder::BomStream::SeekFromEnd(pos_t _size)
145 | {
146 | CHECK_FAIL(L"BomDecoder::BomStream::SeekFromEnd(pos_t)#Operation not supported.");
147 | }
148 |
149 | vint BomDecoder::BomStream::Read(void* _buffer, vint _size)
150 | {
151 | vint result=0;
152 | unsigned char* buffer=(unsigned char*)_buffer;
153 | if(bomPositionRead(buffer, _size);
165 | }
166 | return result;
167 | }
168 |
169 | vint BomDecoder::BomStream::Write(void* _buffer, vint _size)
170 | {
171 | CHECK_FAIL(L"BomDecoder::BomStream::Write(void*, vint)#Operation not supported.");
172 | }
173 |
174 | vint BomDecoder::BomStream::Peek(void* _buffer, vint _size)
175 | {
176 | CHECK_FAIL(L"BomDecoder::BomStream::Peek(void*, vint)#Operation not supported.");
177 | }
178 |
179 | BomDecoder::BomDecoder()
180 | :decoder(0)
181 | {
182 | }
183 |
184 | BomDecoder::~BomDecoder()
185 | {
186 | Close();
187 | }
188 |
189 | void BomDecoder::Setup(IStream* _stream)
190 | {
191 | char bom[3]={0};
192 | vint length=_stream->Read(bom, sizeof(bom));
193 | if(strncmp(bom, "\xEF\xBB\xBF", 3)==0)
194 | {
195 | decoder=new Utf8Decoder;
196 | stream=new BomStream(_stream, bom+3, 0);
197 | }
198 | else if(strncmp(bom, "\xFF\xFE", 2)==0)
199 | {
200 | decoder=new Utf16Decoder;
201 | stream=new BomStream(_stream, bom+2, 1);
202 | }
203 | else if(strncmp(bom, "\xFE\xFF", 2)==0)
204 | {
205 | decoder=new Utf16BEDecoder;
206 | stream=new BomStream(_stream, bom+2, 1);
207 | }
208 | else
209 | {
210 | decoder=new MbcsDecoder;
211 | stream=new BomStream(_stream, bom, 3);
212 | }
213 | decoder->Setup(stream);
214 | }
215 |
216 | void BomDecoder::Close()
217 | {
218 | if(decoder)
219 | {
220 | decoder->Close();
221 | delete decoder;
222 | decoder=0;
223 | stream->Close();
224 | delete stream;
225 | stream=0;
226 | }
227 | }
228 |
229 | vint BomDecoder::Read(void* _buffer, vint _size)
230 | {
231 | return decoder->Read(_buffer, _size);
232 | }
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/BomEncoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_CHARFORMAT_BOMENCODING
7 | #define VCZH_STREAM_ENCODING_CHARFORMAT_BOMENCODING
8 |
9 | #include "../Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /***********************************************************************
16 | Bom
17 | ***********************************************************************/
18 |
19 | /// Encoder to write text in a specified encoding. A BOM will be added at the beginning.
20 | class BomEncoder : public Object, public IEncoder
21 | {
22 | public:
23 | /// Text encoding.
24 | enum Encoding
25 | {
26 | /// Multi-bytes character string.
27 | Mbcs,
28 | /// UTF-8. EF, BB, BF will be written before writing any text.
29 | Utf8,
30 | /// UTF-16. FF FE will be written before writing any text.
31 | Utf16,
32 | /// Big endian UTF-16. FE FF, BF will be written before writing any text.
33 | Utf16BE
34 | };
35 | protected:
36 | Encoding encoding;
37 | IEncoder* encoder;
38 | public:
39 | /// Create an encoder with a specified encoding.
40 | /// The specified encoding.
41 | BomEncoder(Encoding _encoding);
42 | ~BomEncoder();
43 |
44 | void Setup(IStream* _stream);
45 | void Close();
46 | vint Write(void* _buffer, vint _size);
47 | };
48 |
49 | /// Decoder to read text. This decoder depends on BOM at the beginning to decide the format of the input.
50 | class BomDecoder : public Object, public IDecoder
51 | {
52 | private:
53 | class BomStream : public Object, public IStream
54 | {
55 | protected:
56 | IStream* stream;
57 | char bom[3];
58 | vint bomLength;
59 | vint bomPosition;
60 | public:
61 | BomStream(IStream* _stream, char* _bom, vint _bomLength);
62 |
63 | bool CanRead()const;
64 | bool CanWrite()const;
65 | bool CanSeek()const;
66 | bool CanPeek()const;
67 | bool IsLimited()const;
68 | bool IsAvailable()const;
69 | void Close();
70 | pos_t Position()const;
71 | pos_t Size()const;
72 | void Seek(pos_t _size);
73 | void SeekFromBegin(pos_t _size);
74 | void SeekFromEnd(pos_t _size);
75 | vint Read(void* _buffer, vint _size);
76 | vint Write(void* _buffer, vint _size);
77 | vint Peek(void* _buffer, vint _size);
78 | };
79 | protected:
80 | IDecoder* decoder;
81 | IStream* stream;
82 |
83 | public:
84 | /// Create an decoder, BOM will be consumed before reading any text.
85 | BomDecoder();
86 | ~BomDecoder();
87 |
88 | void Setup(IStream* _stream);
89 | void Close();
90 | vint Read(void* _buffer, vint _size);
91 | };
92 | }
93 | }
94 |
95 | #endif
96 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/CharFormat.Linux.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "CharFormat.h"
7 | #include
8 |
9 | #ifndef VCZH_GCC
10 | static_assert(false, "Do not build this file for Windows applications.");
11 | #endif
12 |
13 | namespace vl
14 | {
15 | namespace stream
16 | {
17 | using namespace vl::encoding;
18 |
19 | bool IsMbcsLeadByte(char c)
20 | {
21 | return (vint8_t)c < 0;
22 | }
23 |
24 | void MbcsToWChar(wchar_t* wideBuffer, vint wideChars, vint wideReaded, char* mbcsBuffer, vint mbcsChars)
25 | {
26 | AString a = AString::CopyFrom(mbcsBuffer, mbcsChars);
27 | WString w = atow(a);
28 | memcpy(wideBuffer, w.Buffer(), wideReaded * sizeof(wchar_t));
29 | }
30 |
31 | /***********************************************************************
32 | MbcsEncoder
33 | ***********************************************************************/
34 |
35 | vint MbcsEncoder::WriteString(wchar_t* _buffer, vint chars)
36 | {
37 | WString w = WString::CopyFrom(_buffer, chars);
38 | AString a = wtoa(w);
39 | vint length = a.Length();
40 | vint result = stream->Write((void*)a.Buffer(), length);
41 |
42 | if (result != length)
43 | {
44 | Close();
45 | return 0;
46 | }
47 | return chars;
48 | }
49 |
50 | /***********************************************************************
51 | Helper Functions
52 | ***********************************************************************/
53 |
54 | extern bool CanBeMbcs(unsigned char* buffer, vint size);
55 | extern bool CanBeUtf8(unsigned char* buffer, vint size);
56 | extern bool CanBeUtf16(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
57 | extern bool CanBeUtf16BE(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
58 |
59 | /***********************************************************************
60 | TestEncoding
61 | ***********************************************************************/
62 |
63 | extern void TestEncodingInternal(
64 | unsigned char* buffer,
65 | vint size,
66 | BomEncoder::Encoding& encoding,
67 | bool containsBom,
68 | bool utf16HitSurrogatePairs,
69 | bool utf16BEHitSurrogatePairs,
70 | bool roughMbcs,
71 | bool roughUtf8,
72 | bool roughUtf16,
73 | bool roughUtf16BE
74 | )
75 | {
76 | if (roughUtf16 && roughUtf16BE && !roughUtf8)
77 | {
78 | if (utf16BEHitSurrogatePairs && !utf16HitSurrogatePairs)
79 | {
80 | encoding = BomEncoder::Utf16BE;
81 | }
82 | else
83 | {
84 | encoding = BomEncoder::Utf16;
85 | }
86 | }
87 | else
88 | {
89 | encoding = BomEncoder::Utf8;
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/CharFormat.Windows.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "CharFormat.h"
7 | #include
8 |
9 | #ifndef VCZH_MSVC
10 | static_assert(false, "Do not build this file for non-Windows applications.");
11 | #endif
12 |
13 | namespace vl
14 | {
15 | namespace stream
16 | {
17 | bool IsMbcsLeadByte(char c)
18 | {
19 | return IsDBCSLeadByte(c);
20 | }
21 |
22 | void MbcsToWChar(wchar_t* wideBuffer, vint wideChars, vint wideReaded, char* mbcsBuffer, vint mbcsChars)
23 | {
24 | MultiByteToWideChar(CP_THREAD_ACP, 0, mbcsBuffer, (int)mbcsChars, wideBuffer, (int)wideChars);
25 | }
26 |
27 | /***********************************************************************
28 | MbcsEncoder
29 | ***********************************************************************/
30 |
31 | vint MbcsEncoder::WriteString(wchar_t* _buffer, vint chars)
32 | {
33 | vint length = WideCharToMultiByte(CP_THREAD_ACP, 0, _buffer, (int)chars, NULL, NULL, NULL, NULL);
34 | char* mbcs = new char[length];
35 | WideCharToMultiByte(CP_THREAD_ACP, 0, _buffer, (int)chars, mbcs, (int)length, NULL, NULL);
36 | vint result = stream->Write(mbcs, length);
37 | delete[] mbcs;
38 |
39 | if (result != length)
40 | {
41 | Close();
42 | return 0;
43 | }
44 | return chars;
45 | }
46 |
47 | /***********************************************************************
48 | Helper Functions
49 | ***********************************************************************/
50 |
51 | extern bool CanBeMbcs(unsigned char* buffer, vint size);
52 | extern bool CanBeUtf8(unsigned char* buffer, vint size);
53 | extern bool CanBeUtf16(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
54 | extern bool CanBeUtf16BE(unsigned char* buffer, vint size, bool& hitSurrogatePairs);
55 |
56 | template
57 | bool GetEncodingResult(int(&tests)[Count], bool(&results)[Count], int test)
58 | {
59 | for (vint i = 0; i < Count; i++)
60 | {
61 | if (tests[i] & test)
62 | {
63 | if (results[i]) return true;
64 | }
65 | }
66 | return false;
67 | }
68 |
69 | /***********************************************************************
70 | TestEncoding
71 | ***********************************************************************/
72 |
73 | extern void TestEncodingInternal(
74 | unsigned char* buffer,
75 | vint size,
76 | BomEncoder::Encoding& encoding,
77 | bool containsBom,
78 | bool utf16HitSurrogatePairs,
79 | bool utf16BEHitSurrogatePairs,
80 | bool roughMbcs,
81 | bool roughUtf8,
82 | bool roughUtf16,
83 | bool roughUtf16BE
84 | )
85 | {
86 | int tests[] =
87 | {
88 | IS_TEXT_UNICODE_REVERSE_ASCII16,
89 | IS_TEXT_UNICODE_REVERSE_STATISTICS,
90 | IS_TEXT_UNICODE_REVERSE_CONTROLS,
91 |
92 | IS_TEXT_UNICODE_ASCII16,
93 | IS_TEXT_UNICODE_STATISTICS,
94 | IS_TEXT_UNICODE_CONTROLS,
95 |
96 | IS_TEXT_UNICODE_ILLEGAL_CHARS,
97 | IS_TEXT_UNICODE_ODD_LENGTH,
98 | IS_TEXT_UNICODE_NULL_BYTES,
99 | };
100 |
101 | const vint TestCount = sizeof(tests) / sizeof(*tests);
102 | bool results[TestCount];
103 | for (vint i = 0; i < TestCount; i++)
104 | {
105 | int test = tests[i];
106 | results[i] = IsTextUnicode(buffer, (int)size, &test) != 0;
107 | }
108 |
109 | if (size % 2 == 0
110 | && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16)
111 | && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_STATISTICS)
112 | && !GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS)
113 | )
114 | {
115 | for (vint i = 0; i < size; i += 2)
116 | {
117 | unsigned char c = buffer[i];
118 | buffer[i] = buffer[i + 1];
119 | buffer[i + 1] = c;
120 | }
121 | // 3 = (count of reverse group) = (count of unicode group)
122 | for (vint i = 0; i < 3; i++)
123 | {
124 | int test = tests[i + 3];
125 | results[i] = IsTextUnicode(buffer, (int)size, &test) != 0;
126 | }
127 | for (vint i = 0; i < size; i += 2)
128 | {
129 | unsigned char c = buffer[i];
130 | buffer[i] = buffer[i + 1];
131 | buffer[i + 1] = c;
132 | }
133 | }
134 |
135 | if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK))
136 | {
137 | if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_ASCII_MASK))
138 | {
139 | encoding = BomEncoder::Utf8;
140 | }
141 | else if (roughUtf8 || !roughMbcs)
142 | {
143 | encoding = BomEncoder::Utf8;
144 | }
145 | }
146 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_ASCII16))
147 | {
148 | encoding = BomEncoder::Utf16;
149 | }
150 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_ASCII16))
151 | {
152 | encoding = BomEncoder::Utf16BE;
153 | }
154 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_CONTROLS))
155 | {
156 | encoding = BomEncoder::Utf16;
157 | }
158 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_REVERSE_CONTROLS))
159 | {
160 | encoding = BomEncoder::Utf16BE;
161 | }
162 | else
163 | {
164 | if (!roughUtf8)
165 | {
166 | if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS))
167 | {
168 | encoding = BomEncoder::Utf16;
169 | }
170 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_STATISTICS))
171 | {
172 | encoding = BomEncoder::Utf16BE;
173 | }
174 | }
175 | else if (GetEncodingResult(tests, results, IS_TEXT_UNICODE_NOT_UNICODE_MASK))
176 | {
177 | encoding = BomEncoder::Utf8;
178 | }
179 | else if (roughUtf8 || !roughMbcs)
180 | {
181 | encoding = BomEncoder::Utf8;
182 | }
183 | }
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/CharFormat.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "CharFormat.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | /***********************************************************************
13 | Helper Functions
14 | ***********************************************************************/
15 |
16 | bool CanBeMbcs(unsigned char* buffer, vint size)
17 | {
18 | for(vint i=0;i= 3 && strncmp((char*)buffer, "\xEF\xBB\xBF", 3) == 0)
160 | {
161 | encoding = BomEncoder::Utf8;
162 | containsBom = true;
163 | }
164 | else if (size >= 2 && strncmp((char*)buffer, "\xFF\xFE", 2) == 0)
165 | {
166 | encoding = BomEncoder::Utf16;
167 | containsBom = true;
168 | }
169 | else if (size >= 2 && strncmp((char*)buffer, "\xFE\xFF", 2) == 0)
170 | {
171 | encoding = BomEncoder::Utf16BE;
172 | containsBom = true;
173 | }
174 | else
175 | {
176 | encoding = BomEncoder::Mbcs;
177 | containsBom = false;
178 |
179 | bool utf16HitSurrogatePairs = false;
180 | bool utf16BEHitSurrogatePairs = false;
181 | bool roughMbcs = CanBeMbcs(buffer, size);
182 | bool roughUtf8 = CanBeUtf8(buffer, size);
183 | bool roughUtf16 = CanBeUtf16(buffer, size, utf16HitSurrogatePairs);
184 | bool roughUtf16BE = CanBeUtf16BE(buffer, size, utf16BEHitSurrogatePairs);
185 |
186 | vint roughCount = (roughMbcs ? 1 : 0) + (roughUtf8 ? 1 : 0) + (roughUtf16 ? 1 : 0) + (roughUtf16BE ? 1 : 0);
187 | if (roughCount == 1)
188 | {
189 | if (roughUtf8) encoding = BomEncoder::Utf8;
190 | else if (roughUtf16) encoding = BomEncoder::Utf16;
191 | else if (roughUtf16BE) encoding = BomEncoder::Utf16BE;
192 | }
193 | else if (roughCount > 1)
194 | {
195 | TestEncodingInternal(buffer, size, encoding, containsBom, utf16HitSurrogatePairs, utf16BEHitSurrogatePairs, roughMbcs, roughUtf8, roughUtf16, roughUtf16BE);
196 | }
197 | }
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/CharFormat.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_CHARFORMAT
7 | #define VCZH_STREAM_ENCODING_CHARFORMAT
8 |
9 | #include "MbcsEncoding.h"
10 | #include "UtfEncoding.h"
11 | #include "BomEncoding.h"
12 |
13 | namespace vl
14 | {
15 | namespace stream
16 | {
17 | /***********************************************************************
18 | Utf-8
19 | ***********************************************************************/
20 |
21 | /// Encoder to write UTF-8 text.
22 | class Utf8Encoder : public UtfGeneralEncoder {};
23 | /// Decoder to read UTF-8 text.
24 | class Utf8Decoder : public UtfGeneralDecoder {};
25 |
26 | /***********************************************************************
27 | Utf-16
28 | ***********************************************************************/
29 |
30 | /// Encoder to write UTF-16 text.
31 | class Utf16Encoder : public UtfGeneralEncoder {};
32 | /// Decoder to read UTF-16 text.
33 | class Utf16Decoder : public UtfGeneralDecoder {};
34 |
35 | /***********************************************************************
36 | Utf-16BE
37 | ***********************************************************************/
38 |
39 | /// Encoder to write big endian UTF-16 to.
40 | class Utf16BEEncoder : public UtfGeneralEncoder {};
41 | /// Decoder to read big endian UTF-16 text.
42 | class Utf16BEDecoder : public UtfGeneralDecoder {};
43 |
44 | /***********************************************************************
45 | Utf-32
46 | ***********************************************************************/
47 |
48 | /// Encoder to write UTF-8 text.
49 | class Utf32Encoder : public UtfGeneralEncoder {};
50 | /// Decoder to read UTF-8 text.
51 | class Utf32Decoder : public UtfGeneralDecoder {};
52 |
53 | /***********************************************************************
54 | Encoding Test
55 | ***********************************************************************/
56 |
57 | /// Guess the text encoding in a buffer.
58 | /// The buffer to guess.
59 | /// Size of the buffer in bytes.
60 | /// Returns the most possible encoding.
61 | /// Returns true if the BOM information is at the beginning of the buffer.
62 | extern void TestEncoding(unsigned char* buffer, vint size, BomEncoder::Encoding& encoding, bool& containsBom);
63 | }
64 | }
65 |
66 | #endif
67 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/MbcsEncoding.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "CharFormat.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | /***********************************************************************
13 | MbcsDecoder::ReadString
14 | ***********************************************************************/
15 |
16 | extern bool IsMbcsLeadByte(char c);
17 | extern void MbcsToWChar(wchar_t* wideBuffer, vint wideChars, vint wideReaded, char* mbcsBuffer, vint mbcsChars);
18 |
19 | vint MbcsDecoder::ReadString(wchar_t* _buffer, vint chars)
20 | {
21 | char* source = new char[chars * 2];
22 | char* reading = source;
23 | vint readed = 0;
24 | while (readed < chars)
25 | {
26 | if (stream->Read(reading, 1) != 1)
27 | {
28 | break;
29 | }
30 | if (IsMbcsLeadByte(*reading))
31 | {
32 | if (stream->Read(reading + 1, 1) != 1)
33 | {
34 | break;
35 | }
36 | reading += 2;
37 | }
38 | else
39 | {
40 | reading++;
41 | }
42 | readed++;
43 | }
44 |
45 | MbcsToWChar(_buffer, chars, readed, source, (vint)(reading - source));
46 | delete[] source;
47 | return readed;
48 | }
49 |
50 | /***********************************************************************
51 | MbcsEncoder
52 | ***********************************************************************/
53 |
54 | vint MbcsEncoder::Write(void* _buffer, vint _size)
55 | {
56 | // prepare a buffer for input
57 | vint availableChars = (cacheSize + _size) / sizeof(wchar_t);
58 | vint availableBytes = availableChars * sizeof(wchar_t);
59 | bool needToFree = false;
60 | vuint8_t* unicode = nullptr;
61 | if (cacheSize > 0)
62 | {
63 | unicode = new vuint8_t[cacheSize + _size];
64 | memcpy(unicode, cacheBuffer, cacheSize);
65 | memcpy((vuint8_t*)unicode + cacheSize, _buffer, _size);
66 | needToFree = true;
67 | }
68 | else
69 | {
70 | unicode = (vuint8_t*)_buffer;
71 | }
72 |
73 | #if defined VCZH_WCHAR_UTF16
74 | if (availableChars > 0)
75 | {
76 | // a surrogate pair must be written as a whole thing
77 | vuint16_t c = (vuint16_t)((wchar_t*)unicode)[availableChars - 1];
78 | if ((c & 0xFC00U) == 0xD800U)
79 | {
80 | availableChars -= 1;
81 | availableBytes -= sizeof(wchar_t);
82 | }
83 | }
84 | #endif
85 |
86 | // write the buffer
87 | if (availableChars > 0)
88 | {
89 | vint written = WriteString((wchar_t*)unicode, availableChars) * sizeof(wchar_t);
90 | CHECK_ERROR(written == availableBytes, L"MbcsEncoder::Write(void*, vint)#Failed to write a complete string.");
91 | }
92 |
93 | // cache the remaining
94 | cacheSize = cacheSize + _size - availableBytes;
95 | if (cacheSize > 0)
96 | {
97 | CHECK_ERROR(cacheSize <= sizeof(char32_t), L"MbcsEncoder::Write(void*, vint)#Unwritten text is too large to cache.");
98 | memcpy(cacheBuffer, unicode + availableBytes, cacheSize);
99 | }
100 |
101 | if (needToFree) delete[] unicode;
102 | return _size;
103 | }
104 |
105 | /***********************************************************************
106 | MbcsDecoder::WriteString
107 | ***********************************************************************/
108 |
109 | // implemented in platform dependent files
110 |
111 | /***********************************************************************
112 | MbcsDecoder
113 | ***********************************************************************/
114 |
115 | vint MbcsDecoder::Read(void* _buffer, vint _size)
116 | {
117 | vuint8_t* writing = (vuint8_t*)_buffer;
118 | vint filledBytes = 0;
119 |
120 | // feed the cache first
121 | if (cacheSize > 0)
122 | {
123 | filledBytes = cacheSize < _size ? cacheSize : _size;
124 | memcpy(writing, cacheBuffer, cacheSize);
125 | _size -= filledBytes;
126 | writing += filledBytes;
127 |
128 | // adjust the cache if it is not fully consumed
129 | cacheSize -= filledBytes;
130 | if (cacheSize > 0)
131 | {
132 | memcpy(cacheBuffer, cacheBuffer + filledBytes, cacheSize);
133 | }
134 |
135 | if (_size == 0)
136 | {
137 | return filledBytes;
138 | }
139 | }
140 |
141 | // fill the buffer as many as possible
142 | while (_size >= sizeof(wchar_t))
143 | {
144 | vint availableChars = _size / sizeof(wchar_t);
145 | vint readBytes = ReadString((wchar_t*)writing, availableChars) * sizeof(wchar_t);
146 | if (readBytes == 0) break;
147 | filledBytes += readBytes;
148 | _size -= readBytes;
149 | writing += readBytes;
150 | }
151 |
152 | // cache the remaining wchar_t
153 | if (_size < sizeof(wchar_t))
154 | {
155 | wchar_t c;
156 | vint readChars = ReadString(&c, 1) * sizeof(wchar_t);
157 | if (readChars == sizeof(wchar_t))
158 | {
159 | vuint8_t* reading = (vuint8_t*)&c;
160 | memcpy(writing, reading, _size);
161 | filledBytes += _size;
162 | cacheSize = sizeof(wchar_t) - _size;
163 | memcpy(cacheBuffer, reading + _size, cacheSize);
164 | }
165 | }
166 |
167 | return filledBytes;
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/MbcsEncoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_CHARFORMAT_MBCSENCODING
7 | #define VCZH_STREAM_ENCODING_CHARFORMAT_MBCSENCODING
8 |
9 | #include "../Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /***********************************************************************
16 | MbcsEncoder
17 | ***********************************************************************/
18 |
19 | /// Encoder to write text in the local code page.
20 | class MbcsEncoder : public EncoderBase
21 | {
22 | protected:
23 | vuint8_t cacheBuffer[sizeof(char32_t)];
24 | vint cacheSize = 0;
25 |
26 | vint WriteString(wchar_t* _buffer, vint chars);
27 | public:
28 |
29 | vint Write(void* _buffer, vint _size) override;
30 | };
31 |
32 | /***********************************************************************
33 | MbcsDecoder
34 | ***********************************************************************/
35 |
36 | /// Decoder to read text in the local code page.
37 | class MbcsDecoder : public DecoderBase
38 | {
39 | protected:
40 | vuint8_t cacheBuffer[sizeof(wchar_t)];
41 | vint cacheSize = 0;
42 |
43 | vint ReadString(wchar_t* _buffer, vint chars);
44 | public:
45 |
46 | vint Read(void* _buffer, vint _size) override;
47 | };
48 | }
49 | }
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/UtfEncoding.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "UtfEncoding.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | /***********************************************************************
13 | UtfGeneralEncoder
14 | ***********************************************************************/
15 |
16 | template
17 | vint UtfGeneralEncoder::Write(void* _buffer, vint _size)
18 | {
19 | // prepare a buffer for input
20 | vint availableChars = (cacheSize + _size) / sizeof(TExpect);
21 | vint availableBytes = availableChars * sizeof(TExpect);
22 | bool needToFree = false;
23 | vuint8_t* unicode = nullptr;
24 | if (cacheSize > 0)
25 | {
26 | unicode = new vuint8_t[cacheSize + _size];
27 | memcpy(unicode, cacheBuffer, cacheSize);
28 | memcpy((vuint8_t*)unicode + cacheSize, _buffer, _size);
29 | needToFree = true;
30 | }
31 | else
32 | {
33 | unicode = (vuint8_t*)_buffer;
34 | }
35 |
36 | // write the buffer
37 | if (availableChars > 0)
38 | {
39 | TStringRangeReader reader((TExpect*)unicode, availableChars);
40 | while (TNative c = reader.Read())
41 | {
42 | vint written = stream->Write(&c, sizeof(c));
43 | if (written != sizeof(c))
44 | {
45 | Close();
46 | CHECK_FAIL(L"UtfGeneralEncoder::Write(void*, vint)#Failed to write a complete string.");
47 | }
48 | }
49 | auto cluster = reader.SourceCluster();
50 | availableChars = cluster.index + cluster.size;
51 | availableBytes = availableChars * sizeof(TExpect);
52 | }
53 |
54 | // cache the remaining
55 | cacheSize = cacheSize + _size - availableBytes;
56 | if (cacheSize > 0)
57 | {
58 | CHECK_ERROR(cacheSize <= sizeof(cacheBuffer), L"UtfGeneralEncoder::Write(void*, vint)#Unwritten text is too large to cache.");
59 | memcpy(cacheBuffer, unicode + availableBytes, cacheSize);
60 | }
61 |
62 | if (needToFree) delete[] unicode;
63 | return _size;
64 | }
65 |
66 | /***********************************************************************
67 | UtfGeneralDecoder
68 | ***********************************************************************/
69 |
70 | template
71 | void UtfGeneralDecoder::Setup(IStream* _stream)
72 | {
73 | DecoderBase::Setup(_stream);
74 | reader.Setup(_stream);
75 | }
76 |
77 | template
78 | vint UtfGeneralDecoder::Read(void* _buffer, vint _size)
79 | {
80 | vuint8_t* writing = (vuint8_t*)_buffer;
81 | vint filledBytes = 0;
82 |
83 | // feed the cache first
84 | if (cacheSize > 0)
85 | {
86 | filledBytes = cacheSize < _size ? cacheSize : _size;
87 | memcpy(writing, cacheBuffer, cacheSize);
88 | _size -= filledBytes;
89 | writing += filledBytes;
90 |
91 | // adjust the cache if it is not fully consumed
92 | cacheSize -= filledBytes;
93 | if (cacheSize > 0)
94 | {
95 | memcpy(cacheBuffer, cacheBuffer + filledBytes, cacheSize);
96 | }
97 |
98 | if (_size == 0)
99 | {
100 | return filledBytes;
101 | }
102 | }
103 |
104 | // fill the buffer as many as possible
105 | while (_size >= sizeof(TExpect))
106 | {
107 | vint availableChars = _size / sizeof(TExpect);
108 | vint readBytes = 0;
109 | for (vint i = 0; i < availableChars; i++)
110 | {
111 | TExpect c = reader.Read();
112 | if (!c) break;
113 | *((TExpect*)writing) = c;
114 | writing += sizeof(TExpect);
115 | readBytes += sizeof(TExpect);
116 | }
117 | if (readBytes == 0) break;
118 | filledBytes += readBytes;
119 | _size -= readBytes;
120 | }
121 |
122 | // cache the remaining TExpect
123 | if (_size < sizeof(TExpect))
124 | {
125 | if (TExpect c = reader.Read())
126 | {
127 | vuint8_t* reading = (vuint8_t*)&c;
128 | memcpy(writing, reading, _size);
129 | filledBytes += _size;
130 | cacheSize = sizeof(TExpect) - _size;
131 | memcpy(cacheBuffer, reading + _size, cacheSize);
132 | }
133 | }
134 |
135 | return filledBytes;
136 | }
137 |
138 | /***********************************************************************
139 | UtfGeneralEncoder
140 | ***********************************************************************/
141 |
142 | template
143 | vint UtfGeneralEncoder::Write(void* _buffer, vint _size)
144 | {
145 | return stream->Write(_buffer, _size);
146 | }
147 |
148 | /***********************************************************************
149 | UtfGeneralDecoder
150 | ***********************************************************************/
151 |
152 | template
153 | vint UtfGeneralDecoder::Read(void* _buffer, vint _size)
154 | {
155 | return stream->Read(_buffer, _size);
156 | }
157 |
158 | /***********************************************************************
159 | Unicode General (extern templates)
160 | ***********************************************************************/
161 |
162 | template class UtfGeneralEncoder;
163 | template class UtfGeneralEncoder;
164 | template class UtfGeneralEncoder;
165 | template class UtfGeneralEncoder;
166 | template class UtfGeneralEncoder;
167 |
168 | template class UtfGeneralEncoder;
169 | template class UtfGeneralEncoder;
170 | template class UtfGeneralEncoder;
171 | template class UtfGeneralEncoder;
172 | template class UtfGeneralEncoder;
173 |
174 | template class UtfGeneralEncoder;
175 | template class UtfGeneralEncoder;
176 | template class UtfGeneralEncoder;
177 | template class UtfGeneralEncoder;
178 | template class UtfGeneralEncoder;
179 |
180 | template class UtfGeneralEncoder;
181 | template class UtfGeneralEncoder;
182 | template class UtfGeneralEncoder;
183 | template class UtfGeneralEncoder;
184 | template class UtfGeneralEncoder;
185 |
186 | template class UtfGeneralEncoder;
187 | template class UtfGeneralEncoder;
188 | template class UtfGeneralEncoder;
189 | template class UtfGeneralEncoder;
190 | template class UtfGeneralEncoder;
191 |
192 | template class UtfGeneralDecoder;
193 | template class UtfGeneralDecoder;
194 | template class UtfGeneralDecoder;
195 | template class UtfGeneralDecoder;
196 | template class UtfGeneralDecoder;
197 |
198 | template class UtfGeneralDecoder;
199 | template class UtfGeneralDecoder;
200 | template class UtfGeneralDecoder;
201 | template class UtfGeneralDecoder;
202 | template class UtfGeneralDecoder;
203 |
204 | template class UtfGeneralDecoder;
205 | template class UtfGeneralDecoder;
206 | template class UtfGeneralDecoder;
207 | template class UtfGeneralDecoder;
208 | template class UtfGeneralDecoder;
209 |
210 | template class UtfGeneralDecoder;
211 | template class UtfGeneralDecoder;
212 | template class UtfGeneralDecoder;
213 | template class UtfGeneralDecoder;
214 | template class UtfGeneralDecoder;
215 |
216 | template class UtfGeneralDecoder;
217 | template class UtfGeneralDecoder;
218 | template class UtfGeneralDecoder;
219 | template class UtfGeneralDecoder;
220 | template class UtfGeneralDecoder;
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/Source/Encoding/CharFormat/UtfEncoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_CHARFORMAT_UTFENCODING
7 | #define VCZH_STREAM_ENCODING_CHARFORMAT_UTFENCODING
8 |
9 | #include "../Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 |
16 | /***********************************************************************
17 | UtfStreamConsumer
18 | ***********************************************************************/
19 |
20 | template
21 | class UtfStreamConsumer : public Object
22 | {
23 | protected:
24 | IStream* stream = nullptr;
25 |
26 | T Consume()
27 | {
28 | T c;
29 | vint size = stream->Read(&c, sizeof(c));
30 | if (size != sizeof(c)) return 0;
31 | return c;
32 | }
33 | public:
34 | void Setup(IStream* _stream)
35 | {
36 | stream = _stream;
37 | }
38 |
39 | bool HasIllegalChar() const
40 | {
41 | return false;
42 | }
43 | };
44 |
45 | template
46 | class UtfStreamConsumerApiRedirection : public Object
47 | {
48 | private:
49 | T& internalConsumer;
50 |
51 | public:
52 | UtfStreamConsumerApiRedirection(T& _internalConsumer)
53 | : internalConsumer(_internalConsumer)
54 | {
55 | }
56 |
57 | void Setup(IStream* _stream)
58 | {
59 | internalConsumer.Setup(_stream);
60 | }
61 |
62 | encoding::UtfCharCluster SourceCluster() const
63 | {
64 | return internalConsumer.SourceCluster();
65 | }
66 | };
67 |
68 | /***********************************************************************
69 | UtfStreamToStreamReader
70 | ***********************************************************************/
71 |
72 | template
73 | using UtfStreamToStreamReader = encoding::UtfToUtfReaderBase, UtfStreamConsumerApiRedirection>;
74 |
75 | /***********************************************************************
76 | Unicode General
77 | ***********************************************************************/
78 |
79 | template
80 | struct MaxPossibleCodePoints
81 | {
82 | static const vint Value = encoding::UtfConversion::BufferLength;
83 | };
84 |
85 | template<>
86 | struct MaxPossibleCodePoints
87 | {
88 | static const vint Value = 1;
89 | };
90 |
91 | template
92 | class UtfGeneralEncoder : public EncoderBase
93 | {
94 | using TStringRangeReader = encoding::UtfStringRangeToStringRangeReader;
95 | protected:
96 | vuint8_t cacheBuffer[sizeof(TExpect) * MaxPossibleCodePoints::Value];
97 | vint cacheSize = 0;
98 |
99 | public:
100 |
101 | vint Write(void* _buffer, vint _size) override;
102 | };
103 |
104 | template
105 | class UtfGeneralDecoder : public DecoderBase
106 | {
107 | using TStreamReader = UtfStreamToStreamReader;
108 | protected:
109 | vuint8_t cacheBuffer[sizeof(TExpect)];
110 | vint cacheSize = 0;
111 | TStreamReader reader;
112 |
113 | public:
114 |
115 | void Setup(IStream* _stream) override;
116 | vint Read(void* _buffer, vint _size) override;
117 | };
118 |
119 | /***********************************************************************
120 | Unicode General (without conversion)
121 | ***********************************************************************/
122 |
123 | template
124 | class UtfGeneralEncoder : public EncoderBase
125 | {
126 | public:
127 | vint Write(void* _buffer, vint _size) override;
128 | };
129 |
130 | template
131 | class UtfGeneralDecoder : public DecoderBase
132 | {
133 | public:
134 | vint Read(void* _buffer, vint _size) override;
135 | };
136 |
137 | #if defined VCZH_WCHAR_UTF16
138 |
139 | template<>
140 | class UtfGeneralEncoder : public UtfGeneralEncoder {};
141 |
142 | template<>
143 | class UtfGeneralEncoder : public UtfGeneralEncoder {};
144 |
145 | #elif defined VCZH_WCHAR_UTF32
146 |
147 | template<>
148 | class UtfGeneralEncoder : public UtfGeneralEncoder {};
149 |
150 | template<>
151 | class UtfGeneralEncoder : public UtfGeneralEncoder {};
152 |
153 | #endif
154 |
155 | /***********************************************************************
156 | Unicode General (extern templates)
157 | ***********************************************************************/
158 |
159 | extern template class UtfGeneralEncoder;
160 | extern template class UtfGeneralEncoder;
161 | extern template class UtfGeneralEncoder;
162 | extern template class UtfGeneralEncoder;
163 | extern template class UtfGeneralEncoder;
164 |
165 | extern template class UtfGeneralEncoder;
166 | extern template class UtfGeneralEncoder;
167 | extern template class UtfGeneralEncoder;
168 | extern template class UtfGeneralEncoder;
169 | extern template class UtfGeneralEncoder;
170 |
171 | extern template class UtfGeneralEncoder;
172 | extern template class UtfGeneralEncoder;
173 | extern template class UtfGeneralEncoder;
174 | extern template class UtfGeneralEncoder;
175 | extern template class UtfGeneralEncoder;
176 |
177 | extern template class UtfGeneralEncoder;
178 | extern template class UtfGeneralEncoder;
179 | extern template class UtfGeneralEncoder;
180 | extern template class UtfGeneralEncoder;
181 | extern template class UtfGeneralEncoder;
182 |
183 | extern template class UtfGeneralEncoder;
184 | extern template class UtfGeneralEncoder;
185 | extern template class UtfGeneralEncoder;
186 | extern template class UtfGeneralEncoder;
187 | extern template class UtfGeneralEncoder;
188 |
189 | extern template class UtfGeneralDecoder;
190 | extern template class UtfGeneralDecoder;
191 | extern template class UtfGeneralDecoder;
192 | extern template class UtfGeneralDecoder;
193 | extern template class UtfGeneralDecoder;
194 |
195 | extern template class UtfGeneralDecoder;
196 | extern template class UtfGeneralDecoder;
197 | extern template class UtfGeneralDecoder;
198 | extern template class UtfGeneralDecoder;
199 | extern template class UtfGeneralDecoder;
200 |
201 | extern template class UtfGeneralDecoder;
202 | extern template class UtfGeneralDecoder;
203 | extern template class UtfGeneralDecoder;
204 | extern template class UtfGeneralDecoder;
205 | extern template class UtfGeneralDecoder;
206 |
207 | extern template class UtfGeneralDecoder;
208 | extern template class UtfGeneralDecoder;
209 | extern template class UtfGeneralDecoder;
210 | extern template class UtfGeneralDecoder;
211 | extern template class UtfGeneralDecoder;
212 |
213 | extern template class UtfGeneralDecoder;
214 | extern template class UtfGeneralDecoder;
215 | extern template class UtfGeneralDecoder;
216 | extern template class UtfGeneralDecoder;
217 | extern template class UtfGeneralDecoder;
218 | }
219 | }
220 |
221 | #endif
222 |
--------------------------------------------------------------------------------
/Source/Encoding/Encoding.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "Encoding.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | /***********************************************************************
13 | EncoderBase
14 | ***********************************************************************/
15 |
16 | void EncoderBase::Setup(IStream* _stream)
17 | {
18 | stream = _stream;
19 | }
20 |
21 | void EncoderBase::Close()
22 | {
23 | }
24 |
25 | /***********************************************************************
26 | DecoderBase
27 | ***********************************************************************/
28 |
29 | void DecoderBase::Setup(IStream* _stream)
30 | {
31 | stream = _stream;
32 | }
33 |
34 | void DecoderBase::Close()
35 | {
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Source/Encoding/Encoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_ENCODING
7 | #define VCZH_STREAM_ENCODING_ENCODING
8 |
9 | #include "../Stream/Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /***********************************************************************
16 | IEncoder and IDecoder
17 | ***********************************************************************/
18 |
19 | /// Encoder interface. This interface defines a writable transformation from one stream to another stream. You can create a [T:vl.stream.EncoderStream] after you have an encoder.
20 | class IEncoder : public Interface
21 | {
22 | public:
23 | /// Set a target writable stream to receive data. transforms the content and write to this tream.
24 | /// The target writable stream.
25 | virtual void Setup(IStream* _stream)=0;
26 | /// Stop the transformation, ensuring all content is written to the target stream.
27 | virtual void Close()=0;
28 | ///
29 | /// Transform content and write to the target stream.
30 | /// This function could use caching to improve performance.
31 | /// Please do not expect that all transformed content will be written to the target stream immediately.
32 | ///
33 | ///
34 | /// Returns the actual size of the content that has written before transforming.
35 | /// A successful write operation may only cache the data without actually write anything to the target stream.
36 | ///
37 | /// A buffer storing the content to transform.
38 | /// The expected size of the content in bytes in "_buffer" to use.
39 | virtual vint Write(void* _buffer, vint _size)=0;
40 | };
41 |
42 | /// Decoder interface. This interface defines a readable transformation from one stream to another stream. You can create a [T:vl.stream.DecoderStream] after you have an decoder.
43 | class IDecoder : public Interface
44 | {
45 | public:
46 | ///
47 | /// Set a target readable stream.
48 | /// reads from this tream and transform the content.
49 | ///
50 | /// The target readable stream.
51 | virtual void Setup(IStream* _stream)=0;
52 | /// Stop the transformation.
53 | virtual void Close()=0;
54 | /// Read from the target stream and transform the content.
55 | /// Returns the actual size of the content has read after transforming.
56 | /// A buffer to store the content.
57 | /// The expected size of the content in bytes in "_buffer" to receive.
58 | virtual vint Read(void* _buffer, vint _size)=0;
59 | };
60 |
61 | /***********************************************************************
62 | EncoderBase and DecoderBase
63 | ***********************************************************************/
64 |
65 | /// Basic implementation of IEncoder.
66 | class EncoderBase : public Object, public IEncoder
67 | {
68 | protected:
69 | IStream* stream = nullptr;
70 |
71 | public:
72 |
73 | void Setup(IStream* _stream) override;
74 | void Close() override;
75 | };
76 |
77 | /// Basic implementation of IDecoder.
78 | class DecoderBase : public Object, public IDecoder
79 | {
80 | protected:
81 | IStream* stream = nullptr;
82 |
83 | public:
84 |
85 | void Setup(IStream* _stream) override;
86 | void Close() override;
87 | };
88 | }
89 | }
90 |
91 | #endif
--------------------------------------------------------------------------------
/Source/Encoding/LzwEncoding.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODING_LZWENCODING
7 | #define VCZH_STREAM_ENCODING_LZWENCODING
8 |
9 | #include "Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 |
16 | /***********************************************************************
17 | Compression
18 | ***********************************************************************/
19 |
20 | namespace lzw
21 | {
22 | static const vint BufferSize = 1024;
23 | static const vint MaxDictionarySize = 1 << 24;
24 |
25 | struct Code
26 | {
27 | typedef collections::PushOnlyAllocator CodeAllocator;
28 | typedef collections::ByteObjectMap::Allocator MapAllocator;
29 |
30 | vuint8_t byte = 0;
31 | vint code = -1;
32 | Code* parent = 0;
33 | vint size = 0;
34 | collections::ByteObjectMap children;
35 | };
36 | }
37 |
38 | class LzwBase : public Object
39 | {
40 | protected:
41 | lzw::Code::CodeAllocator codeAllocator;
42 | lzw::Code::MapAllocator mapAllocator;
43 | lzw::Code* root;
44 | vint eofIndex = -1;
45 | vint nextIndex = 0;
46 | vint indexBits = 1;
47 |
48 | void UpdateIndexBits();
49 | lzw::Code* CreateCode(lzw::Code* parent, vuint8_t byte);
50 |
51 | LzwBase();
52 | LzwBase(bool (&existingBytes)[256]);
53 | ~LzwBase();
54 | };
55 |
56 | /// An encoder to compress data using the Lzw algorithm.
57 | ///
58 | /// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
59 | /// and is recommended.
60 | ///
61 | class LzwEncoder : public LzwBase, public EncoderBase
62 | {
63 | protected:
64 | vuint8_t buffer[lzw::BufferSize];
65 | vint bufferUsedBits = 0;
66 | lzw::Code* prefix;
67 |
68 | void Flush();
69 | void WriteNumber(vint number, vint bitSize);
70 | public:
71 | /// Create an encoder.
72 | LzwEncoder();
73 | /// Create an encoder, specifying what bytes will never appear in the data to compress.
74 | ///
75 | /// A filter array
76 | /// If existingBytes[x] == true, it means x will possibly appear.
77 | /// If existingBytes[x] == false, it means x will never appear.
78 | ///
79 | ///
80 | /// The behavior is undefined, if existingBytes[x] == false, but byte x is actually in the data to compress.
81 | ///
82 | LzwEncoder(bool (&existingBytes)[256]);
83 | ~LzwEncoder();
84 |
85 | void Close()override;
86 | vint Write(void* _buffer, vint _size)override;
87 | };
88 |
89 | /// An decoder to decompress data using the Lzw algorithm.
90 | ///
91 | /// You are not recommended to compress data more than 1 mega bytes at once using the encoder directly.
92 | /// and is recommended.
93 | ///
94 | class LzwDecoder :public LzwBase, public DecoderBase
95 | {
96 | protected:
97 | collections::List dictionary;
98 | lzw::Code* lastCode = 0;
99 |
100 | vuint8_t inputBuffer[lzw::BufferSize];
101 | vint inputBufferSize = 0;
102 | vint inputBufferUsedBits = 0;
103 |
104 | collections::Array outputBuffer;
105 | vint outputBufferSize = 0;
106 | vint outputBufferUsedBytes = 0;
107 |
108 | bool ReadNumber(vint& number, vint bitSize);
109 | void PrepareOutputBuffer(vint size);
110 | void ExpandCodeToOutputBuffer(lzw::Code* code);
111 | public:
112 | /// Create a decoder.
113 | LzwDecoder();
114 | /// Create an encoder, specifying what bytes will never appear in the decompressed data.
115 | ///
116 | /// A filter array
117 | /// If existingBytes[x] == true, it means x will possibly appear.
118 | /// If existingBytes[x] == false, it means x will never appear.
119 | ///
120 | ///
121 | /// The array "existingBytes" should exactly match the one given to .
122 | ///
123 | LzwDecoder(bool (&existingBytes)[256]);
124 | ~LzwDecoder();
125 |
126 | vint Read(void* _buffer, vint _size)override;
127 | };
128 |
129 | /***********************************************************************
130 | Helper Functions
131 | ***********************************************************************/
132 |
133 | /// Copy data from a readable input stream to a writable output stream.
134 | /// Data copied in bytes.
135 | /// The readable input stream.
136 | /// The writable output stream.
137 | extern vint CopyStream(stream::IStream& inputStream, stream::IStream& outputStream);
138 |
139 | /// Compress data from a readable input stream to a writable output stream.
140 | /// Data copied in bytes.
141 | /// The readable input stream.
142 | /// The writable output stream.
143 | ///
144 | /// Data is compressed in multiple batches,
145 | /// the is expected output stream to have data in multiple parts.
146 | /// In each part, the first 4 bytes is the data before compression in bytes.
147 | /// the rest is the compressed data.
148 | ///
149 | ///
172 | extern void CompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
173 |
174 | /// Decompress data from a readable input stream (with compressed data) to a writable output stream (with uncompressed data).
175 | /// Data copied in bytes.
176 | /// The readable input stream.
177 | /// The writable output stream.
178 | ///
179 | /// Data is compressed in multiple batches,
180 | /// the is expected input stream to have data in multiple parts.
181 | /// In each part, the first 4 bytes is the data before compression in bytes.
182 | /// the rest is the compressed data.
183 | ///
184 | ///
207 | extern void DecompressStream(stream::IStream& inputStream, stream::IStream& outputStream);
208 | }
209 | }
210 |
211 | #endif
--------------------------------------------------------------------------------
/Source/FileSystem.Linux.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "FileSystem.h"
7 | #include "Locale.h"
8 | #include "Stream/FileStream.h"
9 | #include "Stream/MemoryWrapperStream.h"
10 | #include "Stream/Accessor.h"
11 | #include "Stream/EncodingStream.h"
12 | #include
13 | #include
14 | #include
15 |
16 | #ifndef VCZH_GCC
17 | static_assert(false, "Do not build this file for Windows applications.");
18 | #endif
19 |
20 | namespace vl
21 | {
22 | namespace filesystem
23 | {
24 | using namespace collections;
25 | using namespace stream;
26 |
27 | /***********************************************************************
28 | FilePath
29 | ***********************************************************************/
30 |
31 | const wchar_t FilePath::Delimiter;
32 |
33 | void FilePath::Initialize()
34 | {
35 | {
36 | Array buffer(fullPath.Length() + 1);
37 | wcscpy(&buffer[0], fullPath.Buffer());
38 | NormalizeDelimiters(buffer);
39 | fullPath = &buffer[0];
40 | }
41 |
42 | if (fullPath.Length() == 0)
43 | fullPath = WString::Unmanaged(L"/");
44 |
45 | if (fullPath[0] != Delimiter)
46 | {
47 | char buffer[PATH_MAX] = { 0 };
48 | getcwd(buffer, PATH_MAX);
49 | fullPath = atow(AString(buffer)) + WString::FromChar(Delimiter) + fullPath;
50 | }
51 |
52 | {
53 | collections::List components;
54 | GetPathComponents(fullPath, components);
55 | for (int i = 0; i < components.Count(); i++)
56 | {
57 | if (components[i] == L".")
58 | {
59 | components.RemoveAt(i);
60 | i--;
61 | }
62 | else if (components[i] == L"..")
63 | {
64 | if (i > 0)
65 | {
66 | components.RemoveAt(i);
67 | components.RemoveAt(i - 1);
68 | i -= 2;
69 | }
70 | else
71 | {
72 | throw ArgumentException(L"Illegal path.");
73 | }
74 | }
75 | }
76 |
77 | fullPath = ComponentsToPath(components);
78 | }
79 |
80 | TrimLastDelimiter(fullPath);
81 | }
82 |
83 | bool FilePath::IsFile()const
84 | {
85 | struct stat info;
86 | AString path = wtoa(fullPath);
87 | int result = stat(path.Buffer(), &info);
88 | if(result != 0) return false;
89 | else return S_ISREG(info.st_mode);
90 | }
91 |
92 | bool FilePath::IsFolder()const
93 | {
94 | struct stat info;
95 | AString path = wtoa(fullPath);
96 | int result = stat(path.Buffer(), &info);
97 | if(result != 0) return false;
98 | else return S_ISDIR(info.st_mode);
99 | }
100 |
101 | bool FilePath::IsRoot()const
102 | {
103 | return fullPath == L"/";
104 | }
105 |
106 | WString FilePath::GetRelativePathFor(const FilePath& _filePath) const
107 | {
108 | if (fullPath.Length() == 0 || _filePath.fullPath.Length() == 0 || fullPath[0] != _filePath.fullPath[0])
109 | {
110 | return _filePath.fullPath;
111 | }
112 |
113 | collections::List srcComponents, tgtComponents, resultComponents;
114 | GetPathComponents(IsFolder() ? fullPath : GetFolder().GetFullPath(), srcComponents);
115 | GetPathComponents(_filePath.fullPath, tgtComponents);
116 |
117 | int minLength = srcComponents.Count() <= tgtComponents.Count() ? srcComponents.Count() : tgtComponents.Count();
118 | int lastCommonComponent = 0;
119 | for (int i = 0; i < minLength; i++)
120 | {
121 | if (srcComponents[i] == tgtComponents[i])
122 | {
123 | lastCommonComponent = i;
124 | }
125 | else
126 | break;
127 | }
128 |
129 | for (int i = lastCommonComponent + 1; i < srcComponents.Count(); i++)
130 | {
131 | resultComponents.Add(L"..");
132 | }
133 |
134 | for (int i = lastCommonComponent + 1; i < tgtComponents.Count(); i++)
135 | {
136 | resultComponents.Add(tgtComponents[i]);
137 | }
138 |
139 | return ComponentsToPath(resultComponents);
140 | }
141 |
142 | /***********************************************************************
143 | File
144 | ***********************************************************************/
145 |
146 | bool File::Delete()const
147 | {
148 | AString path = wtoa(filePath.GetFullPath());
149 | return unlink(path.Buffer()) == 0;
150 | }
151 |
152 | bool File::Rename(const WString& newName)const
153 | {
154 | AString oldFileName = wtoa(filePath.GetFullPath());
155 | AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
156 | return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
157 | }
158 |
159 | /***********************************************************************
160 | Folder
161 | ***********************************************************************/
162 |
163 | bool Folder::GetFolders(collections::List& folders)const
164 | {
165 | if (!Exists()) return false;
166 |
167 | DIR *dir;
168 | AString searchPath = wtoa(filePath.GetFullPath());
169 |
170 | if ((dir = opendir(searchPath.Buffer())) == NULL)
171 | {
172 | return false;
173 | }
174 |
175 | struct dirent* entry;
176 | while ((entry = readdir(dir)) != NULL)
177 | {
178 | WString childName = atow(AString(entry->d_name));
179 | FilePath childFullPath = filePath / childName;
180 | if (childName != L"." && childName != L".." && childFullPath.IsFolder())
181 | {
182 | folders.Add(Folder(childFullPath));
183 | }
184 | }
185 |
186 | if (closedir(dir) != 0)
187 | {
188 | return false;
189 | }
190 |
191 | return true;
192 | }
193 |
194 | bool Folder::GetFiles(collections::List& files)const
195 | {
196 | if (!Exists()) return false;
197 |
198 | DIR* dir;
199 | AString searchPath = wtoa(filePath.GetFullPath());
200 |
201 | if ((dir = opendir(searchPath.Buffer())) == NULL)
202 | {
203 | return false;
204 | }
205 |
206 | struct dirent* entry;
207 | while ((entry = readdir(dir)) != NULL)
208 | {
209 | FilePath childFullPath = filePath / (atow(AString(entry->d_name)));
210 | if (childFullPath.IsFile())
211 | {
212 | files.Add(File(childFullPath));
213 | }
214 | }
215 |
216 | if (closedir(dir) != 0)
217 | {
218 | return false;
219 | }
220 |
221 | return true;
222 | }
223 |
224 | bool Folder::CreateNonRecursively()const
225 | {
226 | AString path = wtoa(filePath.GetFullPath());
227 | return mkdir(path.Buffer(), 0777) == 0;
228 | }
229 |
230 | bool Folder::DeleteNonRecursively()const
231 | {
232 | AString path = wtoa(filePath.GetFullPath());
233 | return rmdir(path.Buffer()) == 0;
234 | }
235 |
236 | bool Folder::Rename(const WString& newName)const
237 | {
238 | AString oldFileName = wtoa(filePath.GetFullPath());
239 | AString newFileName = wtoa((filePath.GetFolder() / newName).GetFullPath());
240 | return rename(oldFileName.Buffer(), newFileName.Buffer()) == 0;
241 | }
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/Source/FileSystem.Windows.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "FileSystem.h"
7 | #include "Locale.h"
8 | #include "Stream/FileStream.h"
9 | #include "Stream/MemoryWrapperStream.h"
10 | #include "Stream/Accessor.h"
11 | #include "Stream/EncodingStream.h"
12 | #include
13 | #include
14 |
15 | #ifndef VCZH_MSVC
16 | static_assert(false, "Do not build this file for non-Windows applications.");
17 | #endif
18 |
19 | #pragma comment(lib, "Shlwapi.lib")
20 |
21 | namespace vl
22 | {
23 | namespace filesystem
24 | {
25 | using namespace collections;
26 | using namespace stream;
27 |
28 | /***********************************************************************
29 | FilePath
30 | ***********************************************************************/
31 |
32 | void FilePath::Initialize()
33 | {
34 | {
35 | Array buffer(fullPath.Length() + 1);
36 | wcscpy_s(&buffer[0], fullPath.Length() + 1, fullPath.Buffer());
37 | NormalizeDelimiters(buffer);
38 | fullPath = &buffer[0];
39 | }
40 |
41 | if (fullPath != L"")
42 | {
43 | if (fullPath.Length() < 2 || fullPath[1] != L':')
44 | {
45 | wchar_t buffer[MAX_PATH + 1] = { 0 };
46 | auto result = GetCurrentDirectory(sizeof(buffer) / sizeof(*buffer), buffer);
47 | if (result > MAX_PATH + 1 || result == 0)
48 | {
49 | throw ArgumentException(L"Failed to call GetCurrentDirectory.", L"vl::filesystem::FilePath::Initialize", L"");
50 | }
51 | fullPath = WString(buffer) + L"\\" + fullPath;
52 | }
53 | {
54 | wchar_t buffer[MAX_PATH + 1] = { 0 };
55 | if (fullPath.Length() == 2 && fullPath[1] == L':')
56 | {
57 | fullPath += L"\\";
58 | }
59 | auto result = GetFullPathName(fullPath.Buffer(), sizeof(buffer) / sizeof(*buffer), buffer, NULL);
60 | if (result > MAX_PATH + 1 || result == 0)
61 | {
62 | throw ArgumentException(L"The path is illegal.", L"vl::filesystem::FilePath::FilePath", L"_filePath");
63 | }
64 |
65 | {
66 | wchar_t shortPath[MAX_PATH + 1];
67 | wchar_t longPath[MAX_PATH + 1];
68 | if (GetShortPathName(buffer, shortPath, MAX_PATH) > 0)
69 | {
70 | if (GetLongPathName(shortPath, longPath, MAX_PATH) > 0)
71 | {
72 | memcpy(buffer, longPath, sizeof(buffer));
73 | }
74 | }
75 | }
76 | fullPath = buffer;
77 | }
78 | }
79 |
80 | TrimLastDelimiter(fullPath);
81 | }
82 |
83 | bool FilePath::IsFile()const
84 | {
85 | WIN32_FILE_ATTRIBUTE_DATA info;
86 | BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
87 | if (!result) return false;
88 | return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
89 | }
90 |
91 | bool FilePath::IsFolder()const
92 | {
93 | WIN32_FILE_ATTRIBUTE_DATA info;
94 | BOOL result = GetFileAttributesEx(fullPath.Buffer(), GetFileExInfoStandard, &info);
95 | if (!result) return false;
96 | return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
97 | }
98 |
99 | bool FilePath::IsRoot()const
100 | {
101 | return fullPath == L"";
102 | }
103 |
104 | WString FilePath::GetRelativePathFor(const FilePath& _filePath) const
105 | {
106 | if (fullPath.Length() == 0 || _filePath.fullPath.Length() == 0 || fullPath[0] != _filePath.fullPath[0])
107 | {
108 | return _filePath.fullPath;
109 | }
110 |
111 | wchar_t buffer[MAX_PATH + 1] = { 0 };
112 | PathRelativePathTo(
113 | buffer,
114 | fullPath.Buffer(),
115 | (IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0),
116 | _filePath.fullPath.Buffer(),
117 | (_filePath.IsFolder() ? FILE_ATTRIBUTE_DIRECTORY : 0)
118 | );
119 | return buffer;
120 | }
121 |
122 | /***********************************************************************
123 | File
124 | ***********************************************************************/
125 |
126 | bool File::Delete()const
127 | {
128 | return DeleteFile(filePath.GetFullPath().Buffer()) != 0;
129 | }
130 |
131 | bool File::Rename(const WString& newName)const
132 | {
133 | WString oldFileName = filePath.GetFullPath();
134 | WString newFileName = (filePath.GetFolder() / newName).GetFullPath();
135 | return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0;
136 | }
137 |
138 | /***********************************************************************
139 | Folder
140 | ***********************************************************************/
141 |
142 | bool Folder::GetFolders(collections::List& folders)const
143 | {
144 | if (filePath.IsRoot())
145 | {
146 | auto bufferSize = GetLogicalDriveStrings(0, nullptr);
147 | if (bufferSize > 0)
148 | {
149 | Array buffer(bufferSize);
150 | if (GetLogicalDriveStrings((DWORD)buffer.Count(), &buffer[0]) > 0)
151 | {
152 | auto begin = &buffer[0];
153 | auto end = begin + buffer.Count();
154 | while (begin < end && *begin)
155 | {
156 | WString driveString = begin;
157 | begin += driveString.Length() + 1;
158 | folders.Add(Folder(FilePath(driveString)));
159 | }
160 | return true;
161 | }
162 | }
163 | return false;
164 | }
165 | else
166 | {
167 | if (!Exists()) return false;
168 | WIN32_FIND_DATA findData;
169 | HANDLE findHandle = INVALID_HANDLE_VALUE;
170 |
171 | while (true)
172 | {
173 | if (findHandle == INVALID_HANDLE_VALUE)
174 | {
175 | WString searchPath = (filePath / L"*").GetFullPath();
176 | findHandle = FindFirstFile(searchPath.Buffer(), &findData);
177 | if (findHandle == INVALID_HANDLE_VALUE)
178 | {
179 | break;
180 | }
181 | }
182 | else
183 | {
184 | BOOL result = FindNextFile(findHandle, &findData);
185 | if (result == 0)
186 | {
187 | FindClose(findHandle);
188 | break;
189 | }
190 | }
191 |
192 | if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
193 | {
194 | if (wcscmp(findData.cFileName, L".") != 0 && wcscmp(findData.cFileName, L"..") != 0)
195 | {
196 | folders.Add(Folder(filePath / findData.cFileName));
197 | }
198 | }
199 | }
200 | return true;
201 | }
202 | }
203 |
204 | bool Folder::GetFiles(collections::List& files)const
205 | {
206 | if (filePath.IsRoot())
207 | {
208 | return true;
209 | }
210 | if (!Exists()) return false;
211 | WIN32_FIND_DATA findData;
212 | HANDLE findHandle = INVALID_HANDLE_VALUE;
213 |
214 | while (true)
215 | {
216 | if (findHandle == INVALID_HANDLE_VALUE)
217 | {
218 | WString searchPath = (filePath / L"*").GetFullPath();
219 | findHandle = FindFirstFile(searchPath.Buffer(), &findData);
220 | if (findHandle == INVALID_HANDLE_VALUE)
221 | {
222 | break;
223 | }
224 | }
225 | else
226 | {
227 | BOOL result = FindNextFile(findHandle, &findData);
228 | if (result == 0)
229 | {
230 | FindClose(findHandle);
231 | break;
232 | }
233 | }
234 |
235 | if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
236 | {
237 | files.Add(File(filePath / findData.cFileName));
238 | }
239 | }
240 | return true;
241 | }
242 |
243 | bool Folder::CreateNonRecursively()const
244 | {
245 | return CreateDirectory(filePath.GetFullPath().Buffer(), NULL) != 0;
246 | }
247 |
248 | bool Folder::DeleteNonRecursively()const
249 | {
250 | return RemoveDirectory(filePath.GetFullPath().Buffer()) != 0;
251 | }
252 |
253 | bool Folder::Rename(const WString& newName)const
254 | {
255 | WString oldFileName = filePath.GetFullPath();
256 | WString newFileName = (filePath.GetFolder() / newName).GetFullPath();
257 | return MoveFile(oldFileName.Buffer(), newFileName.Buffer()) != 0;
258 | }
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/Source/HttpUtility.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_HTTPUTILITY
7 | #define VCZH_HTTPUTILITY
8 |
9 | #include
10 |
11 | #ifdef VCZH_MSVC
12 |
13 | namespace vl
14 | {
15 |
16 | /***********************************************************************
17 | HTTP Utility
18 | ***********************************************************************/
19 |
20 | /// An http requiest.
21 | class HttpRequest
22 | {
23 | typedef collections::Array BodyBuffer;
24 | typedef collections::List StringList;
25 | typedef collections::Dictionary HeaderMap;
26 | public:
27 | /// Name of the server, like "gaclib.net".
28 | WString server;
29 | /// Port of the server, like 80.
30 | vint port = 0;
31 | /// Query of the request, like "/index.html".
32 | WString query;
33 | /// Set to true if the request uses SSL, or https.
34 | bool secure = false;
35 | /// User name to authorize. Set to empty if authorization is not needed.
36 | WString username;
37 | /// Password to authorize. Set to empty if authorization is not needed.
38 | WString password;
39 | /// HTTP method, like "GET", "POST", "PUT", "DELETE", etc.
40 | WString method;
41 | /// Cookie. Set to empty if cookie is not needed.
42 | WString cookie;
43 | /// Request body. This is a byte array.
44 | BodyBuffer body;
45 | /// Content type, like "text/xml".
46 | WString contentType;
47 | /// Accept type list, elements like "text/xml".
48 | StringList acceptTypes;
49 | /// A dictionary to contain extra headers.
50 | HeaderMap extraHeaders;
51 |
52 | /// Create an empty request.
53 | HttpRequest() = default;
54 |
55 | /// Set , , and fields for you using an URL.
56 | /// Returns true if this operation succeeded.
57 | /// The URL.
58 | bool SetHost(const WString& inputQuery);
59 |
60 | /// Fill the text body in UTF-8.
61 | /// The text to fill.
62 | void SetBodyUtf8(const WString& bodyString);
63 | };
64 |
65 | /// A type representing an http response.
66 | class HttpResponse
67 | {
68 | typedef collections::Array BodyBuffer;
69 | public:
70 | /// Status code, like 200.
71 | vint statusCode = 0;
72 | /// Response body. This is a byte array.
73 | BodyBuffer body;
74 | /// Returned cookie from the server.
75 | WString cookie;
76 |
77 | HttpResponse() = default;
78 |
79 | /// Get the text body, encoding is assumed to be UTF-8.
80 | /// The response body as text.
81 | WString GetBodyUtf8();
82 | };
83 |
84 | /// Send an http request and receive a response.
85 | /// Returns true if this operation succeeded, even when the server returns 404.
86 | /// The request to send.
87 | /// Returns the response.
88 | ///
89 | ///
90 | /// This function will block the calling thread until the respons is returned.
91 | ///
92 | ///
93 | /// This function is only available in Windows.
94 | ///
95 | ///
96 | ///
107 | extern bool HttpQuery(const HttpRequest& request, HttpResponse& response);
108 |
109 | /// Encode a text as part of the url. This function can be used to create arguments in an URL.
110 | /// The encoded text.
111 | /// The text to encode.
112 | ///
113 | ///
114 | /// When a character is not a digit or a letter,
115 | /// it is first encoded to UTF-8,
116 | /// then each byte is written as "%" with two hex digits.
117 | ///
118 | ///
119 | /// This function is only available in Windows.
120 | ///
121 | ///
122 | extern WString UrlEncodeQuery(const WString& query);
123 | }
124 |
125 | #endif
126 |
127 | #endif
128 |
--------------------------------------------------------------------------------
/Source/Locale.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "Locale.h"
7 |
8 | namespace vl
9 | {
10 |
11 | /***********************************************************************
12 | Locale
13 | ***********************************************************************/
14 |
15 | Locale::Locale(const WString& _localeName)
16 | :localeName(_localeName)
17 | {
18 | }
19 |
20 | const WString& Locale::GetName()const
21 | {
22 | return localeName;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/Stream/BroadcastStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include
7 | #include "BroadcastStream.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | BroadcastStream
15 | ***********************************************************************/
16 |
17 | BroadcastStream::BroadcastStream()
18 | :closed(false)
19 | ,position(0)
20 | {
21 | }
22 |
23 | BroadcastStream::~BroadcastStream()
24 | {
25 | }
26 |
27 | BroadcastStream::StreamList& BroadcastStream::Targets()
28 | {
29 | return streams;
30 | }
31 |
32 | bool BroadcastStream::CanRead()const
33 | {
34 | return false;
35 | }
36 |
37 | bool BroadcastStream::CanWrite()const
38 | {
39 | return !closed;
40 | }
41 |
42 | bool BroadcastStream::CanSeek()const
43 | {
44 | return false;
45 | }
46 |
47 | bool BroadcastStream::CanPeek()const
48 | {
49 | return false;
50 | }
51 |
52 | bool BroadcastStream::IsLimited()const
53 | {
54 | return false;
55 | }
56 |
57 | bool BroadcastStream::IsAvailable()const
58 | {
59 | return !closed;
60 | }
61 |
62 | void BroadcastStream::Close()
63 | {
64 | closed=true;
65 | position=-1;
66 | }
67 |
68 | pos_t BroadcastStream::Position()const
69 | {
70 | return position;
71 | }
72 |
73 | pos_t BroadcastStream::Size()const
74 | {
75 | return position;
76 | }
77 |
78 | void BroadcastStream::Seek(pos_t _size)
79 | {
80 | CHECK_FAIL(L"BroadcastStream::Seek(pos_t)#Operation not supported.");
81 | }
82 |
83 | void BroadcastStream::SeekFromBegin(pos_t _size)
84 | {
85 | CHECK_FAIL(L"BroadcastStream::SeekFromBegin(pos_t)#Operation not supported.");
86 | }
87 |
88 | void BroadcastStream::SeekFromEnd(pos_t _size)
89 | {
90 | CHECK_FAIL(L"BroadcastStream::SeekFromEnd(pos_t)#Operation not supported.");
91 | }
92 |
93 | vint BroadcastStream::Read(void* _buffer, vint _size)
94 | {
95 | CHECK_FAIL(L"BroadcastStream::Read(void*, vint)#Operation not supported.");
96 | }
97 |
98 | vint BroadcastStream::Write(void* _buffer, vint _size)
99 | {
100 | // TODO: (enumerable) foreach
101 | for(vint i=0;iWrite(_buffer, _size);
104 | CHECK_ERROR(written == _size, L"BroadcastStream::Write(void*, vint)#Failed to copy data to the output stream.");
105 | }
106 | position+=_size;
107 | return _size;
108 | }
109 |
110 | vint BroadcastStream::Peek(void* _buffer, vint _size)
111 | {
112 | CHECK_FAIL(L"BroadcastStream::Peek(void*, vint)#Operation not supported.");
113 | }
114 | }
115 | }
--------------------------------------------------------------------------------
/Source/Stream/BroadcastStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_BROADCASTSTREAM
7 | #define VCZH_STREAM_BROADCASTSTREAM
8 |
9 | #include "Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /// A writable stream that copy the written content to multiple output streams.
16 | ///
17 | /// When writing happens, the boreadcast stream will only performance one write attempt to each output stream.
18 | ///
19 | class BroadcastStream : public Object, public virtual IStream
20 | {
21 | typedef collections::List StreamList;
22 | protected:
23 | bool closed;
24 | pos_t position;
25 | StreamList streams;
26 | public:
27 | /// Create a boradcast stream.
28 | BroadcastStream();
29 | ~BroadcastStream();
30 |
31 | ///
32 | /// Get the list of output streams.
33 | /// You can change this list to subscribe or unsubscribe.
34 | ///
35 | /// The list of output streams.
36 | StreamList& Targets();
37 | bool CanRead()const;
38 | bool CanWrite()const;
39 | bool CanSeek()const;
40 | bool CanPeek()const;
41 | bool IsLimited()const;
42 | bool IsAvailable()const;
43 | void Close();
44 | pos_t Position()const;
45 | pos_t Size()const;
46 | void Seek(pos_t _size);
47 | void SeekFromBegin(pos_t _size);
48 | void SeekFromEnd(pos_t _size);
49 | vint Read(void* _buffer, vint _size);
50 | vint Write(void* _buffer, vint _size);
51 | vint Peek(void* _buffer, vint _size);
52 | };
53 | }
54 | }
55 |
56 | #endif
--------------------------------------------------------------------------------
/Source/Stream/CacheStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include
7 | #include "CacheStream.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | CacheStream
15 | ***********************************************************************/
16 |
17 | void CacheStream::Flush()
18 | {
19 | if(dirtyLength>0)
20 | {
21 | if(target->Position()!=start+dirtyStart)
22 | {
23 | target->SeekFromBegin(start+dirtyStart);
24 | }
25 | target->Write(buffer+dirtyStart, dirtyLength);
26 | }
27 | dirtyStart=0;
28 | dirtyLength=0;
29 | availableLength=0;
30 | }
31 |
32 | void CacheStream::Load(pos_t _position)
33 | {
34 | if(target->Position()!=_position)
35 | {
36 | target->SeekFromBegin(_position);
37 | }
38 | start=_position;
39 | if(target->CanRead())
40 | {
41 | availableLength=target->Read(buffer, block);
42 | }
43 | }
44 |
45 | vint CacheStream::InternalRead(void* _buffer, vint _size)
46 | {
47 | vint readed=0;
48 | if(position>=start && positionreaded)
58 | {
59 | Flush();
60 | if(_size-readed>=block)
61 | {
62 | if(CanSeek())
63 | {
64 | target->SeekFromBegin(position+readed);
65 | }
66 | vint additional=target->Read(_buffer, _size-readed);
67 | if(additional!=-1)
68 | {
69 | readed+=additional;
70 | }
71 | }
72 | else
73 | {
74 | Load(position+readed);
75 | vint remain=_size-readed;
76 | vint min=availableLength=start && position0)
109 | {
110 | availableLength+=availableOffset;
111 | }
112 | }
113 |
114 | if(_size>written)
115 | {
116 | Flush();
117 | if(_size-written>=block)
118 | {
119 | if(CanSeek())
120 | {
121 | target->SeekFromBegin(position+written);
122 | }
123 | vint additional=target->Write(_buffer, _size-written);
124 | if(additional!=-1)
125 | {
126 | written+=additional;
127 | }
128 | }
129 | else
130 | {
131 | Load(position+written);
132 | dirtyLength=_size-written;
133 | memcpy(buffer, _buffer, dirtyLength);
134 | written+=dirtyLength;
135 | }
136 | }
137 | return written;
138 | }
139 |
140 | CacheStream::CacheStream(IStream& _target, vint _block)
141 | :target(&_target)
142 | ,block(_block)
143 | ,start(0)
144 | ,position(0)
145 | ,dirtyStart(0)
146 | ,dirtyLength(0)
147 | ,availableLength(0)
148 | ,operatedSize(0)
149 | {
150 | if(block<=0)
151 | {
152 | block=65536;
153 | }
154 | buffer=new char[block];
155 | }
156 |
157 | CacheStream::~CacheStream()
158 | {
159 | Close();
160 | }
161 |
162 | bool CacheStream::CanRead()const
163 | {
164 | return target!=0 && target->CanRead();
165 | }
166 |
167 | bool CacheStream::CanWrite()const
168 | {
169 | return target!=0 && target->CanWrite();
170 | }
171 |
172 | bool CacheStream::CanSeek()const
173 | {
174 | return target!=0 && target->CanSeek();
175 | }
176 |
177 | bool CacheStream::CanPeek()const
178 | {
179 | return target!=0 && target->CanPeek();
180 | }
181 |
182 | bool CacheStream::IsLimited()const
183 | {
184 | return target!=0 && target->IsLimited();
185 | }
186 |
187 | bool CacheStream::IsAvailable()const
188 | {
189 | return target!=0 && target->IsAvailable();
190 | }
191 |
192 | void CacheStream::Close()
193 | {
194 | Flush();
195 | target=0;
196 | delete[] buffer;
197 | buffer=0;
198 | position=-1;
199 | dirtyStart=0;
200 | dirtyLength=0;
201 | availableLength=0;
202 | operatedSize=-1;
203 | }
204 |
205 | pos_t CacheStream::Position()const
206 | {
207 | return position;
208 | }
209 |
210 | pos_t CacheStream::Size()const
211 | {
212 | if(target!=0)
213 | {
214 | if(IsLimited())
215 | {
216 | return target->Size();
217 | }
218 | else
219 | {
220 | return operatedSize;
221 | }
222 | }
223 | else
224 | {
225 | return -1;
226 | }
227 | }
228 |
229 | void CacheStream::Seek(pos_t _size)
230 | {
231 | SeekFromBegin(position+_size);
232 | }
233 |
234 | void CacheStream::SeekFromBegin(pos_t _size)
235 | {
236 | if(CanSeek())
237 | {
238 | if(_size<0)
239 | {
240 | position=0;
241 | }
242 | else if(_size>Size())
243 | {
244 | position=Size();
245 | }
246 | else
247 | {
248 | position=_size;
249 | }
250 | }
251 | }
252 |
253 | void CacheStream::SeekFromEnd(pos_t _size)
254 | {
255 | SeekFromBegin(Size()-_size);
256 | }
257 |
258 | vint CacheStream::Read(void* _buffer, vint _size)
259 | {
260 | CHECK_ERROR(CanRead(), L"CacheStream::Read(void*, vint)#Stream is closed or operation not supported.");
261 | CHECK_ERROR(_size>=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative.");
262 |
263 | _size=InternalRead(_buffer, _size);
264 | position+=_size;
265 | if(operatedSize=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative.");
276 |
277 | if(IsLimited())
278 | {
279 | pos_t size=Size();
280 | if(size!=-1)
281 | {
282 | vint remain=(vint)(size-(position+_size));
283 | if(remain<0)
284 | {
285 | _size-=remain;
286 | }
287 | }
288 | }
289 |
290 | _size=InternalWrite(_buffer, _size);
291 | position+=_size;
292 | if(operatedSize=0, L"CacheStream::Read(void*, vint)#Argument size cannot be negative.");
303 |
304 | return InternalRead(_buffer, _size);
305 | }
306 | }
307 | }
--------------------------------------------------------------------------------
/Source/Stream/CacheStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_CACHESTREAM
7 | #define VCZH_STREAM_CACHESTREAM
8 |
9 | #include "Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | ///
16 | ///
17 | /// A potentially readable, peekable, writable, seekable and finite stream that creates on another stream.
18 | /// Each feature is available if the target stream has the same feature.
19 | ///
20 | ///
21 | /// When you read from the cache strema,
22 | /// it will read a specified size of content from the target stream at once and cache,
23 | /// reducing the number of operations on the target stream.
24 | ///
25 | ///
26 | /// When you write to the cache stream,
27 | /// it will cache all the data to write,
28 | /// and write to the target stream after the cache is full,
29 | /// reducing the number of operations on the target stream.
30 | ///
31 | ///
32 | class CacheStream : public Object, public virtual IStream
33 | {
34 | protected:
35 | IStream* target;
36 | vint block;
37 | pos_t start;
38 | pos_t position;
39 |
40 | char* buffer;
41 | vint dirtyStart;
42 | vint dirtyLength;
43 | vint availableLength;
44 | pos_t operatedSize;
45 |
46 | void Flush();
47 | void Load(pos_t _position);
48 | vint InternalRead(void* _buffer, vint _size);
49 | vint InternalWrite(void* _buffer, vint _size);
50 | public:
51 | /// Create a cache stream from a target stream.
52 | /// The target stream.
53 | /// Size of the cache.
54 | CacheStream(IStream& _target, vint _block=65536);
55 | ~CacheStream();
56 |
57 | bool CanRead()const;
58 | bool CanWrite()const;
59 | bool CanSeek()const;
60 | bool CanPeek()const;
61 | bool IsLimited()const;
62 | bool IsAvailable()const;
63 | void Close();
64 | pos_t Position()const;
65 | pos_t Size()const;
66 | void Seek(pos_t _size);
67 | void SeekFromBegin(pos_t _size);
68 | void SeekFromEnd(pos_t _size);
69 | vint Read(void* _buffer, vint _size);
70 | vint Write(void* _buffer, vint _size);
71 | vint Peek(void* _buffer, vint _size);
72 | };
73 | }
74 | }
75 |
76 | #endif
--------------------------------------------------------------------------------
/Source/Stream/EncodingStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "EncodingStream.h"
7 |
8 | namespace vl
9 | {
10 | namespace stream
11 | {
12 | /***********************************************************************
13 | EncoderStream
14 | ***********************************************************************/
15 |
16 | EncoderStream::EncoderStream(IStream& _stream, IEncoder& _encoder)
17 | :stream(&_stream)
18 | ,encoder(&_encoder)
19 | ,position(0)
20 | {
21 | encoder->Setup(stream);
22 | }
23 |
24 | EncoderStream::~EncoderStream()
25 | {
26 | Close();
27 | }
28 |
29 | bool EncoderStream::CanRead()const
30 | {
31 | return false;
32 | }
33 |
34 | bool EncoderStream::CanWrite()const
35 | {
36 | return IsAvailable();
37 | }
38 |
39 | bool EncoderStream::CanSeek()const
40 | {
41 | return false;
42 | }
43 |
44 | bool EncoderStream::CanPeek()const
45 | {
46 | return false;
47 | }
48 |
49 | bool EncoderStream::IsLimited()const
50 | {
51 | return stream!=0 && stream->IsLimited();
52 | }
53 |
54 | bool EncoderStream::IsAvailable()const
55 | {
56 | return stream!=0 && stream->IsAvailable();
57 | }
58 |
59 | void EncoderStream::Close()
60 | {
61 | encoder->Close();
62 | stream=0;
63 | }
64 |
65 | pos_t EncoderStream::Position()const
66 | {
67 | return IsAvailable()?position:-1;
68 | }
69 |
70 | pos_t EncoderStream::Size()const
71 | {
72 | return -1;
73 | }
74 |
75 | void EncoderStream::Seek(pos_t _size)
76 | {
77 | CHECK_FAIL(L"EncoderStream::Seek(pos_t)#Operation not supported.");
78 | }
79 |
80 | void EncoderStream::SeekFromBegin(pos_t _size)
81 | {
82 | CHECK_FAIL(L"EncoderStream::SeekFromBegin(pos_t)#Operation not supported.");
83 | }
84 |
85 | void EncoderStream::SeekFromEnd(pos_t _size)
86 | {
87 | CHECK_FAIL(L"EncoderStream::SeekFromEnd(pos_t)#Operation not supported.");
88 | }
89 |
90 | vint EncoderStream::Read(void* _buffer, vint _size)
91 | {
92 | CHECK_FAIL(L"EncoderStream::Read(void*, vint)#Operation not supported.");
93 | }
94 |
95 | vint EncoderStream::Write(void* _buffer, vint _size)
96 | {
97 | vint result=encoder->Write(_buffer, _size);
98 | if(result>=0)
99 | {
100 | position+=result;
101 | }
102 | return result;
103 | }
104 |
105 | vint EncoderStream::Peek(void* _buffer, vint _size)
106 | {
107 | CHECK_FAIL(L"EncoderStream::Peek(void*, vint)#Operation not supported.");
108 | }
109 |
110 | /***********************************************************************
111 | DecoderStream
112 | ***********************************************************************/
113 |
114 | DecoderStream::DecoderStream(IStream& _stream, IDecoder& _decoder)
115 | :stream(&_stream)
116 | ,decoder(&_decoder)
117 | ,position(0)
118 | {
119 | decoder->Setup(stream);
120 | }
121 |
122 | DecoderStream::~DecoderStream()
123 | {
124 | Close();
125 | }
126 |
127 | bool DecoderStream::CanRead()const
128 | {
129 | return IsAvailable();
130 | }
131 |
132 | bool DecoderStream::CanWrite()const
133 | {
134 | return false;
135 | }
136 |
137 | bool DecoderStream::CanSeek()const
138 | {
139 | return false;
140 | }
141 |
142 | bool DecoderStream::CanPeek()const
143 | {
144 | return false;
145 | }
146 |
147 | bool DecoderStream::IsLimited()const
148 | {
149 | return stream!=0 && stream->IsLimited();
150 | }
151 |
152 | bool DecoderStream::IsAvailable()const
153 | {
154 | return stream!=0 && stream->IsAvailable();
155 | }
156 |
157 | void DecoderStream::Close()
158 | {
159 | decoder->Close();
160 | stream=0;
161 | }
162 |
163 | pos_t DecoderStream::Position()const
164 | {
165 | return IsAvailable()?position:-1;
166 | }
167 |
168 | pos_t DecoderStream::Size()const
169 | {
170 | return -1;
171 | }
172 |
173 | void DecoderStream::Seek(pos_t _size)
174 | {
175 | CHECK_FAIL(L"DecoderStream::Seek(pos_t)#Operation not supported.");
176 | }
177 |
178 | void DecoderStream::SeekFromBegin(pos_t _size)
179 | {
180 | CHECK_FAIL(L"DecoderStream::SeekFromBegin(pos_t)#Operation not supported.");
181 | }
182 |
183 | void DecoderStream::SeekFromEnd(pos_t _size)
184 | {
185 | CHECK_FAIL(L"DecoderStream::SeekFromEnd(pos_t)#Operation not supported.");
186 | }
187 |
188 | vint DecoderStream::Read(void* _buffer, vint _size)
189 | {
190 | vint result=decoder->Read(_buffer, _size);
191 | if(result>=0)
192 | {
193 | position+=result;
194 | }
195 | return result;
196 | }
197 |
198 | vint DecoderStream::Write(void* _buffer, vint _size)
199 | {
200 | CHECK_FAIL(L"DecoderStream::Write(void*, vint)#Operation not supported.");
201 | }
202 |
203 | vint DecoderStream::Peek(void* _buffer, vint _size)
204 | {
205 | CHECK_FAIL(L"DecoderStream::Peek(void*, vint)#Operation not supported.");
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/Source/Stream/EncodingStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_ENCODINGSTREAM
7 | #define VCZH_STREAM_ENCODINGSTREAM
8 |
9 | #include "../Encoding/Encoding.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /***********************************************************************
16 | Encoding Related
17 | ***********************************************************************/
18 |
19 | /// Encoder stream, a writable and potentially finite stream using [T:vl.stream.IEncoder] to transform content.
20 | class EncoderStream : public virtual IStream
21 | {
22 | protected:
23 | IStream* stream;
24 | IEncoder* encoder;
25 | pos_t position;
26 |
27 | public:
28 | /// Create en encoder stream.
29 | /// The output stream to write.
30 | /// The encoder to transform content.
31 | EncoderStream(IStream& _stream, IEncoder& _encoder);
32 | ~EncoderStream();
33 |
34 | bool CanRead()const;
35 | bool CanWrite()const;
36 | bool CanSeek()const;
37 | bool CanPeek()const;
38 | bool IsLimited()const;
39 | bool IsAvailable()const;
40 | void Close();
41 | pos_t Position()const;
42 | pos_t Size()const;
43 | void Seek(pos_t _size);
44 | void SeekFromBegin(pos_t _size);
45 | void SeekFromEnd(pos_t _size);
46 | vint Read(void* _buffer, vint _size);
47 | vint Write(void* _buffer, vint _size);
48 | vint Peek(void* _buffer, vint _size);
49 | };
50 |
51 | /// Decoder stream, a readable and potentially finite stream using [T:vl.stream.IDecoder] to transform content.
52 | class DecoderStream : public virtual IStream
53 | {
54 | protected:
55 | IStream* stream;
56 | IDecoder* decoder;
57 | pos_t position;
58 |
59 | public:
60 | /// Create a decoder stream.
61 | /// The input stream to read.
62 | /// The decoder to transform content.
63 | DecoderStream(IStream& _stream, IDecoder& _decoder);
64 | ~DecoderStream();
65 |
66 | bool CanRead()const;
67 | bool CanWrite()const;
68 | bool CanSeek()const;
69 | bool CanPeek()const;
70 | bool IsLimited()const;
71 | bool IsAvailable()const;
72 | void Close();
73 | pos_t Position()const;
74 | pos_t Size()const;
75 | void Seek(pos_t _size);
76 | void SeekFromBegin(pos_t _size);
77 | void SeekFromEnd(pos_t _size);
78 | vint Read(void* _buffer, vint _size);
79 | vint Write(void* _buffer, vint _size);
80 | vint Peek(void* _buffer, vint _size);
81 | };
82 | }
83 | }
84 |
85 | #endif
--------------------------------------------------------------------------------
/Source/Stream/FileStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "FileStream.h"
7 | #if defined VCZH_GCC
8 | #include
9 | #endif
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 |
16 | #if defined VCZH_GCC
17 | void _fseeki64(FILE* file, pos_t offset, int origin)
18 | {
19 | fseek(file, (long)offset, origin);
20 | }
21 | #endif
22 |
23 | /***********************************************************************
24 | FileStream
25 | ***********************************************************************/
26 |
27 | FileStream::FileStream(const WString& fileName, AccessRight _accessRight)
28 | :accessRight(_accessRight)
29 | {
30 | const wchar_t* mode=L"rb";
31 | switch(accessRight)
32 | {
33 | case ReadOnly:
34 | mode=L"rb";
35 | break;
36 | case WriteOnly:
37 | mode=L"wb";
38 | break;
39 | case ReadWrite:
40 | mode=L"w+b";
41 | break;
42 | }
43 |
44 | #if defined VCZH_MSVC
45 | if(_wfopen_s(&file, fileName.Buffer(), mode)!=0)
46 | {
47 | file=0;
48 | }
49 | #elif defined VCZH_GCC
50 | AString fileNameA = wtoa(fileName);
51 | AString modeA = wtoa(mode);
52 | file = fopen(fileNameA.Buffer(), modeA.Buffer());
53 | #endif
54 | }
55 |
56 | FileStream::~FileStream()
57 | {
58 | Close();
59 | }
60 |
61 | bool FileStream::CanRead()const
62 | {
63 | return file!=0 && (accessRight==ReadOnly || accessRight==ReadWrite);
64 | }
65 |
66 | bool FileStream::CanWrite()const
67 | {
68 | return file!=0 && (accessRight==WriteOnly || accessRight==ReadWrite);
69 | }
70 |
71 | bool FileStream::CanSeek()const
72 | {
73 | return file!=0;
74 | }
75 |
76 | bool FileStream::CanPeek()const
77 | {
78 | return file!=0 && (accessRight==ReadOnly || accessRight==ReadWrite);
79 | }
80 |
81 | bool FileStream::IsLimited()const
82 | {
83 | return file!=0 && accessRight==ReadOnly;
84 | }
85 |
86 | bool FileStream::IsAvailable()const
87 | {
88 | return file!=0;
89 | }
90 |
91 | void FileStream::Close()
92 | {
93 | if(file!=0)
94 | {
95 | fclose(file);
96 | file=0;
97 | }
98 | }
99 |
100 | pos_t FileStream::Position()const
101 | {
102 | if(file!=0)
103 | {
104 | #if defined VCZH_MSVC
105 | fpos_t position=0;
106 | if(fgetpos(file, &position)==0)
107 | {
108 | return position;
109 | }
110 | #elif defined VCZH_GCC
111 | return (pos_t)ftell(file);
112 | #endif
113 | }
114 | return -1;
115 | }
116 |
117 | pos_t FileStream::Size()const
118 | {
119 | if(file!=0)
120 | {
121 | #if defined VCZH_MSVC
122 | fpos_t position=0;
123 | if(fgetpos(file, &position)==0)
124 | {
125 | if(fseek(file, 0, SEEK_END)==0)
126 | {
127 | pos_t size=Position();
128 | if(fsetpos(file, &position)==0)
129 | {
130 | return size;
131 | }
132 | }
133 | }
134 | #elif defined VCZH_GCC
135 | long position = ftell(file);
136 | fseek(file, 0, SEEK_END);
137 | long size=ftell(file);
138 | fseek(file, position, SEEK_SET);
139 | return (pos_t)size;
140 | #endif
141 | }
142 | return -1;
143 | }
144 |
145 | void FileStream::Seek(pos_t _size)
146 | {
147 | if(Position()+_size>Size())
148 | {
149 | _fseeki64(file, 0, SEEK_END);
150 | }
151 | else if(Position()+_size<0)
152 | {
153 | _fseeki64(file, 0, SEEK_SET);
154 | }
155 | else
156 | {
157 | _fseeki64(file, _size, SEEK_CUR);
158 | }
159 | }
160 |
161 | void FileStream::SeekFromBegin(pos_t _size)
162 | {
163 | if(_size>Size())
164 | {
165 | _fseeki64(file, 0, SEEK_END);
166 | }
167 | else if(_size<0)
168 | {
169 | _fseeki64(file, 0, SEEK_SET);
170 | }
171 | else
172 | {
173 | _fseeki64(file, _size, SEEK_SET);
174 | }
175 | }
176 |
177 | void FileStream::SeekFromEnd(pos_t _size)
178 | {
179 | if(_size<0)
180 | {
181 | _fseeki64(file, 0, SEEK_END);
182 | }
183 | else if(_size>Size())
184 | {
185 | _fseeki64(file, 0, SEEK_SET);
186 | }
187 | else
188 | {
189 | _fseeki64(file, -_size, SEEK_END);
190 | }
191 | }
192 |
193 | vint FileStream::Read(void* _buffer, vint _size)
194 | {
195 | CHECK_ERROR(file!=0, L"FileStream::Read(pos_t)#Stream is closed, cannot perform this operation.");
196 | CHECK_ERROR(_size>=0, L"FileStream::Read(void*, vint)#Argument size cannot be negative.");
197 | return fread(_buffer, 1, _size, file);
198 | }
199 |
200 | vint FileStream::Write(void* _buffer, vint _size)
201 | {
202 | CHECK_ERROR(file!=0, L"FileStream::Write(pos_t)#Stream is closed, cannot perform this operation.");
203 | CHECK_ERROR(_size>=0, L"FileStream::Write(void*, vint)#Argument size cannot be negative.");
204 | return fwrite(_buffer, 1, _size, file);
205 | }
206 |
207 | vint FileStream::Peek(void* _buffer, vint _size)
208 | {
209 | CHECK_ERROR(file!=0, L"FileStream::Peek(pos_t)#Stream is closed, cannot perform this operation.");
210 | CHECK_ERROR(_size>=0, L"FileStream::Peek(void*, vint)#Argument size cannot be negative.");
211 | #if defined VCZH_MSVC
212 | fpos_t position=0;
213 | if(fgetpos(file, &position)==0)
214 | {
215 | size_t count=fread(_buffer, 1, _size, file);
216 | if(fsetpos(file, &position)==0)
217 | {
218 | return count;
219 | }
220 | }
221 | return -1;
222 | #elif defined VCZH_GCC
223 | long position=ftell(file);
224 | size_t count=fread(_buffer, 1, _size, file);
225 | fseek(file, position, SEEK_SET);
226 | return count;
227 | #endif
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/Source/Stream/FileStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_FILESTREAM
7 | #define VCZH_STREAM_FILESTREAM
8 |
9 | #include
10 | #include "Interfaces.h"
11 |
12 | namespace vl
13 | {
14 | namespace stream
15 | {
16 | /// A file stream. If the given file name is not working, the stream could be unavailable.
17 | class FileStream : public Object, public virtual IStream
18 | {
19 | public:
20 | /// Access to the file.
21 | enum AccessRight
22 | {
23 | /// The file is opened to read, making this stream readable, seekable and finite.
24 | ReadOnly,
25 | /// The file is opened to write, making this stream writable.
26 | WriteOnly,
27 | /// The file is opened to both read and write, making this stream readable, seekable and writable.
28 | ReadWrite
29 | };
30 | protected:
31 | AccessRight accessRight;
32 | FILE* file;
33 | public:
34 | /// Create a file stream from a given file name.
35 | /// The file to operate.
36 | /// Expected operations on the file.
37 | FileStream(const WString& fileName, AccessRight _accessRight);
38 | ~FileStream();
39 |
40 | bool CanRead()const;
41 | bool CanWrite()const;
42 | bool CanSeek()const;
43 | bool CanPeek()const;
44 | bool IsLimited()const;
45 | bool IsAvailable()const;
46 | void Close();
47 | pos_t Position()const;
48 | pos_t Size()const;
49 | void Seek(pos_t _size);
50 | void SeekFromBegin(pos_t _size);
51 | void SeekFromEnd(pos_t _size);
52 | vint Read(void* _buffer, vint _size);
53 | vint Write(void* _buffer, vint _size);
54 | vint Peek(void* _buffer, vint _size);
55 | };
56 | }
57 | }
58 |
59 | #endif
--------------------------------------------------------------------------------
/Source/Stream/Interfaces.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_INTERFACES
7 | #define VCZH_STREAM_INTERFACES
8 |
9 | #include
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | ///
16 | ///
17 | /// Interface for streams.
18 | ///
19 | ///
20 | /// Please notice that, even if you get a stream object, if [M:vl.stream.IStream.IsAvailable] returns false, all other methods cannot be used.
21 | ///
22 | ///
23 | /// Not all methods are available for all types of streams.
24 | /// Feature testing functions must be called before calling other methods, if it is not sure that what kind of stream is being operated against:
25 | ///
26 | ///
27 | ///
28 | /// - Readable: A stream is readable if [M:vl.stream.IStream.CanRead] returns true.
29 | /// - Peekable: A stream is peekable if [M:vl.stream.IStream.CanPeek] returns true.
30 | /// - Writable: A stream is writable if [M:vl.stream.IStream.CanWrite] returns true.
31 | /// - Seekable: A stream is readable if [M:vl.stream.IStream.CanSeek] returns true.
32 | /// - Finite: A stream is finite if [M:vl.stream.IStream.IsLimited] returns true.
33 | ///
34 | ///
35 | ///
36 | class IStream : public virtual Interface
37 | {
38 | public:
39 | /// Test if the stream is readable.
40 | /// Returns true if the stream is readable.
41 | virtual bool CanRead()const=0;
42 | /// Test if the stream is writable.
43 | /// Returns true if the stream is writable.
44 | virtual bool CanWrite()const=0;
45 | /// Test if the stream is seekable.
46 | /// Returns true if the stream is seekable.
47 | virtual bool CanSeek()const=0;
48 | /// Test if the stream is peekable.
49 | /// Returns true if the stream is peekable.
50 | virtual bool CanPeek()const=0;
51 | /// Test if the content of the stream is finite. A writable stream can also be limited, it means that you can only write limited content to the stream.
52 | /// Returns true if the content of the stream is finite.
53 | virtual bool IsLimited()const=0;
54 | /// Test if the stream is available. For example, if you create a readable [T:vl.stream.FileStream] giving a wrong file name, it will be unavailable.
55 | /// Returns true if the stream is available.
56 | virtual bool IsAvailable()const=0;
57 | /// Close the stream, making the stream unavailable.
58 | virtual void Close()=0;
59 | /// Get the current position in the stream.
60 | /// The position in the stream. Returns -1 if the stream is unavailable.
61 | virtual pos_t Position()const=0;
62 | /// Get the size of the content in this stream.
63 | /// The size of the content in this stream. Returns -1 if the size is unsizable or unavailable.
64 | virtual pos_t Size()const=0;
65 | /// Step forward or backward from the current position. It will crash if the stream is unseekable or unavailable.
66 | /// The length to step forward if it is a positive number. The length to step backward if it is a negative number
67 | virtual void Seek(pos_t _size)=0;
68 | /// Step forward from the beginning. It will crash if the stream is unseekable or unavailable.
69 | /// The length to step forward.
70 | virtual void SeekFromBegin(pos_t _size)=0;
71 | /// Step backward from the end. It will crash if the stream is unseekable or unavailable.
72 | /// The length to step backward.
73 | virtual void SeekFromEnd(pos_t _size)=0;
74 | /// Read from the current position and step forward. It will crash if the stream is unreadable or unavailable.
75 | /// Returns the actual size of the content that has read. Returns 0 if a stream has no more data to read.
76 | /// A buffer to store the content.
77 | /// The size of the content that is expected to read.
78 | virtual vint Read(void* _buffer, vint _size)=0;
79 | /// Write to the current position and step forward. It will crash if the stream is unwritable or unavailable.
80 | /// Returns the actual size of the content that has written. Returns 0 if a stream has not enough space to write.
81 | /// A buffer storing the content to write.
82 | /// The size of the content that is expected to write.
83 | virtual vint Write(void* _buffer, vint _size)=0;
84 | /// Read from the current position without stepping forward. It will crash if the stream is unpeekable or unavailable.
85 | /// Returns the actual size of the content that is read. Returns 0 if a stream has no more data to read.
86 | /// A buffer to store the content.
87 | /// The size of the content that is expected to read.
88 | virtual vint Peek(void* _buffer, vint _size)=0;
89 | };
90 | }
91 | }
92 |
93 | #endif
--------------------------------------------------------------------------------
/Source/Stream/MemoryStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include
7 | #include "MemoryStream.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | MemoryStream
15 | ***********************************************************************/
16 |
17 | void MemoryStream::PrepareSpace(vint totalSpace)
18 | {
19 | if(totalSpace>capacity)
20 | {
21 | totalSpace=(totalSpace/block+1)*block;
22 | char* newBuffer=new char[totalSpace];
23 | if(buffer)
24 | {
25 | memcpy(newBuffer, buffer, size);
26 | delete[] buffer;
27 | }
28 | buffer=newBuffer;
29 | capacity=totalSpace;
30 | }
31 | }
32 |
33 | MemoryStream::MemoryStream(vint _block)
34 | :block(_block)
35 | ,buffer(0)
36 | ,size(0)
37 | ,position(0)
38 | ,capacity(0)
39 | {
40 | if(block<=0)
41 | {
42 | block=65536;
43 | }
44 | }
45 |
46 | MemoryStream::~MemoryStream()
47 | {
48 | Close();
49 | }
50 |
51 | bool MemoryStream::CanRead()const
52 | {
53 | return block!=0;
54 | }
55 |
56 | bool MemoryStream::CanWrite()const
57 | {
58 | return block!=0;
59 | }
60 |
61 | bool MemoryStream::CanSeek()const
62 | {
63 | return block!=0;
64 | }
65 |
66 | bool MemoryStream::CanPeek()const
67 | {
68 | return block!=0;
69 | }
70 |
71 | bool MemoryStream::IsLimited()const
72 | {
73 | return false;
74 | }
75 |
76 | bool MemoryStream::IsAvailable()const
77 | {
78 | return block!=0;
79 | }
80 |
81 | void MemoryStream::Close()
82 | {
83 | if(buffer)
84 | {
85 | delete[] buffer;
86 | }
87 | block=0;
88 | buffer=0;
89 | size=-1;
90 | position=-1;
91 | capacity=0;
92 | }
93 |
94 | pos_t MemoryStream::Position()const
95 | {
96 | return position;
97 | }
98 |
99 | pos_t MemoryStream::Size()const
100 | {
101 | return size;
102 | }
103 |
104 | void MemoryStream::Seek(pos_t _size)
105 | {
106 | SeekFromBegin(position+_size);
107 | }
108 |
109 | void MemoryStream::SeekFromBegin(pos_t _size)
110 | {
111 | CHECK_ERROR(block!=0, L"MemoryStream::SeekFromBegin(pos_t)#Stream is closed, cannot perform this operation.");
112 | vint expected=(vint)_size;
113 | if(expected<0)
114 | {
115 | position=0;
116 | }
117 | else if(expected>=size)
118 | {
119 | position=size;
120 | }
121 | else
122 | {
123 | position=expected;
124 | }
125 | }
126 |
127 | void MemoryStream::SeekFromEnd(pos_t _size)
128 | {
129 | SeekFromBegin(size-_size);
130 | }
131 |
132 | vint MemoryStream::Read(void* _buffer, vint _size)
133 | {
134 | CHECK_ERROR(block!=0, L"MemoryStream::Read(pos_t)#Stream is closed, cannot perform this operation.");
135 | CHECK_ERROR(_size>=0, L"MemoryStream::Read(void*, vint)#Argument size cannot be negative.");
136 | vint max=size-position;
137 | if(_size>max)
138 | {
139 | _size=max;
140 | }
141 | memmove(_buffer, buffer+position, _size);
142 | position+=_size;
143 | return _size;
144 | }
145 |
146 | vint MemoryStream::Write(void* _buffer, vint _size)
147 | {
148 | CHECK_ERROR(block!=0, L"MemoryStream::Write(pos_t)#Stream is closed, cannot perform this operation.");
149 | CHECK_ERROR(_size>=0, L"MemoryStream::Write(void*, vint)#Argument size cannot be negative.");
150 | PrepareSpace(size+_size);
151 | memmove(buffer+position, _buffer, _size);
152 | position+=_size;
153 | if(size=0, L"MemoryStream::Peek(void*, vint)#Argument size cannot be negative.");
164 | vint max=size-position;
165 | if(_size>max)
166 | {
167 | _size=max;
168 | }
169 | memmove(_buffer, buffer+position, _size);
170 | return _size;
171 | }
172 |
173 | void* MemoryStream::GetInternalBuffer()
174 | {
175 | return buffer;
176 | }
177 | }
178 | }
--------------------------------------------------------------------------------
/Source/Stream/MemoryStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_MEMORYSTREAM
7 | #define VCZH_STREAM_MEMORYSTREAM
8 |
9 | #include "Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /// A readable, peekable, writable and seekable stream that creates on a buffer.
16 | class MemoryStream : public Object, public virtual IStream
17 | {
18 | protected:
19 | vint block;
20 | char* buffer;
21 | vint size;
22 | vint position;
23 | vint capacity;
24 |
25 | void PrepareSpace(vint totalSpace);
26 | public:
27 | /// Create a memory stream.
28 | ///
29 | /// Size for each allocation.
30 | /// When the allocated buffer is not big enough for writing,
31 | /// the buffer will be rebuilt with an extension of "_block" in bytes.
32 | ///
33 | MemoryStream(vint _block=65536);
34 | ~MemoryStream();
35 |
36 | bool CanRead()const;
37 | bool CanWrite()const;
38 | bool CanSeek()const;
39 | bool CanPeek()const;
40 | bool IsLimited()const;
41 | bool IsAvailable()const;
42 | void Close();
43 | pos_t Position()const;
44 | pos_t Size()const;
45 | void Seek(pos_t _size);
46 | void SeekFromBegin(pos_t _size);
47 | void SeekFromEnd(pos_t _size);
48 | vint Read(void* _buffer, vint _size);
49 | vint Write(void* _buffer, vint _size);
50 | vint Peek(void* _buffer, vint _size);
51 | void* GetInternalBuffer();
52 | };
53 | }
54 | }
55 |
56 | #endif
--------------------------------------------------------------------------------
/Source/Stream/MemoryWrapperStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include
7 | #include "MemoryWrapperStream.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | MemoryWrapperStream
15 | ***********************************************************************/
16 |
17 | MemoryWrapperStream::MemoryWrapperStream(void* _buffer, vint _size)
18 | :buffer((char*)_buffer)
19 | ,size(_size)
20 | ,position(0)
21 | {
22 | if(size<=0)
23 | {
24 | buffer=0;
25 | size=0;
26 | }
27 | }
28 |
29 | MemoryWrapperStream::~MemoryWrapperStream()
30 | {
31 | }
32 |
33 | bool MemoryWrapperStream::CanRead()const
34 | {
35 | return buffer!=0;
36 | }
37 |
38 | bool MemoryWrapperStream::CanWrite()const
39 | {
40 | return buffer!=0;
41 | }
42 |
43 | bool MemoryWrapperStream::CanSeek()const
44 | {
45 | return buffer!=0;
46 | }
47 |
48 | bool MemoryWrapperStream::CanPeek()const
49 | {
50 | return buffer!=0;
51 | }
52 |
53 | bool MemoryWrapperStream::IsLimited()const
54 | {
55 | return buffer!=0;
56 | }
57 |
58 | bool MemoryWrapperStream::IsAvailable()const
59 | {
60 | return buffer!=0;
61 | }
62 |
63 | void MemoryWrapperStream::Close()
64 | {
65 | buffer=0;
66 | size=-1;
67 | position=-1;
68 | }
69 |
70 | pos_t MemoryWrapperStream::Position()const
71 | {
72 | return position;
73 | }
74 |
75 | pos_t MemoryWrapperStream::Size()const
76 | {
77 | return size;
78 | }
79 |
80 | void MemoryWrapperStream::Seek(pos_t _size)
81 | {
82 | SeekFromBegin(position+_size);
83 | }
84 |
85 | void MemoryWrapperStream::SeekFromBegin(pos_t _size)
86 | {
87 | CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::SeekFromBegin(pos_t)#Stream is closed, cannot perform this operation.");
88 | vint expected=(vint)_size;
89 | if(expected<0)
90 | {
91 | position=0;
92 | }
93 | else if(expected>=size)
94 | {
95 | position=size;
96 | }
97 | else
98 | {
99 | position=expected;
100 | }
101 | }
102 |
103 | void MemoryWrapperStream::SeekFromEnd(pos_t _size)
104 | {
105 | SeekFromBegin(size-_size);
106 | }
107 |
108 | vint MemoryWrapperStream::Read(void* _buffer, vint _size)
109 | {
110 | CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Read(pos_t)#Stream is closed, cannot perform this operation.");
111 | CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Read(void*, vint)#Argument size cannot be negative.");
112 | vint max=size-position;
113 | if(_size>max)
114 | {
115 | _size=max;
116 | }
117 | memmove(_buffer, buffer+position, _size);
118 | position+=_size;
119 | return _size;
120 | }
121 |
122 | vint MemoryWrapperStream::Write(void* _buffer, vint _size)
123 | {
124 | CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Write(pos_t)#Stream is closed, cannot perform this operation.");
125 | CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Write(void*, vint)#Argument size cannot be negative.");
126 | vint max=size-position;
127 | if(_size>max)
128 | {
129 | _size=max;
130 | }
131 | memmove(buffer+position, _buffer, _size);
132 | position+=_size;
133 | return _size;
134 | }
135 |
136 | vint MemoryWrapperStream::Peek(void* _buffer, vint _size)
137 | {
138 | CHECK_ERROR(buffer!=0, L"MemoryWrapperStream::Peek(pos_t)#Stream is closed, cannot perform this operation.");
139 | CHECK_ERROR(_size>=0, L"MemoryWrapperStream::Peek(void*, vint)#Argument size cannot be negative.");
140 | vint max=size-position;
141 | if(_size>max)
142 | {
143 | _size=max;
144 | }
145 | memmove(_buffer, buffer+position, _size);
146 | return _size;
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/Source/Stream/MemoryWrapperStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_MEMORYWRAPPERSTREAM
7 | #define VCZH_STREAM_MEMORYWRAPPERSTREAM
8 |
9 | #include "Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | /// A readable, peekable, writable, seekable and finite stream that creates on a buffer.
16 | class MemoryWrapperStream : public Object, public virtual IStream
17 | {
18 | protected:
19 | char* buffer;
20 | vint size;
21 | vint position;
22 | public:
23 | /// Create a memory wrapper stream.
24 | /// The buffer to operate.
25 | /// Size of the buffer in bytes.
26 | MemoryWrapperStream(void* _buffer, vint _size);
27 | ~MemoryWrapperStream();
28 |
29 | bool CanRead()const;
30 | bool CanWrite()const;
31 | bool CanSeek()const;
32 | bool CanPeek()const;
33 | bool IsLimited()const;
34 | bool IsAvailable()const;
35 | void Close();
36 | pos_t Position()const;
37 | pos_t Size()const;
38 | void Seek(pos_t _size);
39 | void SeekFromBegin(pos_t _size);
40 | void SeekFromEnd(pos_t _size);
41 | vint Read(void* _buffer, vint _size);
42 | vint Write(void* _buffer, vint _size);
43 | vint Peek(void* _buffer, vint _size);
44 | };
45 | }
46 | }
47 |
48 | #endif
--------------------------------------------------------------------------------
/Source/Stream/RecorderStream.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include
7 | #include "RecorderStream.h"
8 |
9 | namespace vl
10 | {
11 | namespace stream
12 | {
13 | /***********************************************************************
14 | RecorderStream
15 | ***********************************************************************/
16 |
17 | RecorderStream::RecorderStream(IStream& _in, IStream& _out)
18 | :in(&_in)
19 | , out(&_out)
20 | {
21 | }
22 |
23 | RecorderStream::~RecorderStream()
24 | {
25 | }
26 |
27 | bool RecorderStream::CanRead()const
28 | {
29 | return IsAvailable() && in->CanRead();
30 | }
31 |
32 | bool RecorderStream::CanWrite()const
33 | {
34 | return false;
35 | }
36 |
37 | bool RecorderStream::CanSeek()const
38 | {
39 | return false;
40 | }
41 |
42 | bool RecorderStream::CanPeek()const
43 | {
44 | return false;
45 | }
46 |
47 | bool RecorderStream::IsLimited()const
48 | {
49 | return IsAvailable() && in->IsLimited();
50 | }
51 |
52 | bool RecorderStream::IsAvailable()const
53 | {
54 | return in != 0 && out != 0 && in->IsAvailable() && out->IsAvailable();
55 | }
56 |
57 | void RecorderStream::Close()
58 | {
59 | in = nullptr;
60 | out = nullptr;
61 | }
62 |
63 | pos_t RecorderStream::Position()const
64 | {
65 | return IsAvailable() ? in->Position() : -1;
66 | }
67 |
68 | pos_t RecorderStream::Size()const
69 | {
70 | return IsAvailable() ? in->Size() : -1;
71 | }
72 |
73 | void RecorderStream::Seek(pos_t _size)
74 | {
75 | CHECK_FAIL(L"RecorderStream::Seek(pos_t)#Operation not supported.");
76 | }
77 |
78 | void RecorderStream::SeekFromBegin(pos_t _size)
79 | {
80 | CHECK_FAIL(L"RecorderStream::SeekFromBegin(pos_t)#Operation not supported.");
81 | }
82 |
83 | void RecorderStream::SeekFromEnd(pos_t _size)
84 | {
85 | CHECK_FAIL(L"RecorderStream::SeekFromEnd(pos_t)#Operation not supported.");
86 | }
87 |
88 | vint RecorderStream::Read(void* _buffer, vint _size)
89 | {
90 | _size = in->Read(_buffer, _size);
91 | vint written = out->Write(_buffer, _size);
92 | CHECK_ERROR(written == _size, L"RecorderStream::Read(void*, vint)#Failed to copy data to the output stream.");
93 | return _size;
94 | }
95 |
96 | vint RecorderStream::Write(void* _buffer, vint _size)
97 | {
98 | CHECK_FAIL(L"RecorderStream::Write(void*, vint)#Operation not supported.");
99 | }
100 |
101 | vint RecorderStream::Peek(void* _buffer, vint _size)
102 | {
103 | CHECK_FAIL(L"RecorderStream::Peek(void*, vint)#Operation not supported.");
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/Source/Stream/RecorderStream.h:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #ifndef VCZH_STREAM_RECORDERSTREAM
7 | #define VCZH_STREAM_RECORDERSTREAM
8 |
9 | #include "Interfaces.h"
10 |
11 | namespace vl
12 | {
13 | namespace stream
14 | {
15 | ///
16 | /// A readable stream that, reads from one stream, and copy everything that is read to another stream.
17 | /// The stream is unavailable if one of the input stream or the output stream is unavailable.
18 | /// The stream is readable, and potentially finite.
19 | ///
20 | ///
21 | /// When reading happens, the recorder stream will only performance one write attempt to the output stream.
22 | ///
23 | class RecorderStream : public Object, public virtual IStream
24 | {
25 | protected:
26 | IStream* in;
27 | IStream* out;
28 | public:
29 | /// Create a recorder stream.
30 | ///
31 | /// The input stream.
32 | /// This recorder stream is readable only when the input stream is readable
33 | /// This recorder stream is finite only when the input stream is finite
34 | ///
35 | ///
36 | /// The output stream.
37 | ///
38 | RecorderStream(IStream& _in, IStream& _out);
39 | ~RecorderStream();
40 |
41 | bool CanRead()const;
42 | bool CanWrite()const;
43 | bool CanSeek()const;
44 | bool CanPeek()const;
45 | bool IsLimited()const;
46 | bool IsAvailable()const;
47 | void Close();
48 | pos_t Position()const;
49 | pos_t Size()const;
50 | void Seek(pos_t _size);
51 | void SeekFromBegin(pos_t _size);
52 | void SeekFromEnd(pos_t _size);
53 | vint Read(void* _buffer, vint _size);
54 | vint Write(void* _buffer, vint _size);
55 | vint Peek(void* _buffer, vint _size);
56 | };
57 | }
58 | }
59 |
60 | #endif
--------------------------------------------------------------------------------
/Source/Threading.cpp:
--------------------------------------------------------------------------------
1 | /***********************************************************************
2 | Author: Zihan Chen (vczh)
3 | Licensed under https://github.com/vczh-libraries/License
4 | ***********************************************************************/
5 |
6 | #include "Threading.h"
7 |
8 | #if defined VCZH_ARM
9 | #include
10 | #elif defined VCZH_MSVC || defined VCZH_GCC
11 | #include
12 | #endif
13 |
14 | namespace vl
15 | {
16 |
17 | /***********************************************************************
18 | SpinLock
19 | ***********************************************************************/
20 |
21 | SpinLock::Scope::Scope(SpinLock& _spinLock)
22 | :spinLock(&_spinLock)
23 | {
24 | spinLock->Enter();
25 | }
26 |
27 | SpinLock::Scope::~Scope()
28 | {
29 | spinLock->Leave();
30 | }
31 |
32 | bool SpinLock::TryEnter()
33 | {
34 | return token.exchange(1) == 0;
35 | }
36 |
37 | void SpinLock::Enter()
38 | {
39 | vint expected = 0;
40 | while (!token.compare_exchange_strong(expected, 1))
41 | {
42 | while (token != 0)
43 | {
44 | #ifdef VCZH_ARM
45 | __yield();
46 | #else
47 | _mm_pause();
48 | #endif
49 | }
50 | }
51 | }
52 |
53 | void SpinLock::Leave()
54 | {
55 | token.exchange(0);
56 | }
57 |
58 | /***********************************************************************
59 | ThreadLocalStorage
60 | ***********************************************************************/
61 |
62 | void ThreadLocalStorage::Clear()
63 | {
64 | CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Clear()#Cannot access a disposed ThreadLocalStorage.");
65 | if(destructor)
66 | {
67 | if (auto data = Get())
68 | {
69 | destructor(data);
70 | }
71 | }
72 | Set(nullptr);
73 | }
74 |
75 | void ThreadLocalStorage::Dispose()
76 | {
77 | CHECK_ERROR(!disposed, L"vl::ThreadLocalStorage::Dispose()#Cannot access a disposed ThreadLocalStorage.");
78 | Clear();
79 | disposed = true;
80 | }
81 |
82 | struct TlsStorageLink
83 | {
84 | ThreadLocalStorage* storage = nullptr;
85 | TlsStorageLink* next = nullptr;
86 | };
87 |
88 | volatile bool tlsFixed = false;
89 | TlsStorageLink* tlsHead = nullptr;
90 | TlsStorageLink** tlsTail = &tlsHead;
91 |
92 | void ThreadLocalStorage::PushStorage(ThreadLocalStorage* storage)
93 | {
94 | CHECK_ERROR(!tlsFixed, L"vl::ThreadLocalStorage::PushStorage(ThreadLocalStorage*)#Cannot create new ThreadLocalStorage instance after calling ThreadLocalStorage::FixStorages().");
95 | auto link = new TlsStorageLink;
96 | link->storage = storage;
97 | *tlsTail = link;
98 | tlsTail = &link->next;
99 | }
100 |
101 | void ThreadLocalStorage::FixStorages()
102 | {
103 | tlsFixed = true;
104 | }
105 |
106 | void ThreadLocalStorage::ClearStorages()
107 | {
108 | FixStorages();
109 | auto current = tlsHead;
110 | while (current)
111 | {
112 | current->storage->Clear();
113 | current = current->next;
114 | }
115 | }
116 |
117 | void ThreadLocalStorage::DisposeStorages()
118 | {
119 | FixStorages();
120 | auto current = tlsHead;
121 | tlsHead = nullptr;
122 | tlsTail = nullptr;
123 | while (current)
124 | {
125 | current->storage->Dispose();
126 |
127 | auto temp = current;
128 | current = current->next;
129 | delete temp;
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | ## 2.0
4 |
5 | - Extensible `vl::filesystem`.
6 | - Virtual or filter files/folders (even on root, for wasm or unit test).
7 | - `vl::filesystem::OSFileSystem` static class to access file system as `Filepath`, `File` and `Folder`.
8 | - `vl::filesystem::InjectFileSystemImpl(vl::filesystem::IFileSystemImpl*)`, `nullptr` to cancel, a default implementation using `vl::filesystem::OSFileSystem` will take place.
9 | - Need to affect `FileStream`.
10 |
11 | ## Optional
12 |
--------------------------------------------------------------------------------
/Test/Linux/Main.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Import/Vlpp.h"
2 |
3 | using namespace vl;
4 |
5 | WString GetTestResourcePath()
6 | {
7 | return L"../Resources/";
8 | }
9 |
10 | WString GetTestOutputPath()
11 | {
12 | return L"../Output/";
13 | }
14 |
15 | int main(int argc, char* argv[])
16 | {
17 | vint result = unittest::UnitTest::RunAndDisposeTests(argc, argv);
18 | FinalizeGlobalStorage();
19 | return result;
20 | }
21 |
--------------------------------------------------------------------------------
/Test/Linux/vmake:
--------------------------------------------------------------------------------
1 | <#
2 | CPP_TARGET=./Bin/UnitTest
3 | CPP_VCXPROJ=../UnitTest/UnitTest/UnitTest.vcxproj
4 | CPP_REMOVES=(
5 | "../../Import/Vlpp.Windows.cpp"
6 | "../../Source/FileSystem.Windows.cpp"
7 | "../../Source/HttpUtility.Windows.cpp"
8 | "../../Source/Locale.Windows.cpp"
9 | "../../Source/Threading.Windows.cpp"
10 | "../../Source/Encoding/CharFormat/CharFormat.Windows.cpp"
11 | "../Source/TestLocale.cpp"
12 | "../UnitTest/UnitTest/Main.cpp"
13 | )
14 | CPP_ADDS=("Main.cpp")
15 | FOLDERS=("../Output")
16 | TARGETS=("${CPP_TARGET}")
17 | CPP_COMPILE_OPTIONS="-I ../../Import"
18 | #>
19 | <#@ include "${VCPROOT}/vl/vmake-cpp" #>
20 |
--------------------------------------------------------------------------------
/Test/Source/TestLocale.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Locale.h"
2 | #include "../../Source/Stream/Accessor.h"
3 | #include "../../Source/Stream/EncodingStream.h"
4 | #include "../../Source/Encoding/CharFormat/CharFormat.h"
5 | #include "../../Source/Stream/FileStream.h"
6 |
7 | using namespace vl;
8 | using namespace vl::collections;
9 | using namespace vl::stream;
10 |
11 | extern WString GetTestOutputPath();
12 |
13 | TEST_FILE
14 | {
15 | TEST_CASE(L"Locale comparisong")
16 | {
17 | {
18 | Locale a, b;
19 | TEST_ASSERT((a == b) == true);
20 | TEST_ASSERT((a != b) == false);
21 | TEST_ASSERT((a < b) == false);
22 | TEST_ASSERT((a <= b) == true);
23 | TEST_ASSERT((a > b) == false);
24 | TEST_ASSERT((a >= b) == true);
25 | }
26 | {
27 | Locale a(L"a"), b(L"b");
28 | TEST_ASSERT((a == b) == false);
29 | TEST_ASSERT((a != b) == true);
30 | TEST_ASSERT((a < b) == true);
31 | TEST_ASSERT((a <= b) == true);
32 | TEST_ASSERT((a > b) == false);
33 | TEST_ASSERT((a >= b) == false);
34 | }
35 | });
36 |
37 | TEST_CASE(L"Print locale awared data")
38 | {
39 | DateTime dt = DateTime::LocalTime();
40 |
41 | FileStream fileStream(GetTestOutputPath() + L"Locale.txt", FileStream::WriteOnly);
42 | BomEncoder encoder(BomEncoder::Utf16);
43 | EncoderStream encoderStream(fileStream, encoder);
44 | StreamWriter writer(encoderStream);
45 |
46 | writer.WriteLine(L"Invariant locale: " + Locale::Invariant().GetName());
47 | writer.WriteLine(L"User default locale: " + Locale::UserDefault().GetName());
48 | writer.WriteLine(L"System default locale: " + Locale::SystemDefault().GetName());
49 |
50 | writer.WriteLine(L"========================================");
51 | {
52 | Locale locale = Locale::UserDefault();
53 | WString input = L"abcdeABCDEabcdeABCDE战斗戰鬥あいうえおアイウエオアイウエオ";
54 | writer.WriteLine(L"[Normal] => " + input);
55 | writer.WriteLine(L"[ToFullWidth] => " + locale.ToFullWidth(input));
56 | writer.WriteLine(L"[ToHalfWidth] => " + locale.ToHalfWidth(input));
57 | writer.WriteLine(L"[ToHiragana] => " + locale.ToHiragana(input));
58 | writer.WriteLine(L"[ToKatagana] => " + locale.ToKatagana(input));
59 | writer.WriteLine(L"[ToLower] => " + locale.ToLower(input));
60 | writer.WriteLine(L"[ToUpper] => " + locale.ToUpper(input));
61 | writer.WriteLine(L"[ToLinguisticLower] => " + locale.ToLinguisticLower(input));
62 | writer.WriteLine(L"[ToLinguisticUpper] => " + locale.ToLinguisticUpper(input));
63 | writer.WriteLine(L"[ToSimplifiedChinese] => " + locale.ToSimplifiedChinese(input));
64 | writer.WriteLine(L"[ToTraditionalChinese] => " + locale.ToTraditionalChinese(input));
65 | writer.WriteLine(L"[ToTileCase] => " + locale.ToTileCase(input));
66 | }
67 |
68 | List locales;
69 | Locale::Enumerate(locales);
70 | locales.Insert(0, Locale::Invariant());
71 | for (auto locale : locales)
72 | {
73 | writer.WriteLine(L"========================================");
74 | writer.WriteLine(L"Locale: " + locale.GetName());
75 | writer.WriteLine(L"[Number 0] => " + locale.FormatNumber(L"0"));
76 | writer.WriteLine(L"[Number 1] => " + locale.FormatNumber(L"1"));
77 | writer.WriteLine(L"[Number -1] => " + locale.FormatNumber(L"-1"));
78 | writer.WriteLine(L"[Number 100.2] => " + locale.FormatNumber(L"100.2"));
79 | writer.WriteLine(L"[Number -100.2] => " + locale.FormatNumber(L"-100.2"));
80 | writer.WriteLine(L"[Currency 0] => " + locale.FormatCurrency(L"0"));
81 | writer.WriteLine(L"[Currency 1] => " + locale.FormatCurrency(L"1"));
82 | writer.WriteLine(L"[Currency -1] => " + locale.FormatCurrency(L"-1"));
83 | writer.WriteLine(L"[Currency 100.2] => " + locale.FormatCurrency(L"100.2"));
84 | writer.WriteLine(L"[Currency -100.2] => " + locale.FormatCurrency(L"-100.2"));
85 | {
86 | writer.WriteString(L"[ShortDayOfWeek]");
87 | for (vint i = 0; i <= 6; i++)
88 | {
89 | writer.WriteString(L" " + locale.GetShortDayOfWeekName(i));
90 | }
91 | writer.WriteLine(L"");
92 |
93 | writer.WriteString(L"[LongDayOfWeek]");
94 | for (vint i = 0; i <= 6; i++)
95 | {
96 | writer.WriteString(L" " + locale.GetLongDayOfWeekName(i));
97 | }
98 | writer.WriteLine(L"");
99 |
100 | writer.WriteString(L"[ShortMonth]");
101 | for (vint i = 1; i <= 12; i++)
102 | {
103 | writer.WriteString(L" " + locale.GetShortMonthName(i));
104 | }
105 | writer.WriteLine(L"");
106 |
107 | writer.WriteString(L"[LongMonth]");
108 | for (vint i = 1; i <= 12; i++)
109 | {
110 | writer.WriteString(L" " + locale.GetLongMonthName(i));
111 | }
112 | writer.WriteLine(L"");
113 | }
114 | {
115 | List formats;
116 | locale.GetLongDateFormats(formats);
117 | for (auto format : formats)
118 | {
119 | writer.WriteLine(L"[LongDate]" + format + L" => " + locale.FormatDate(format, dt));
120 | }
121 | }
122 | {
123 | List formats;
124 | locale.GetShortDateFormats(formats);
125 | for (auto format : formats)
126 | {
127 | writer.WriteLine(L"[ShortDate]" + format + L" => " + locale.FormatDate(format, dt));
128 | }
129 | }
130 | {
131 | List formats;
132 | locale.GetYearMonthDateFormats(formats);
133 | for (auto format : formats)
134 | {
135 | writer.WriteLine(L"[YearMonth]" + format + L" => " + locale.FormatDate(format, dt));
136 | }
137 | }
138 | {
139 | List formats;
140 | locale.GetLongTimeFormats(formats);
141 | for (auto format : formats)
142 | {
143 | writer.WriteLine(L"[LongTime]" + format + L" => " + locale.FormatTime(format, dt));
144 | }
145 | }
146 | {
147 | List formats;
148 | locale.GetShortTimeFormats(formats);
149 | for (auto format : formats)
150 | {
151 | writer.WriteLine(L"[ShortTime]" + format + L" => " + locale.FormatTime(format, dt));
152 | }
153 | }
154 | }
155 | });
156 | }
--------------------------------------------------------------------------------
/Test/Source/TestLocaleString.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Locale.h"
2 | #include "../../Source/Stream/Accessor.h"
3 | #include "../../Source/Encoding/CharFormat/CharFormat.h"
4 | #include "../../Source/Stream/FileStream.h"
5 |
6 | using namespace vl;
7 | using namespace vl::collections;
8 | using namespace vl::stream;
9 |
10 | extern WString GetTestOutputPath();
11 |
12 | TEST_FILE
13 | {
14 | TEST_CASE(L"Test locale awared date/time format")
15 | {
16 | DateTime dt = DateTime::FromDateTime(2000, 1, 2, 13, 2, 3);
17 | auto df = L"yyyy,MM,MMM,MMMM,dd,ddd,dddd";
18 | auto ds = L"2000,01,Jan,January,02,Sun,Sunday";
19 | auto tf = L"hh,HH,mm,ss,tt";
20 | auto ts = L"01,13,02,03,PM";
21 | TEST_ASSERT(INVLOC.FormatDate(df, dt) == ds);
22 | TEST_ASSERT(INVLOC.FormatTime(tf, dt) == ts);
23 | });
24 |
25 | TEST_CASE(L"Test locale awared string comparison")
26 | {
27 | TEST_ASSERT(INVLOC.Compare(L"abc", L"abc", Locale::Normalization::None) == 0);
28 | TEST_ASSERT(INVLOC.Compare(L"abc", L"ABC", Locale::Normalization::None) != 0);
29 | TEST_ASSERT(INVLOC.Compare(L"abc", L"abc", Locale::Normalization::IgnoreCase) == 0);
30 | TEST_ASSERT(INVLOC.Compare(L"abc", L"ABC", Locale::Normalization::IgnoreCase) == 0);
31 |
32 | TEST_ASSERT(INVLOC.CompareOrdinal(L"abc", L"abc") == 0);
33 | TEST_ASSERT(INVLOC.CompareOrdinal(L"abc", L"ABC") != 0);
34 | TEST_ASSERT(INVLOC.CompareOrdinalIgnoreCase(L"abc", L"abc") == 0);
35 | TEST_ASSERT(INVLOC.CompareOrdinalIgnoreCase(L"abc", L"ABC") == 0);
36 | });
37 |
38 | TEST_CASE(L"Test locale awared string searching")
39 | {
40 | TEST_ASSERT(INVLOC.FindFirst(L"abc", L"vczh", Locale::Normalization::None).key == -1);
41 | TEST_ASSERT(INVLOC.FindFirst(L"abcvczhdefvczhghi", L"vczh", Locale::Normalization::None).key == 3);
42 | TEST_ASSERT(INVLOC.FindFirst(L"abc", L"Vczh", Locale::Normalization::None).key == -1);
43 | TEST_ASSERT(INVLOC.FindFirst(L"abcvczhdefvczhghi", L"Vczh", Locale::Normalization::None).key == -1);
44 | TEST_ASSERT(INVLOC.FindFirst(L"abc", L"vczh", Locale::Normalization::IgnoreCase).key == -1);
45 | TEST_ASSERT(INVLOC.FindFirst(L"abcvczhdefvczhghi", L"vczh", Locale::Normalization::IgnoreCase).key == 3);
46 | TEST_ASSERT(INVLOC.FindFirst(L"abc", L"Vczh", Locale::Normalization::IgnoreCase).key == -1);
47 | TEST_ASSERT(INVLOC.FindFirst(L"abcvczhdefvczhghi", L"Vczh", Locale::Normalization::IgnoreCase).key == 3);
48 |
49 | TEST_ASSERT(INVLOC.FindLast(L"abc", L"vczh", Locale::Normalization::None).key == -1);
50 | TEST_ASSERT(INVLOC.FindLast(L"abcvczhdefvczhghi", L"vczh", Locale::Normalization::None).key == 10);
51 | TEST_ASSERT(INVLOC.FindLast(L"abc", L"Vczh", Locale::Normalization::None).key == -1);
52 | TEST_ASSERT(INVLOC.FindLast(L"abcvczhdefvczhghi", L"Vczh", Locale::Normalization::None).key == -1);
53 | TEST_ASSERT(INVLOC.FindLast(L"abc", L"vczh", Locale::Normalization::IgnoreCase).key == -1);
54 | TEST_ASSERT(INVLOC.FindLast(L"abcvczhdefvczhghi", L"vczh", Locale::Normalization::IgnoreCase).key == 10);
55 | TEST_ASSERT(INVLOC.FindLast(L"abc", L"Vczh", Locale::Normalization::IgnoreCase).key == -1);
56 | TEST_ASSERT(INVLOC.FindLast(L"abcvczhdefvczhghi", L"Vczh", Locale::Normalization::IgnoreCase).key == 10);
57 |
58 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"a", Locale::Normalization::None) == true);
59 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"A", Locale::Normalization::None) == false);
60 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"c", Locale::Normalization::None) == false);
61 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"C", Locale::Normalization::None) == false);
62 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"a", Locale::Normalization::IgnoreCase) == true);
63 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"A", Locale::Normalization::IgnoreCase) == true);
64 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"c", Locale::Normalization::IgnoreCase) == false);
65 | TEST_ASSERT(INVLOC.StartsWith(L"abc", L"C", Locale::Normalization::IgnoreCase) == false);
66 |
67 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"a", Locale::Normalization::None) == false);
68 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"A", Locale::Normalization::None) == false);
69 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"c", Locale::Normalization::None) == true);
70 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"C", Locale::Normalization::None) == false);
71 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"a", Locale::Normalization::IgnoreCase) == false);
72 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"A", Locale::Normalization::IgnoreCase) == false);
73 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"c", Locale::Normalization::IgnoreCase) == true);
74 | TEST_ASSERT(INVLOC.EndsWith(L"abc", L"C", Locale::Normalization::IgnoreCase) == true);
75 | });
76 |
77 | TEST_CASE(L"Test locale awared string casing")
78 | {
79 | TEST_ASSERT(INVLOC.ToUpper(L"abcABC") == L"ABCABC");
80 | TEST_ASSERT(INVLOC.ToLower(L"abcABC") == L"abcabc");
81 | TEST_ASSERT(INVLOC.ToLinguisticUpper(L"abcABC") == L"ABCABC");
82 | TEST_ASSERT(INVLOC.ToLinguisticLower(L"abcABC") == L"abcabc");
83 | });
84 | }
--------------------------------------------------------------------------------
/Test/Source/TestSerialization.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Stream/Serialization.h"
2 | #include "../../Source/Stream/MemoryStream.h"
3 |
4 | using namespace vl;
5 | using namespace vl::stream;
6 | using namespace vl::collections;
7 |
8 | namespace TestSerialization_TestObjects
9 | {
10 | enum Seasons1
11 | {
12 | Spring,
13 | Summer,
14 | Autumn,
15 | Winter,
16 | };
17 |
18 | enum class Seasons2
19 | {
20 | Spring,
21 | Summer,
22 | Autumn,
23 | Winter,
24 | };
25 |
26 | struct Strings
27 | {
28 | WString sa;
29 | U8String sb;
30 | U16String sc;
31 | U32String sd;
32 | };
33 | }
34 | using namespace TestSerialization_TestObjects;
35 |
36 | namespace vl
37 | {
38 | namespace stream
39 | {
40 | namespace internal
41 | {
42 | BEGIN_SERIALIZATION(Strings)
43 | SERIALIZE(sa)
44 | SERIALIZE(sb)
45 | SERIALIZE(sc)
46 | SERIALIZE(sd)
47 | END_SERIALIZATION
48 | }
49 | }
50 | }
51 |
52 | TEST_FILE
53 | {
54 | TEST_CASE(L"Serialize PODs")
55 | {
56 | MemoryStream memoryStream;
57 | vint8_t a1 = 2, a2;
58 | vuint8_t b1 = 3, b2;
59 | vint16_t c1 = 5, c2;
60 | vuint16_t d1 = 7, d2;
61 | vint32_t e1 = 11, e2;
62 | vuint32_t f1 = 13, f2;
63 | vint64_t g1 = 17, g2;
64 | vuint64_t h1 = 19, h2;
65 | float i1 = 23, i2;
66 | double j1 = 27, j2;
67 | char cha1 = 'A', cha2;
68 | wchar_t chb1 = L'B', chb2;
69 | char8_t chc1 = u8'C', chc2;
70 | char16_t chd1 = u'D', chd2;
71 | char32_t che1 = U'E', che2;
72 | bool ba1 = true, ba2;
73 | bool bb1 = false, bb2;
74 | {
75 | internal::ContextFreeWriter writer(memoryStream);
76 | writer << a1 << b1 << c1 << d1 << e1 << f1 << g1 << h1 << i1 << j1;
77 | writer << cha1 << chb1 << chc1 << chd1 << che1;
78 | writer << ba1 << bb1;
79 | }
80 | memoryStream.SeekFromBegin(0);
81 | {
82 | internal::ContextFreeReader reader(memoryStream);
83 | reader << a2 << b2 << c2 << d2 << e2 << f2 << g2 << h2 << i2 << j2;
84 | reader << cha2 << chb2 << chc2 << chd2 << che2;
85 | reader << ba2 << bb2;
86 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
87 | }
88 | TEST_ASSERT(a1 == a2);
89 | TEST_ASSERT(b1 == b2);
90 | TEST_ASSERT(c1 == c2);
91 | TEST_ASSERT(d1 == d2);
92 | TEST_ASSERT(e1 == e2);
93 | TEST_ASSERT(f1 == f2);
94 | TEST_ASSERT(g1 == g2);
95 | TEST_ASSERT(h1 == h2);
96 | TEST_ASSERT(i1 == i2);
97 |
98 | TEST_ASSERT(cha1 == cha2);
99 | TEST_ASSERT(chb1 == chb2);
100 | TEST_ASSERT(chc1 == chc2);
101 | TEST_ASSERT(chd1 == chd2);
102 | TEST_ASSERT(che1 == che2);
103 |
104 | TEST_ASSERT(ba1 == ba2);
105 | TEST_ASSERT(bb1 == bb2);
106 | });
107 |
108 | TEST_CASE(L"Serialize Strings")
109 | {
110 | MemoryStream memoryStream;
111 | WString sa1 = L"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才", sa2;
112 | U8String sb1 = u8"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才", sb2;
113 | U16String sc1 = u"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才", sc2;
114 | U32String sd1 = U"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才", sd2;
115 | {
116 | internal::ContextFreeWriter writer(memoryStream);
117 | writer << sa1 << sb1 << sc1 << sd1;
118 | }
119 | memoryStream.SeekFromBegin(0);
120 | {
121 | internal::ContextFreeReader reader(memoryStream);
122 | reader << sa2 << sb2 << sc2 << sd2;
123 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
124 | }
125 | TEST_ASSERT(sa1 == sa2);
126 | TEST_ASSERT(sb1 == sb2);
127 | TEST_ASSERT(sc1 == sc2);
128 | TEST_ASSERT(sd1 == sd2);
129 | });
130 |
131 | TEST_CASE(L"Serialize Enums (1)")
132 | {
133 | MemoryStream memoryStream;
134 |
135 | Seasons1 ea1 = Spring, ea2;
136 | Seasons1 eb1 = Summer, eb2;
137 | Seasons1 ec1 = Autumn, ec2;
138 | Seasons1 ed1 = Winter, ed2;
139 |
140 | Seasons2 eca1 = Seasons2::Spring, eca2;
141 | Seasons2 ecb1 = Seasons2::Summer, ecb2;
142 | Seasons2 ecc1 = Seasons2::Autumn, ecc2;
143 | Seasons2 ecd1 = Seasons2::Winter, ecd2;
144 |
145 | Strings e1, e2;
146 | e1.sa = L"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
147 | e1.sb = u8"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
148 | e1.sc = u"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
149 | e1.sd = U"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
150 |
151 | {
152 | internal::ContextFreeWriter writer(memoryStream);
153 | writer << ea1 << eb1 << ec1 << ed1 << eca1 << ecb1 << ecc1 << ecd1 << e1;
154 | }
155 | memoryStream.SeekFromBegin(0);
156 | {
157 | internal::ContextFreeReader reader(memoryStream);
158 | reader << ea2 << eb2 << ec2 << ed2 << eca2 << ecb2 << ecc2 << ecd2 << e2;
159 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
160 | }
161 |
162 | TEST_ASSERT(ea1 == ea2);
163 | TEST_ASSERT(eb1 == eb2);
164 | TEST_ASSERT(ec1 == ec2);
165 | TEST_ASSERT(ed1 == ed2);
166 |
167 | TEST_ASSERT(eca1 == eca2);
168 | TEST_ASSERT(ecb1 == ecb2);
169 | TEST_ASSERT(ecc1 == ecc2);
170 | TEST_ASSERT(ecd1 == ecd2);
171 |
172 | TEST_ASSERT(e1.sa == e2.sa);
173 | TEST_ASSERT(e1.sb == e2.sb);
174 | TEST_ASSERT(e1.sc == e2.sc);
175 | TEST_ASSERT(e1.sd == e2.sd);
176 | });
177 |
178 | TEST_CASE(L"Serialize Generic Types")
179 | {
180 | MemoryStream memoryStream;
181 | auto a1 = Ptr(new Strings);
182 | Ptr a2;
183 | a1->sa = L"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
184 | a1->sb = u8"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
185 | a1->sc = u"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
186 | a1->sd = U"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
187 | Nullable b1 = *a1.Obj(), b2;
188 | {
189 | internal::ContextFreeWriter writer(memoryStream);
190 | writer << a1 << b1;
191 | }
192 | memoryStream.SeekFromBegin(0);
193 | {
194 | internal::ContextFreeReader reader(memoryStream);
195 | reader << a2 << b2;
196 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
197 | }
198 | TEST_ASSERT(a2);
199 | TEST_ASSERT(b2);
200 | TEST_ASSERT(a1->sa == a2->sa);
201 | TEST_ASSERT(a1->sb == a2->sb);
202 | TEST_ASSERT(a1->sc == a2->sc);
203 | TEST_ASSERT(a1->sd == a2->sd);
204 | TEST_ASSERT(b1.Value().sa == b2.Value().sa);
205 | TEST_ASSERT(b1.Value().sb == b2.Value().sb);
206 | TEST_ASSERT(b1.Value().sc == b2.Value().sc);
207 | TEST_ASSERT(b1.Value().sd == b2.Value().sd);
208 | });
209 |
210 | TEST_CASE(L"Serialize Collections")
211 | {
212 | MemoryStream memoryStream;
213 | List a1, a2;
214 | Array b1(4), b2;
215 | Dictionary c1, c2;
216 | Group d1, d2;
217 |
218 | a1.Add(Seasons2::Spring);
219 | a1.Add(Seasons2::Summer);
220 | a1.Add(Seasons2::Autumn);
221 | a1.Add(Seasons2::Winter);
222 |
223 | b1[0] = Seasons2::Spring;
224 | b1[1] = Seasons2::Summer;
225 | b1[2] = Seasons2::Autumn;
226 | b1[3] = Seasons2::Winter;
227 |
228 | c1.Add(1, Seasons2::Spring);
229 | c1.Add(2, Seasons2::Summer);
230 | c1.Add(3, Seasons2::Autumn);
231 | c1.Add(4, Seasons2::Winter);
232 |
233 | d1.Add(1, Seasons2::Spring);
234 | d1.Add(1, Seasons2::Summer);
235 | d1.Add(2, Seasons2::Autumn);
236 | d1.Add(2, Seasons2::Winter);
237 | d1.Add(3, Seasons2::Spring);
238 | d1.Add(3, Seasons2::Summer);
239 | d1.Add(4, Seasons2::Autumn);
240 | d1.Add(4, Seasons2::Winter);
241 |
242 | {
243 | internal::ContextFreeWriter writer(memoryStream);
244 | writer << a1 << b1 << c1 << d1;
245 | }
246 | memoryStream.SeekFromBegin(0);
247 | {
248 | internal::ContextFreeReader reader(memoryStream);
249 | reader << a2 << b2 << c2 << d2;
250 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
251 | }
252 | TEST_ASSERT(CompareEnumerable(a1, a2) == 0);
253 | TEST_ASSERT(CompareEnumerable(b1, b2) == 0);
254 | TEST_ASSERT(CompareEnumerable(c1, c2) == 0);
255 | TEST_ASSERT(CompareEnumerable(d1, d2) == 0);
256 | });
257 |
258 | TEST_CASE(L"Serialize Others")
259 | {
260 | MemoryStream memoryStream;
261 | wchar_t a1[] = L"𩰪㦲𦰗𠀼 𣂕𣴑𣱳𦁚 Vczh is genius!@我是天才";
262 | wchar_t a2[sizeof(a1) / sizeof(*a1)];
263 | {
264 | internal::ContextFreeWriter writer(memoryStream);
265 | MemoryWrapperStream s(a1, sizeof(a1));
266 | writer << (IStream&)s;
267 | }
268 | memoryStream.SeekFromBegin(0);
269 | {
270 | internal::ContextFreeReader reader(memoryStream);
271 | MemoryWrapperStream s(a2, sizeof(a2));
272 | reader << (IStream&)s;
273 | TEST_ASSERT(memoryStream.Position() == memoryStream.Size());
274 | }
275 | TEST_ASSERT(memcmp(a1, a2, sizeof(a1)) == 0);
276 | });
277 | }
--------------------------------------------------------------------------------
/Test/Source/TestStreamBase64.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Stream/Accessor.h"
2 | #include "../../Source/Stream/EncodingStream.h"
3 | #include "../../Source/Encoding/Base64Encoding.h"
4 |
5 | using namespace vl;
6 | using namespace vl::stream;
7 | using namespace vl::collections;
8 |
9 | namespace TestStreamBase64_TestObjects
10 | {
11 | template
12 | void TestBase64OnBytesPerData(const uint8_t(&bytes)[Bytes], const char8_t(&chars)[Chars])
13 | {
14 | MemoryStream memoryStream;
15 | {
16 | Utf8Base64Encoder encoder;
17 | EncoderStream encoderStream(memoryStream, encoder);
18 | vint written = encoderStream.Write((void*)bytes, Bytes);
19 | TEST_ASSERT(written == Bytes);
20 | }
21 | memoryStream.SeekFromBegin(0);
22 | {
23 | StreamReader_ reader(memoryStream);
24 | auto base64 = reader.ReadToEnd();
25 | TEST_ASSERT(base64 == chars);
26 | }
27 | memoryStream.SeekFromBegin(0);
28 | {
29 | Utf8Base64Decoder decoder;
30 | DecoderStream decoderStream(memoryStream, decoder);
31 | uint8_t buffer[Bytes];
32 | vint read = decoderStream.Read(buffer, Bytes);
33 | TEST_ASSERT(read == Bytes);
34 | TEST_ASSERT(memcmp(buffer, bytes, Bytes) == 0);
35 | TEST_ASSERT(decoderStream.Read(buffer, 1) == 0);
36 | }
37 | }
38 |
39 | template
40 | void TestBase64OnBytesPerByte(const uint8_t(&bytes)[Bytes], const char8_t(&chars)[Chars])
41 | {
42 | MemoryStream memoryStream;
43 | {
44 | Utf8Base64Encoder encoder;
45 | EncoderStream encoderStream(memoryStream, encoder);
46 | for (vint i = 0; i < Bytes; i++)
47 | {
48 | vint written = encoderStream.Write((void*)(bytes + i), 1);
49 | TEST_ASSERT(written == 1);
50 | }
51 | }
52 | memoryStream.SeekFromBegin(0);
53 | {
54 | StreamReader_ reader(memoryStream);
55 | auto base64 = reader.ReadToEnd();
56 | TEST_ASSERT(base64 == chars);
57 | }
58 | memoryStream.SeekFromBegin(0);
59 | {
60 | Utf8Base64Decoder decoder;
61 | DecoderStream decoderStream(memoryStream, decoder);
62 | for (vint i = 0; i < Bytes; i++)
63 | {
64 | uint8_t byte = 0;
65 | vint read = decoderStream.Read(&byte, 1);
66 | TEST_ASSERT(read == 1);
67 | TEST_ASSERT(byte == bytes[i]);
68 | }
69 | {
70 | uint8_t byte;
71 | TEST_ASSERT(decoderStream.Read(&byte, 1) == 0);
72 | }
73 | }
74 | }
75 |
76 | template
77 | void TestBase64OnBytes(const uint8_t(&bytes)[Bytes], const char8_t(&chars)[Chars])
78 | {
79 | TestBase64OnBytesPerData(bytes, chars);
80 | TestBase64OnBytesPerByte(bytes, chars);
81 | }
82 |
83 | template
84 | void TestBase64OnChars(const char8_t(&bytes)[Bytes], const char8_t(&chars)[Chars])
85 | {
86 | TestBase64OnBytes(reinterpret_cast(bytes), chars);
87 | }
88 | }
89 | using namespace TestStreamBase64_TestObjects;
90 |
91 | TEST_FILE
92 | {
93 | TEST_CASE(L"Wikipedia[light w]")
94 | {
95 | TestBase64OnChars(u8"light w", u8"bGlnaHQgdw==");
96 | });
97 | TEST_CASE(L"Wikipedia[light wo]")
98 | {
99 | TestBase64OnChars(u8"light wo", u8"bGlnaHQgd28=");
100 | });
101 | TEST_CASE(L"Wikipedia[light wor]")
102 | {
103 | TestBase64OnChars(u8"light wor", u8"bGlnaHQgd29y");
104 | });
105 | TEST_CASE(L"Wikipedia[light work]")
106 | {
107 | TestBase64OnChars(u8"light work", u8"bGlnaHQgd29yaw==");
108 | });
109 | TEST_CASE(L"Wikipedia[light work.]")
110 | {
111 | TestBase64OnChars(u8"light work.", u8"bGlnaHQgd29yay4=");
112 | });
113 |
114 | TEST_CASE(L"0b01010101")
115 | {
116 | uint8_t bytes[] = { 0b01010101 };
117 | TestBase64OnBytes(bytes, u8"VQ==");
118 | });
119 |
120 | TEST_CASE(L"0b01010101 0b10101010")
121 | {
122 | uint8_t bytes[] = { 0b01010101,0b10101010 };
123 | TestBase64OnBytes(bytes, u8"Vao=");
124 | });
125 |
126 | TEST_CASE(L"0b01010101 0b10101010 0b01011010")
127 | {
128 | uint8_t bytes[] = { 0b01010101,0b10101010,0b01011010 };
129 | TestBase64OnBytes(bytes, u8"Vapa");
130 | });
131 | }
--------------------------------------------------------------------------------
/Test/Source/TestStreamLzw.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Stream/FileStream.h"
2 | #include "../../Source/Stream/MemoryStream.h"
3 | #include "../../Source/Stream/EncodingStream.h"
4 | #include "../../Source/Encoding/LzwEncoding.h"
5 |
6 | using namespace vl;
7 | using namespace vl::stream;
8 | using namespace vl::collections;
9 |
10 | extern WString GetTestOutputPath();
11 |
12 | TEST_FILE
13 | {
14 | /***********************************************************************
15 | Lzw
16 | ***********************************************************************/
17 |
18 | auto TestLzwEncodingWithEncoderAndDecoder = [](const char* input, LzwEncoder& encoder, LzwDecoder& decoder)
19 | {
20 | MemoryStream stream;
21 | vint size = strlen(input);
22 | {
23 | EncoderStream encoderStream(stream, encoder);
24 | vint size = strlen(input);
25 | TEST_ASSERT(encoderStream.Write((void*)input, size) == size);
26 | }
27 | stream.SeekFromBegin(0);
28 | unittest::UnitTest::PrintMessage(L" [" + atow(input) + L"]", unittest::UnitTest::MessageKind::Info);
29 | unittest::UnitTest::PrintMessage(L" " + itow(size) + L" -> " + i64tow(stream.Size()), unittest::UnitTest::MessageKind::Info);
30 | {
31 | Array output(size + 1);
32 | DecoderStream decoderStream(stream, decoder);
33 | TEST_ASSERT(decoderStream.Read(&output[0], size) == size);
34 | TEST_ASSERT(decoderStream.Read(&output[0], size) == 0);
35 | output[size] = 0;
36 | TEST_ASSERT(strcmp(input, &output[0]) == 0);
37 | }
38 | };
39 |
40 | auto TestLzwEncodingDefault = [&](const char* input)
41 | {
42 | LzwEncoder encoder;
43 | LzwDecoder decoder;
44 | TestLzwEncodingWithEncoderAndDecoder(input, encoder, decoder);
45 | };
46 |
47 | auto TestLzwEncodingPrepared = [&](const char* input)
48 | {
49 | bool existingBytes[256] = { 0 };
50 | const char* current = input;
51 | while (vuint8_t c = (vuint8_t)*current++)
52 | {
53 | existingBytes[c] = true;
54 | }
55 |
56 | LzwEncoder encoder(existingBytes);
57 | LzwDecoder decoder(existingBytes);
58 | TestLzwEncodingWithEncoderAndDecoder(input, encoder, decoder);
59 | };
60 |
61 | TEST_CASE(L"Test Lzw Encoding")
62 | {
63 | const char* buffer[] =
64 | {
65 | "",
66 | "0000000000000000000000000000000000000000",
67 | "Vczh is genius!Vczh is genius!Vczh is genius!",
68 | };
69 |
70 | for (vint i = 0; i < sizeof(buffer) / sizeof(*buffer); i++)
71 | {
72 | TestLzwEncodingDefault(buffer[i]);
73 | TestLzwEncodingPrepared(buffer[i]);
74 | }
75 | });
76 |
77 | #if defined VCZH_MSVC && defined NDEBUG
78 |
79 | auto Copy = [](IStream& dst, IStream& src, Array& buffer, vint totalSize)
80 | {
81 | vint BufferSize = buffer.Count();
82 | while (true)
83 | {
84 | vint size = src.Read(&buffer[0], BufferSize);
85 | if (size == 0)
86 | {
87 | break;
88 | }
89 | dst.Write(&buffer[0], size);
90 | }
91 | };
92 |
93 | TEST_CASE(L"Test Lzw Performance")
94 | {
95 | const vint BufferSize = 33554432;
96 | Array buffer(BufferSize);
97 | MemoryStream compressedStream(BufferSize), decompressedStream(BufferSize);
98 | unittest::UnitTest::PrintMessage(L" Reading UnitTest.pdb ...", unittest::UnitTest::MessageKind::Info);
99 | {
100 | FileStream fileStream(GetTestOutputPath() + L"../UnitTest/Release/UnitTest.pdb", FileStream::ReadOnly);
101 | Copy(decompressedStream, fileStream, buffer, (vint)fileStream.Size());
102 | }
103 |
104 | decompressedStream.SeekFromBegin(0);
105 | vint totalSize = (vint)decompressedStream.Size();
106 |
107 | unittest::UnitTest::PrintMessage(L" Compressing UnitTest.pdb ...", unittest::UnitTest::MessageKind::Info);
108 | {
109 | DateTime begin = DateTime::LocalTime();
110 |
111 | LzwEncoder encoder;
112 | EncoderStream encoderStream(compressedStream, encoder);
113 | Copy(encoderStream, decompressedStream, buffer, totalSize);
114 |
115 | DateTime end = DateTime::LocalTime();
116 |
117 | double time = (end.osMilliseconds - begin.osMilliseconds) / 1000.0;
118 | unittest::UnitTest::PrintMessage(L" Time elasped: " + ftow(time) + L" seconds", unittest::UnitTest::MessageKind::Info);
119 | unittest::UnitTest::PrintMessage(L" Performance: " + ftow(totalSize / time / (1 << 20)) + L" MB/s", unittest::UnitTest::MessageKind::Info);
120 | }
121 |
122 | compressedStream.SeekFromBegin(0);
123 | unittest::UnitTest::PrintMessage(L" " + i64tow(totalSize) + L" -> " + i64tow(compressedStream.Size()), unittest::UnitTest::MessageKind::Info);
124 |
125 | unittest::UnitTest::PrintMessage(L" Decompressing UnitTest.pdb ...", unittest::UnitTest::MessageKind::Info);
126 | {
127 | DateTime begin = DateTime::LocalTime();
128 |
129 | LzwDecoder decoder;
130 | DecoderStream decoderStream(compressedStream, decoder);
131 | Copy(decompressedStream, decoderStream, buffer, totalSize);
132 |
133 | DateTime end = DateTime::LocalTime();
134 | double time = (end.osMilliseconds - begin.osMilliseconds) / 1000.0;
135 | unittest::UnitTest::PrintMessage(L" Time elasped: " + ftow(time) + L" seconds", unittest::UnitTest::MessageKind::Info);
136 | unittest::UnitTest::PrintMessage(L" Performance: " + ftow(totalSize / time / (1 << 20)) + L" MB/s", unittest::UnitTest::MessageKind::Info);
137 | }
138 | });
139 | #endif
140 | }
--------------------------------------------------------------------------------
/Test/Source/TestStreamReaderWriter.cpp:
--------------------------------------------------------------------------------
1 | #include "../../Source/Stream/MemoryWrapperStream.h"
2 | #include "../../Source/Stream/Accessor.h"
3 |
4 | using namespace vl;
5 | using namespace vl::stream;
6 |
7 | const vint BUFFER_SIZE = 1024;
8 |
9 | TEST_FILE
10 | {
11 | /***********************************************************************
12 | StringReader
13 | ***********************************************************************/
14 |
15 | TEST_CASE(L"Test StringReader")
16 | {
17 | const wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!\r\n3:Vczh is genius!\r\n4:Vczh is genius!";
18 | StringReader reader(text);
19 |
20 | TEST_ASSERT(reader.ReadChar() == L'1');
21 | TEST_ASSERT(reader.ReadString(5) == L":Vczh");
22 | TEST_ASSERT(reader.ReadLine() == L" is genius!");
23 | TEST_ASSERT(reader.ReadLine() == L"2:Vczh is genius!");
24 | TEST_ASSERT(reader.ReadToEnd() == L"3:Vczh is genius!\r\n4:Vczh is genius!");
25 | });
26 |
27 | TEST_CASE(L"Test StringReader with ending CRLF")
28 | {
29 | const wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!!\r\n3:Vczh is genius!!!\r\n4:Vczh is genius!!!!\r\n";
30 | const wchar_t* lines[] = {L"1:Vczh is genius!", L"2:Vczh is genius!!", L"3:Vczh is genius!!!", L"4:Vczh is genius!!!!",L""};
31 | StringReader reader(text);
32 | vint index = 0;
33 |
34 | while (index < sizeof(lines) / sizeof(*lines))
35 | {
36 | TEST_ASSERT(reader.IsEnd() == false);
37 | TEST_ASSERT(reader.ReadLine() == lines[index++]);
38 | }
39 | TEST_ASSERT(reader.IsEnd() == true);
40 | });
41 |
42 | TEST_CASE(L"Test StringReader without ending CRLF")
43 | {
44 | const wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!!\r\n3:Vczh is genius!!!\r\n4:Vczh is genius!!!!";
45 | const wchar_t* lines[] = {L"1:Vczh is genius!", L"2:Vczh is genius!!", L"3:Vczh is genius!!!", L"4:Vczh is genius!!!!"};
46 | StringReader reader(text);
47 | vint index = 0;
48 |
49 | while (index < sizeof(lines) / sizeof(*lines))
50 | {
51 | TEST_ASSERT(reader.IsEnd() == false);
52 | TEST_ASSERT(reader.ReadLine() == lines[index++]);
53 | }
54 | TEST_ASSERT(reader.IsEnd() == true);
55 | });
56 |
57 | /***********************************************************************
58 | StreamReader
59 | ***********************************************************************/
60 |
61 | TEST_CASE(L"Test StreamReader")
62 | {
63 | wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!\r\n3:Vczh is genius!\r\n4:Vczh is genius!";
64 | MemoryWrapperStream stream(text, sizeof(text) - sizeof(*text));
65 | StreamReader reader(stream);
66 |
67 | TEST_ASSERT(reader.ReadChar() == L'1');
68 | TEST_ASSERT(reader.ReadString(5) == L":Vczh");
69 | TEST_ASSERT(reader.ReadLine() == L" is genius!");
70 | TEST_ASSERT(reader.ReadLine() == L"2:Vczh is genius!");
71 | TEST_ASSERT(reader.ReadToEnd() == L"3:Vczh is genius!\r\n4:Vczh is genius!");
72 | });
73 |
74 | TEST_CASE(L"Test StreamReader with ending CRLF")
75 | {
76 | wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!!\r\n3:Vczh is genius!!!\r\n4:Vczh is genius!!!!\r\n";
77 | const wchar_t* lines[] = {L"1:Vczh is genius!", L"2:Vczh is genius!!", L"3:Vczh is genius!!!", L"4:Vczh is genius!!!!",L""};
78 | MemoryWrapperStream stream(text, sizeof(text) - sizeof(*text));
79 | StreamReader reader(stream);
80 | vint index = 0;
81 |
82 | while (index < sizeof(lines) / sizeof(*lines))
83 | {
84 | TEST_ASSERT(reader.IsEnd() == false);
85 | TEST_ASSERT(reader.ReadLine() == lines[index++]);
86 | }
87 | TEST_ASSERT(reader.IsEnd() == true);
88 | });
89 |
90 | TEST_CASE(L"Test StreamReader without ending CRLF")
91 | {
92 | wchar_t text[] = L"1:Vczh is genius!\r\n2:Vczh is genius!!\r\n3:Vczh is genius!!!\r\n4:Vczh is genius!!!!";
93 | const wchar_t* lines[] = {L"1:Vczh is genius!", L"2:Vczh is genius!!", L"3:Vczh is genius!!!", L"4:Vczh is genius!!!!"};
94 | MemoryWrapperStream stream(text, sizeof(text) - sizeof(*text));
95 | StreamReader reader(stream);
96 | vint index = 0;
97 |
98 | while (index < sizeof(lines) / sizeof(*lines))
99 | {
100 | TEST_ASSERT(reader.IsEnd() == false);
101 | TEST_ASSERT(reader.ReadLine() == lines[index++]);
102 | }
103 | TEST_ASSERT(reader.IsEnd() == true);
104 | });
105 |
106 | /***********************************************************************
107 | StreamWriter
108 | ***********************************************************************/
109 |
110 | TEST_CASE(L"Test StreamWriter")
111 | {
112 | wchar_t text[BUFFER_SIZE] = {0};
113 | MemoryWrapperStream stream(text, sizeof(text) - sizeof(*text));
114 | StreamWriter writer(stream);
115 |
116 | writer.WriteChar(L'1');
117 | writer.WriteChar(L':');
118 | writer.WriteChar(L'V');
119 | writer.WriteChar(L'c');
120 | writer.WriteChar(L'z');
121 | writer.WriteChar(L'h');
122 | writer.WriteChar(L' ');
123 | writer.WriteChar(L'i');
124 | writer.WriteChar(L's');
125 | writer.WriteChar(L' ');
126 | writer.WriteChar(L'g');
127 | writer.WriteChar(L'e');
128 | writer.WriteChar(L'n');
129 | writer.WriteChar(L'i');
130 | writer.WriteChar(L'u');
131 | writer.WriteChar(L's');
132 | writer.WriteChar(L'!');
133 | writer.WriteString(L"");
134 | writer.WriteString(L"\r\n2:Vczh is genius!");
135 | writer.WriteString(WString(L""));
136 | writer.WriteLine(L"");
137 | writer.WriteLine(L"3:Vczh is genius!");
138 | writer.WriteLine(WString(L"4:Vczh is genius!"));
139 |
140 | wchar_t baseline[] = L"1:Vczh is genius!\r\n2:Vczh is genius!\r\n3:Vczh is genius!\r\n4:Vczh is genius!\r\n";
141 | TEST_ASSERT(wcscmp(text, baseline) == 0);
142 | });
143 | }
--------------------------------------------------------------------------------
/Test/UnitTest/UnitTest.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.421
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "UnitTest\UnitTest.vcxproj", "{F17D112F-3D02-4A6B-BB8D-14E7D409774E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Win32 = Debug|Win32
11 | Debug|x64 = Debug|x64
12 | Release|Win32 = Release|Win32
13 | Release|x64 = Release|x64
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Debug|Win32.ActiveCfg = Debug|Win32
17 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Debug|Win32.Build.0 = Debug|Win32
18 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Debug|x64.ActiveCfg = Debug|x64
19 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Debug|x64.Build.0 = Debug|x64
20 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Release|Win32.ActiveCfg = Release|Win32
21 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Release|Win32.Build.0 = Release|Win32
22 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Release|x64.ActiveCfg = Release|x64
23 | {F17D112F-3D02-4A6B-BB8D-14E7D409774E}.Release|x64.Build.0 = Release|x64
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {94AC2324-507B-4586-876F-70E3D182CC9B}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Test/UnitTest/UnitTest/Main.cpp:
--------------------------------------------------------------------------------
1 | #include "../../../Source/FileSystem.h"
2 | #include
3 |
4 | using namespace vl;
5 | using namespace vl::filesystem;
6 |
7 | WString GetExePath()
8 | {
9 | wchar_t buffer[65536];
10 | GetModuleFileName(NULL, buffer, sizeof(buffer)/sizeof(*buffer));
11 | vint pos=-1;
12 | vint index=0;
13 | while(buffer[index])
14 | {
15 | if(buffer[index]==L'\\' || buffer[index]==L'/')
16 | {
17 | pos=index;
18 | }
19 | index++;
20 | }
21 | return WString::CopyFrom(buffer, pos + 1);
22 | }
23 |
24 | WString GetTestOutputPath()
25 | {
26 | #ifdef _WIN64
27 | return GetExePath() + L"../../../Output/";
28 | #else
29 | return GetExePath() + L"../../Output/";
30 | #endif
31 | }
32 |
33 | TEST_FILE
34 | {
35 | TEST_CASE_ASSERT(Folder(GetTestOutputPath()).Exists());
36 | }
37 |
38 | int wmain(int argc , wchar_t* argv[])
39 | {
40 | {
41 | Folder folder(GetTestOutputPath());
42 | if (!folder.Exists())
43 | {
44 | folder.Create(false);
45 | }
46 | }
47 | int result = unittest::UnitTest::RunAndDisposeTests(argc, argv);
48 | FinalizeGlobalStorage();
49 | #ifdef VCZH_CHECK_MEMORY_LEAKS
50 | _CrtDumpMemoryLeaks();
51 | #endif
52 | return result;
53 | }
--------------------------------------------------------------------------------
/Test/UnitTest/UnitTest/UnitTest.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {a0063a3f-fb90-4cc0-8369-26646e7eadf7}
18 |
19 |
20 | {746901f8-38ae-4ba3-9387-83468fc5559b}
21 |
22 |
23 | {f2b75d6f-510b-43a2-a249-bf08fc5e8147}
24 |
25 |
26 | {2b7c4044-fe5b-4999-9e23-0b399a59e43e}
27 |
28 |
29 | {9b8e7dd7-d560-48af-92fe-eae76a82879c}
30 |
31 |
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 | Source Files
47 |
48 |
49 | Common
50 |
51 |
52 | Common
53 |
54 |
55 | Common
56 |
57 |
58 | Common
59 |
60 |
61 | Common
62 |
63 |
64 | Common\Stream
65 |
66 |
67 | Common\Stream
68 |
69 |
70 | Common\Stream
71 |
72 |
73 | Common\Stream
74 |
75 |
76 | Common\Stream
77 |
78 |
79 | Common\Stream
80 |
81 |
82 | Source Files
83 |
84 |
85 | Import
86 |
87 |
88 | Source Files
89 |
90 |
91 | Source Files
92 |
93 |
94 | Source Files
95 |
96 |
97 | Source Files
98 |
99 |
100 | Common\Stream
101 |
102 |
103 | Import
104 |
105 |
106 | Import
107 |
108 |
109 | Common
110 |
111 |
112 | Common
113 |
114 |
115 | Common
116 |
117 |
118 | Common
119 |
120 |
121 | Common
122 |
123 |
124 | Common\Encoding\CharFormat
125 |
126 |
127 | Common\Encoding\CharFormat
128 |
129 |
130 | Common\Encoding\CharFormat
131 |
132 |
133 | Common\Encoding\CharFormat
134 |
135 |
136 | Common\Encoding
137 |
138 |
139 | Common\Stream
140 |
141 |
142 | Common\Encoding\CharFormat
143 |
144 |
145 | Common\Encoding\CharFormat
146 |
147 |
148 | Common\Encoding
149 |
150 |
151 | Common\Encoding
152 |
153 |
154 | Source Files
155 |
156 |
157 |
158 |
159 | Common
160 |
161 |
162 | Common
163 |
164 |
165 | Common
166 |
167 |
168 | Common
169 |
170 |
171 | Common\Stream
172 |
173 |
174 | Common\Stream
175 |
176 |
177 | Common\Stream
178 |
179 |
180 | Common\Stream
181 |
182 |
183 | Common\Stream
184 |
185 |
186 | Common\Stream
187 |
188 |
189 | Common\Stream
190 |
191 |
192 | Import
193 |
194 |
195 | Common\Stream
196 |
197 |
198 | Common\Stream
199 |
200 |
201 | Common\Encoding\CharFormat
202 |
203 |
204 | Common\Encoding
205 |
206 |
207 | Common\Encoding
208 |
209 |
210 | Common\Stream
211 |
212 |
213 | Common\Encoding\CharFormat
214 |
215 |
216 | Common\Encoding\CharFormat
217 |
218 |
219 | Common\Encoding\CharFormat
220 |
221 |
222 | Common\Encoding
223 |
224 |
225 |
--------------------------------------------------------------------------------