Skip to content

Commit 8f67d31

Browse files
committed
feat(Compress): Add CompressStringify
1 parent cafd0d8 commit 8f67d31

File tree

5 files changed

+392
-25
lines changed

5 files changed

+392
-25
lines changed

CMakeLists.txt

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,37 +74,14 @@ FetchContent_Declare(
7474
set(WITH_TESTS OFF CACHE BOOL "Build libcbor tests")
7575
set(WITH_EXAMPLES OFF CACHE BOOL "Build libcbor examples")
7676

77-
option(ZSTD_BUILD_CONTRIB "BUILD_CONTRIB" OFF)
78-
option(ZSTD_BUILD_PROGRAMS "BUILD_PROGRAMS" OFF)
79-
option(ZSTD_BUILD_SHARED "BUILD_SHARED" OFF)
80-
option(ZSTD_BUILD_STATIC "BUILD_STATIC" ON)
81-
option(ZSTD_BUILD_TESTS "BUILD_TESTS" OFF)
82-
option(ZSTD_BUILD_LEGACY_SUPPORT "BUILD_LEGACY_SUPPORT" OFF)
83-
option(ZSTD_MULTITHREAD_SUPPORT "BUILD_MULTITHREAD_SUPPORT" OFF)
84-
option(ZSTD_BUILD_PROGRAMS_LINK_SHARED "BUILD_PROGRAMS_LINK_SHARED" OFF)
85-
option(ZSTD_BUILD_LZ4 "BUILD_LZ4" OFF)
86-
option(ZSTD_BUILD_LZMA "BUILD_LZMA" OFF)
87-
option(ZSTD_BUILD_ZLIB "BUILD_ZLIB" OFF)
88-
set(zstd_GIT_REPOSITORY "https://github.com/facebook/zstd.git")
89-
# v1.5.0
90-
set(zstd_GIT_TAG fe616643e0f17552025f50b84508ac5b286dd30f)
91-
FetchContent_Declare(
92-
zstd_lib
93-
GIT_REPOSITORY ${zstd_GIT_REPOSITORY}
94-
GIT_TAG ${zstd_GIT_TAG}
95-
)
96-
9777
list(APPEND CMAKE_MODULE_PATH ${libcbor_SOURCE_DIR}/CMakeModules)
98-
FetchContent_MakeAvailable(rapidjson_lib cli11 rang libcbor zstd_lib)
78+
FetchContent_MakeAvailable(rapidjson_lib cli11 rang libcbor)
9979
set(RapidJSON_INCLUDE_DIR "${rapidjson_lib_SOURCE_DIR}/include")
10080
set(cli11_INCLUDE_DIR "${cli11_SOURCE_DIR}/include")
10181
set(rang_INCLUDE_DIR "${rang_SOURCE_DIR}/include")
10282
set(libcbor_INCLUDE_DIR "${libcbor_SOURCE_DIR}/src")
10383
set(libcbor_EXPORT_DIR "${libcbor_BINARY_DIR}/src")
10484
set(libcbor_CONFIGURATION_DIR "${libcbor_BINARY_DIR}/")
105-
set(zstd_lib_INCLUDE_DIR "${zstd_lib_SOURCE_DIR}/lib")
106-
107-
add_subdirectory("${zstd_lib_SOURCE_DIR}/build/cmake" "${zstd_lib_BINARY_DIR}")
10885

10986
set(BUILD_TESTING ${_itk_build_testing})
11087
set(BUILD_SHARED_LIBS ${_itk_build_shared})
@@ -119,7 +96,6 @@ set(WebAssemblyInterface_INCLUDE_DIRS
11996
${libcbor_INCLUDE_DIR}
12097
${libcbor_EXPORT_DIR}
12198
${libcbor_CONFIGURATION_DIR}
122-
${zstd_lib_INCLUDE_DIR}
12399
)
124100
list(APPEND WebAssemblyInterface_LIBRARIES cbor)
125101

include/itkWASMStringStream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "itkWASMDataObject.h"
2222
#include "rapidjson/document.h"
23+
#include <string_view>
2324

2425
namespace itk
2526
{
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
/*******************************************************************************
2+
MIT License
3+
4+
Copyright (c) 2020 Natasha England-Elbro
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+
******************************************************************************/
24+
25+
/*/
26+
----------------------------------------
27+
Base64 - C++ file
28+
Created on 19/01/2020 by Natasha England-Elbro,
29+
-----------------------------------------
30+
/*/
31+
32+
#ifndef LOCKETTE_BASE64_INL_CC86FA91CA464542919F0B82B87F98EA
33+
#define LOCKETTE_BASE64_INL_CC86FA91CA464542919F0B82B87F98EA
34+
/**
35+
* @file Header only file containing functions and classes for base64 encoding and decoding
36+
*/
37+
38+
39+
#include <cstddef>
40+
#include <string>
41+
#include <stdexcept>
42+
43+
namespace tgk::utils::b64 {
44+
45+
/// Unsigned char byte
46+
using byte = unsigned char;
47+
48+
/// Defines the char type to use
49+
/**
50+
* wchar_t - UNICODE support
51+
* char - ASCII only (also remove the L from the B64_LOOKUP_TBL if your doing this)
52+
*/
53+
using uchar = char;
54+
55+
/// Base64 alphabet for conversions
56+
constexpr uchar B64_LOOKUP_TBL[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
57+
/// Character used for padding '=' by default
58+
constexpr uchar B64_PAD = '=';
59+
60+
61+
/// Get the length of a message after being base64 encoded
62+
/**
63+
* @tparam T: Any container with a size() method returning a valid size of the container
64+
* @param msg: A container of type T containing the message
65+
* @return The size of the message after being base64 encoded
66+
*/
67+
template <typename T>
68+
size_t constexpr get_encoded_size(T msg) {
69+
return ((msg.size() / 3) + (msg.size() % 3 > 0) * 4);
70+
}
71+
72+
/// Get the size of an encoded message when decoded
73+
/**
74+
* @tparam T: Any container with a size() method returning a valid size of the container
75+
* @tparam C: Any implementable number basically
76+
* @param msg: A container of type T containing the message
77+
* @param padding: The amount of padding the message has, defaults to 0
78+
* @return The size required the hold the message once decoded
79+
*/
80+
template <typename T, typename C>
81+
size_t constexpr get_decoded_size(T msg, C padding = 0) {
82+
return ((msg.size() / 4) * 3) - padding;
83+
}
84+
85+
/// Check if something is valid base64
86+
/**
87+
* Returns true if msg is valid base64 (dividable by 4 exactly)
88+
* @tparam T: Any container with a size() method returning a valid size
89+
* @param msg: A container matching T which contains the elements to check
90+
* @return True or False depending on if msg is valid base64 (with padding)
91+
*/
92+
template <typename T>
93+
constexpr bool is_valid_b64(T msg) {
94+
return (msg.size() % 4) == 0;
95+
}
96+
97+
/// Perform base64 encoding on an iterable container
98+
/**
99+
*
100+
* @tparam T: Specifes a container which must implement size() to get its size and have an iterator object member. (i.e
101+
* std::vector)
102+
* @tparam C: The type of char to use, defaults to uchar which is wchar_t, supporting UNICODE
103+
* @tparam STR: A stream with the << operator
104+
* @tparam LK: The type of the lookup table. Must allow array access (using [ ] operator)
105+
* @param in: The container of type T which contains the elements to encode
106+
* @param out: The stream to push the output into
107+
* @param pad_char: The character to pad the output with, defaults to B64_PAD which is '='
108+
* @param lookup_tbl: The lookup table to use for conversion, default to B64_LOOKUP_TBL which is standard non-urlsafe
109+
* base64 encoding
110+
* @return The encoded string as basic_string<C> (which by default will be the same as wstring as C defaults to wchar_t)
111+
*/
112+
113+
template <typename C = uchar, typename T, typename LK = C>
114+
void b64_encode(T in, std::basic_ostream<C> &out, size_t in_size = -1, C pad_char = B64_PAD, LK lookup_tbl[] =
115+
const_cast<LK *>
116+
(B64_LOOKUP_TBL)) {
117+
118+
if (in_size < 0) in_size = in.size();
119+
120+
// Set the iterator (yes I called it c because I get to write c++)
121+
typename T::iterator c = in.begin();
122+
123+
long oct = 0;
124+
125+
for (size_t sec = 0; sec < in_size / 3; ++sec) {
126+
// Split the character into octs
127+
oct = (*c++) << 16;
128+
oct += (*c++) << 8;
129+
oct += (*c++);
130+
131+
// Perform the shifts and append the shifted bits
132+
out << (1, lookup_tbl[(oct & 0x00fc0000) >> 18]);
133+
out << (1, lookup_tbl[(oct & 0x0003f000) >> 12]);
134+
out << (1, lookup_tbl[(oct & 0x00000fc0) >> 6]);
135+
out << (1, lookup_tbl[(oct & 0x0000003f)]);
136+
}
137+
138+
// Pad the output
139+
// Check if remainder of dividing by 3
140+
auto remains = in.size() % 3;
141+
142+
if (remains >= 1) {
143+
bool single_pad = remains == 2;
144+
oct = (*c++) << 16;
145+
if (single_pad) {
146+
// Single pad
147+
oct += (*c++) << 8;
148+
}
149+
150+
// Shift
151+
out << (1, lookup_tbl[(oct & 0x00FC0000) >> 18]);
152+
out << (1, lookup_tbl[(oct & 0x0003F000) >> 12]);
153+
if (single_pad) {
154+
out << (1, lookup_tbl[(oct & 0x00000FC0) >> 6]);
155+
}
156+
// Add padding
157+
out << (single_pad ? 1 : 2, pad_char);
158+
}
159+
}
160+
161+
/// Decode a base64 encoded string
162+
/**
163+
* @tparam T: Any iterable container with a size() method returning a valid size
164+
* @tparam C: The char type to use, defaults to uchar (UNICODE)
165+
* @tparam STR: Any container with an append() method and initaliser
166+
* @param in: A container of type T containg the elements to decode
167+
* @param out: The stream to push to output too
168+
* @param pad_char: The char of type C used for padding on the encoded message. Defaults to '='
169+
* @return The decoded string as an std::basic_string<C>
170+
* @note Currently this is hardcoded for non-urlsafe decoding.
171+
*/
172+
template <typename C = uchar, typename T>
173+
void b64_decode(T in, std::basic_ostream<C> &out, size_t in_size = -1, C pad_char = B64_PAD) {
174+
// Throw if [in] is invalid/not b64 encoded
175+
if (!is_valid_b64(in)) {
176+
throw std::invalid_argument("tgk::utils::b64::b64_decode received an invalid (not base64 "
177+
"encoded) message to decode!");
178+
}
179+
if (in_size < 0) in_size = in.size();
180+
181+
auto padded = 0;
182+
if (in_size) {
183+
// Calculate padding
184+
if (*(in.end() - 1) == pad_char) padded++;
185+
if (*(in.end() - 2) == pad_char) padded++;
186+
}
187+
188+
long oct = 0;
189+
190+
for (auto c : in) {
191+
// Split each 4 char segment
192+
for (size_t sec = 0; sec < 4; ++sec) {
193+
oct <<= 4; // oct == 00010000 if oct = 1
194+
195+
// [A-Z]
196+
if (c >= 0x41 && c <= 0x5A) {
197+
oct |= c - 0x41;
198+
// [a-z]
199+
} else if (c >= 0x61 && c <= 0x7A) {
200+
oct |= c - 0x47;
201+
// [0-9]
202+
} else if (c >= 0x30 && c <= 0x39) {
203+
oct |= c + 0x04;
204+
// '+'
205+
} else if (c == 0x2b) {
206+
oct |= 0x3e;
207+
// '/'
208+
} else if (c == 0x2f) { oct |= 0x3f; }
209+
else if (c == pad_char) {
210+
// Deal with padding
211+
switch (padded) {
212+
case 1:
213+
// Single padded
214+
out << ((oct >> 16) & 0x000000ff);
215+
out << ((oct >> 8) & 0x000000ff);
216+
return;
217+
case 2:
218+
// Doubled passed
219+
out << ((oct >> 10) & 0x000000ff);
220+
return;
221+
default:
222+
throw std::invalid_argument("tgk::utils::b64::b64_decode received an invalid (not base64 "
223+
"encoded) message to decode!");
224+
}
225+
}
226+
}
227+
out << ((oct >> 16) & 0x000000ff);
228+
out << ((oct >> 8) & 0x000000ff);
229+
out << (oct & 0x000000ff);
230+
}
231+
}
232+
}
233+
234+
#endif //LOCKETTE_BASE64_INL_CC86FA91CA464542919F0B82B87F98EA
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
project(CompressStringify)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
6+
include(FetchContent)
7+
option(ZSTD_BUILD_CONTRIB "BUILD_CONTRIB" OFF)
8+
option(ZSTD_BUILD_PROGRAMS "BUILD_PROGRAMS" OFF)
9+
option(ZSTD_BUILD_SHARED "BUILD_SHARED" OFF)
10+
option(ZSTD_BUILD_STATIC "BUILD_STATIC" ON)
11+
option(ZSTD_BUILD_TESTS "BUILD_TESTS" OFF)
12+
option(ZSTD_BUILD_LEGACY_SUPPORT "BUILD_LEGACY_SUPPORT" OFF)
13+
option(ZSTD_MULTITHREAD_SUPPORT "BUILD_MULTITHREAD_SUPPORT" OFF)
14+
option(ZSTD_BUILD_PROGRAMS_LINK_SHARED "BUILD_PROGRAMS_LINK_SHARED" OFF)
15+
option(ZSTD_BUILD_LZ4 "BUILD_LZ4" OFF)
16+
option(ZSTD_BUILD_LZMA "BUILD_LZMA" OFF)
17+
option(ZSTD_BUILD_ZLIB "BUILD_ZLIB" OFF)
18+
set(zstd_GIT_REPOSITORY "https://github.com/facebook/zstd.git")
19+
# v1.5.0
20+
set(zstd_GIT_TAG fe616643e0f17552025f50b84508ac5b286dd30f)
21+
FetchContent_Declare(
22+
zstd_lib
23+
GIT_REPOSITORY ${zstd_GIT_REPOSITORY}
24+
GIT_TAG ${zstd_GIT_TAG}
25+
)
26+
set(zstd_lib_INCLUDE_DIR "${zstd_lib_SOURCE_DIR}/lib")
27+
28+
FetchContent_MakeAvailable(zstd_lib)
29+
add_subdirectory("${zstd_lib_SOURCE_DIR}/build/cmake" "${zstd_lib_BINARY_DIR}")
30+
31+
find_package(ITK REQUIRED COMPONENTS WebAssemblyInterface)
32+
include(${ITK_USE_FILE})
33+
34+
add_executable(CompressStringify CompressStringify.cxx)
35+
target_include_directories(CompressStringify PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${zstd_lib_INCLUDE_DIR})
36+
target_link_libraries(CompressStringify PUBLIC zstd ${ITK_LIBRARIES})
37+
38+
if (DEFINED WebAssemblyInterface_SOURCE_DIR)
39+
foreach(target CompressStringify CompressStringify.umd)
40+
itk_module_target_label(${target})
41+
itk_module_target_export(${target})
42+
itk_module_target_install(${target})
43+
set_property(TARGET ${target}
44+
PROPERTY RUNTIME_OUTPUT_DIRECTORY
45+
${WebAssemblyInterface_BINARY_DIR}/image-io
46+
)
47+
endforeach()
48+
endif()

0 commit comments

Comments
 (0)