├── LICENSE ├── README.md ├── base64.cpp ├── base64.h ├── clipp.h └── compact_html.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Frost Sigh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # compact_html 2 | ## Welcome! 3 | Embed image data directly to HTML files. 4 | 5 | ## Thanks: 6 | [cpp-base64](https://github.com/ReneNyffenegger/cpp-base64): Base64 encoding and decoding with c++. 7 | [cpprestsdk](https://github.com/microsoft/cpprestsdk): The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services. 8 | [clipp](https://github.com/muellan/clipp): easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation. 9 | -------------------------------------------------------------------------------- /base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | base64 encoding and decoding with C++. 5 | More information at 6 | https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp 7 | 8 | Version: 2.rc.08 (release candidate) 9 | 10 | Copyright (C) 2004-2017, 2020, 2021 René Nyffenegger 11 | 12 | This source code is provided 'as-is', without any express or implied 13 | warranty. In no event will the author be held liable for any damages 14 | arising from the use of this software. 15 | 16 | Permission is granted to anyone to use this software for any purpose, 17 | including commercial applications, and to alter it and redistribute it 18 | freely, subject to the following restrictions: 19 | 20 | 1. The origin of this source code must not be misrepresented; you must not 21 | claim that you wrote the original source code. If you use this source code 22 | in a product, an acknowledgment in the product documentation would be 23 | appreciated but is not required. 24 | 25 | 2. Altered source versions must be plainly marked as such, and must not be 26 | misrepresented as being the original source code. 27 | 28 | 3. This notice may not be removed or altered from any source distribution. 29 | 30 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 31 | 32 | */ 33 | 34 | #include "base64.h" 35 | 36 | #include 37 | #include 38 | 39 | // 40 | // Depending on the url parameter in base64_chars, one of 41 | // two sets of base64 characters needs to be chosen. 42 | // They differ in their last two characters. 43 | // 44 | static const char* base64_chars[2] = { 45 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 46 | "abcdefghijklmnopqrstuvwxyz" 47 | "0123456789" 48 | "+/", 49 | 50 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 51 | "abcdefghijklmnopqrstuvwxyz" 52 | "0123456789" 53 | "-_"}; 54 | 55 | static unsigned int pos_of_char(const unsigned char chr) { 56 | // 57 | // Return the position of chr within base64_encode() 58 | // 59 | 60 | if (chr >= 'A' && chr <= 'Z') return chr - 'A'; 61 | else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; 62 | else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; 63 | else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( 64 | else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' 65 | else 66 | // 67 | // 2020-10-23: Throw std::exception rather than const char* 68 | //(Pablo Martin-Gomez, https://github.com/Bouska) 69 | // 70 | throw std::runtime_error("Input is not valid base64-encoded data."); 71 | } 72 | 73 | static std::string insert_linebreaks(std::string str, size_t distance) { 74 | // 75 | // Provided by https://github.com/JomaCorpFX, adapted by me. 76 | // 77 | if (!str.length()) { 78 | return ""; 79 | } 80 | 81 | size_t pos = distance; 82 | 83 | while (pos < str.size()) { 84 | str.insert(pos, "\n"); 85 | pos += distance + 1; 86 | } 87 | 88 | return str; 89 | } 90 | 91 | template 92 | static std::string encode_with_line_breaks(String s) { 93 | return insert_linebreaks(base64_encode(s, false), line_length); 94 | } 95 | 96 | template 97 | static std::string encode_pem(String s) { 98 | return encode_with_line_breaks(s); 99 | } 100 | 101 | template 102 | static std::string encode_mime(String s) { 103 | return encode_with_line_breaks(s); 104 | } 105 | 106 | template 107 | static std::string encode(String s, bool url) { 108 | return base64_encode(reinterpret_cast(s.data()), s.length(), url); 109 | } 110 | 111 | std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) { 112 | 113 | size_t len_encoded = (in_len +2) / 3 * 4; 114 | 115 | unsigned char trailing_char = url ? '.' : '='; 116 | 117 | // 118 | // Choose set of base64 characters. They differ 119 | // for the last two positions, depending on the url 120 | // parameter. 121 | // A bool (as is the parameter url) is guaranteed 122 | // to evaluate to either 0 or 1 in C++ therefore, 123 | // the correct character set is chosen by subscripting 124 | // base64_chars with url. 125 | // 126 | const char* base64_chars_ = base64_chars[url]; 127 | 128 | std::string ret; 129 | ret.reserve(len_encoded); 130 | 131 | unsigned int pos = 0; 132 | 133 | while (pos < in_len) { 134 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); 135 | 136 | if (pos+1 < in_len) { 137 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); 138 | 139 | if (pos+2 < in_len) { 140 | ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); 141 | ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); 142 | } 143 | else { 144 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); 145 | ret.push_back(trailing_char); 146 | } 147 | } 148 | else { 149 | 150 | ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); 151 | ret.push_back(trailing_char); 152 | ret.push_back(trailing_char); 153 | } 154 | 155 | pos += 3; 156 | } 157 | 158 | 159 | return ret; 160 | } 161 | 162 | template 163 | static std::string decode(String encoded_string, bool remove_linebreaks) { 164 | // 165 | // decode(…) is templated so that it can be used with String = const std::string& 166 | // or std::string_view (requires at least C++17) 167 | // 168 | 169 | if (encoded_string.empty()) return std::string(); 170 | 171 | if (remove_linebreaks) { 172 | 173 | std::string copy(encoded_string); 174 | 175 | copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); 176 | 177 | return base64_decode(copy, false); 178 | } 179 | 180 | size_t length_of_string = encoded_string.length(); 181 | size_t pos = 0; 182 | 183 | // 184 | // The approximate length (bytes) of the decoded string might be one or 185 | // two bytes smaller, depending on the amount of trailing equal signs 186 | // in the encoded string. This approximation is needed to reserve 187 | // enough space in the string to be returned. 188 | // 189 | size_t approx_length_of_decoded_string = length_of_string / 4 * 3; 190 | std::string ret; 191 | ret.reserve(approx_length_of_decoded_string); 192 | 193 | while (pos < length_of_string) { 194 | // 195 | // Iterate over encoded input string in chunks. The size of all 196 | // chunks except the last one is 4 bytes. 197 | // 198 | // The last chunk might be padded with equal signs or dots 199 | // in order to make it 4 bytes in size as well, but this 200 | // is not required as per RFC 2045. 201 | // 202 | // All chunks except the last one produce three output bytes. 203 | // 204 | // The last chunk produces at least one and up to three bytes. 205 | // 206 | 207 | size_t pos_of_char_1 = pos_of_char(encoded_string[pos+1] ); 208 | 209 | // 210 | // Emit the first output byte that is produced in each chunk: 211 | // 212 | ret.push_back(static_cast( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); 213 | 214 | if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) 215 | encoded_string[pos+2] != '=' && 216 | encoded_string[pos+2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also. 217 | ) 218 | { 219 | // 220 | // Emit a chunk's second byte (which might not be produced in the last chunk). 221 | // 222 | unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] ); 223 | ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); 224 | 225 | if ( ( pos + 3 < length_of_string ) && 226 | encoded_string[pos+3] != '=' && 227 | encoded_string[pos+3] != '.' 228 | ) 229 | { 230 | // 231 | // Emit a chunk's third byte (which might not be produced in the last chunk). 232 | // 233 | ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3]) )); 234 | } 235 | } 236 | 237 | pos += 4; 238 | } 239 | 240 | return ret; 241 | } 242 | 243 | std::string base64_decode(std::string const& s, bool remove_linebreaks) { 244 | return decode(s, remove_linebreaks); 245 | } 246 | 247 | std::string base64_encode(std::string const& s, bool url) { 248 | return encode(s, url); 249 | } 250 | 251 | std::string base64_encode_pem (std::string const& s) { 252 | return encode_pem(s); 253 | } 254 | 255 | std::string base64_encode_mime(std::string const& s) { 256 | return encode_mime(s); 257 | } 258 | 259 | #if __cplusplus >= 201703L 260 | // 261 | // Interface with std::string_view rather than const std::string& 262 | // Requires C++17 263 | // Provided by Yannic Bonenberger (https://github.com/Yannic) 264 | // 265 | 266 | std::string base64_encode(std::string_view s, bool url) { 267 | return encode(s, url); 268 | } 269 | 270 | std::string base64_encode_pem(std::string_view s) { 271 | return encode_pem(s); 272 | } 273 | 274 | std::string base64_encode_mime(std::string_view s) { 275 | return encode_mime(s); 276 | } 277 | 278 | std::string base64_decode(std::string_view s, bool remove_linebreaks) { 279 | return decode(s, remove_linebreaks); 280 | } 281 | 282 | #endif // __cplusplus >= 201703L 283 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // base64 encoding and decoding with C++. 3 | // Version: 2.rc.08 (release candidate) 4 | // 5 | 6 | #ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 7 | #define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A 8 | 9 | #include 10 | 11 | #if __cplusplus >= 201703L 12 | #include 13 | #endif // __cplusplus >= 201703L 14 | 15 | std::string base64_encode (std::string const& s, bool url = false); 16 | std::string base64_encode_pem (std::string const& s); 17 | std::string base64_encode_mime(std::string const& s); 18 | 19 | std::string base64_decode(std::string const& s, bool remove_linebreaks = false); 20 | std::string base64_encode(unsigned char const*, size_t len, bool url = false); 21 | 22 | #if __cplusplus >= 201703L 23 | // 24 | // Interface with std::string_view rather than const std::string& 25 | // Requires C++17 26 | // Provided by Yannic Bonenberger (https://github.com/Yannic) 27 | // 28 | std::string base64_encode (std::string_view s, bool url = false); 29 | std::string base64_encode_pem (std::string_view s); 30 | std::string base64_encode_mime(std::string_view s); 31 | 32 | std::string base64_decode(std::string_view s, bool remove_linebreaks = false); 33 | #endif // __cplusplus >= 201703L 34 | 35 | #endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ 36 | -------------------------------------------------------------------------------- /compact_html.cpp: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | #include "clipp.h" 3 | #include 4 | // #include 5 | #include 6 | 7 | #ifdef _WIN32 8 | #include 9 | #endif 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | const std::regex img_src_pattern(R"#(