├── .gitignore ├── .travis.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── Doxyfile ├── INSTALL ├── LICENSE ├── Makefile.am ├── NEWS ├── README ├── README.md ├── bootstrap.sh ├── configure-gcc-hardened.sh ├── configure.ac ├── doxy ├── footer.html └── header.html ├── indent.sh ├── javascript ├── base64-speed.html ├── base64-test.html ├── base64.html ├── base64.js ├── qunit.css ├── qunit.js ├── urlparse-test.html └── urlparse.js ├── make-ci.sh ├── makerelease.sh ├── python └── b85.py ├── src ├── Makefile.am ├── arraytoc.c ├── arraytoc.h ├── extern_c_begin.h ├── extern_c_end.h ├── html_named_entities_generator.py ├── modp_ascii.c ├── modp_ascii.h ├── modp_ascii_gen.c ├── modp_b16.c ├── modp_b16.h ├── modp_b16_gen.c ├── modp_b2.c ├── modp_b2.h ├── modp_b2_gen.c ├── modp_b36.c ├── modp_b36.h ├── modp_b64.c ├── modp_b64.h ├── modp_b64_gen.c ├── modp_b64r.h ├── modp_b64w.h ├── modp_b85.c ├── modp_b85.h ├── modp_b85_gen.c ├── modp_bjavascript.c ├── modp_bjavascript.h ├── modp_bjavascript_data.h ├── modp_bjavascript_gen.c ├── modp_burl.c ├── modp_burl.h ├── modp_burl_data.h ├── modp_burl_gen.c ├── modp_html.c ├── modp_html.h ├── modp_html_named_entities.h ├── modp_json.c ├── modp_json.h ├── modp_json_data.h ├── modp_json_gen.py ├── modp_mainpage.h ├── modp_numtoa.c ├── modp_numtoa.h ├── modp_qsiter.c ├── modp_qsiter.h ├── modp_stdint.h ├── modp_utf8.c ├── modp_utf8.h ├── modp_xml.c ├── modp_xml.h ├── stringencoders.pc └── stringencoders.pc.in └── test ├── Makefile.am ├── apr_base64.c ├── apr_base64.h ├── cxx_test.cc ├── minunit.h ├── modp_ascii_test.c ├── modp_b16_test.c ├── modp_b2_test.c ├── modp_b64_test.c ├── modp_b85_test.c ├── modp_bjavascript_test.c ├── modp_burl_test.c ├── modp_html_test.c ├── modp_json_test.c ├── modp_numtoa_test.c ├── modp_qsiter_test.c ├── modp_utf8_test.c ├── modp_xml_test.c ├── speedtest.c ├── speedtest_ascii.c ├── speedtest_msg.c └── speedtest_numtoa.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.log 3 | *.trs 4 | *.lo 5 | Makefile 6 | Makefile.in 7 | .libs 8 | .deps 9 | *.la 10 | aclocal.m4 11 | autom4te.cache/ 12 | compile 13 | config.guess 14 | config.h 15 | config.h.in 16 | config.status 17 | config.sub 18 | configure 19 | depcomp 20 | install-sh 21 | libtool 22 | ltmain.sh 23 | m4/ 24 | missing 25 | stamp-h1 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: c 3 | addons: 4 | apt: 5 | sources: 6 | - ubuntu-toolchain-r-test 7 | - llvm-toolchain-precise-3.8 8 | packages: 9 | - gcc-6 10 | - clang-format-3.8 11 | compiler: gcc-6 12 | env: COMPILER=gcc-6 13 | script: ./make-ci.sh 14 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | it could be you. Send pull requests! 2 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | See LICENSE 2 | 3 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | Yeah, I know this isn't quite the right format. 3 | 4 | 22-Sep-2016 5 | * Fix nasty rounding bug in dtoa functions 6 | * Change license from New BSD to MIT 7 | * Reformat whitespace 8 | * Fix URLs and other documentation 9 | 10 | 01-Nov-2013: 11 | * Added new XML, HTML and UTF-8 functions 12 | * Fixed warnings for latest compilers 13 | * CHANGE: various functions return the amount of data consumed 14 | instead of void 15 | 16 | 06-Oct-2012: 17 | * ADDED new modp_b64r which is a base64 encoding that follows RFC XYZ 18 | 19 | 18-Mar-2012: 20 | * ADDED new file/function: modp_qsiter memory-free query string key-value pair iterator 21 | 22 | 25-Feb-2012: 23 | * ADDED 'make valgrind' to run all tests through valgrind 24 | * Fixed Issue 26 where uint64_t != unsigned long on some platforms. Thanks to ndivx 25 | * Fixed Issue 21 valgrind complains on modp_b16 in some cases. Thanks calfeld@qualys.com 26 | * Fixed Issue 18 copying versions of C++ functions tolower(), toupper(), toprint() modify original string, thanks ilya.m...@gmail.com 27 | 28 | 23-Feb-2012 29 | * Fixed bootstrap code on Mac OS 10. 30 | * Fixed Issue 25 speedtest fails to compile with gcc 4.6+ -Wextra. Thanks to rakesh.pandit 31 | 32 | 19-Mar-2010 33 | * Added "modp_dtoa2" same as dtoa2 but strips trailing zeros (Issue 9) 34 | * FIXED Issue 10 -- NaN not handled correctly in modp_dtoa(2). 35 | * ADDED more tests for NaN/Inf handling 36 | * FIXED some build issues under Ubuntu (64-bit) (sprintf annoyances in testing code) 37 | * REGENERATED that autoconf stuff. Groan. Hopefully it works for you. If not 38 | file a ticket, please! 39 | * VERSION 3.10 RELEASED 40 | 41 | 12-Feb-2010 42 | * FIXED Issue 7 - silent overflow error 43 | * FIXED Incorrect autoconf version 44 | * Issue 6 -- attempt to make VS2008 happy 45 | * VERSION 3.9 RELEASED 46 | 47 | 48 | 05-Jan-2008 49 | * Regenerated libtool/autoconf/autoheader/etc to fix 50 | problem where ranlib was improperly being invoked on some systems 51 | * Added "std::" to some raw "string" in C++ methods 52 | * Added "#include " to some headers for C++ 53 | * Tested with latest snapshot of gcc/g++ with -Wall -Wextra 54 | * No logic changes 55 | 20-Nov-2007 56 | * modp_dtoa 57 | Fixed round-to-even "rollovers" (e.g. 0.99, prec 1 -> 1.0) 58 | Simplified "very small number" logic 59 | Unit tests greatly improved. 60 | thanks again to Johannes Otepka for finding bugs 61 | * VERSION 3.6 RELEASED 62 | 19-Nov-2007 63 | * modp_dtoa 64 | Fixed round-to-even, and precision 0 rules to match printf 65 | thanks to Johannes Otepka 66 | * VERSION 3.5 RELEASED 67 | 68 | 27-Jun-2007 69 | * VERSION 3.4 RELEASED 70 | 71 | 21-Jun-2007 72 | * Ugh. Fix bug in url decode where core dump can occur if someone passes in %XX, where X 73 | has high bit set (> 0x80). Due to signed chars, this is interpreted as a negative, and 74 | bad things happen. Thanks to Andrei Khemmelis. 75 | * Improve more C++ methods, b64, b64w, b16 all have string, const string, const char* and 76 | and (const char*, length) inputs now. 77 | * Added "make help" to give list of options 78 | 79 | 05-Jun-2007 80 | * VERSION 3.3 RELEASED 81 | 82 | 05-Jun-2007 83 | * Fix bug in modp_b16_gen that could core dump (doesn't not effect output, only occurs 84 | during building). Thanks to Constantine Verutin. 85 | 86 | 04-Jun-2007 87 | * toupper/lower now 2x faster than before! Based on an alogirthm by Hsieh 88 | http://www.azillionmonkeys.com/qed/asmexample.html 89 | * C++ added more C++ methods for url_decode 90 | 91 | 24-May-2007 92 | * Version 3.2 released 93 | * Cleaned-up include guards, and 'extern c' stuff for C++. 94 | 95 | 23-May-2007 96 | * Add C++ "const" methods everywhere in case you don't want to 97 | modify the original input 98 | 99 | 15-May-2007 100 | * Removed CuTest since it's crap and leaks memory. 101 | 102 | 14-May-2007 103 | * added modp_ascii -- ascii transformations (upper/lower/etc) -- 104 | 25x faster than ctype toupper,etc 105 | 106 | 13-May-2007 107 | * made b64_encode be about 30% faster on Intel based chip. 108 | Minimal performance loss on AMD, G4 109 | (now all platforms are faster than the apache encoder) 110 | * added modp_b2 -- ascii binary string encode/decode 111 | 112 | 22-Apr-2007 113 | * Release 3.1 114 | * fixes some compliation problems on 64-bit platforms 115 | * add modp_numtoa, fast number to string conversions 116 | 117 | 06-Apr-2007 118 | * Release 3.0 119 | 120 | 03-Mar-2007: 121 | * initial import into google code 122 | 123 | 02-Sep-2006 124 | * New modp_64w which is the configurable base 64 alphabet. 125 | The original modp_b64 will now be the standard base 64 alphabet 126 | and is unchangable. This way you can dump binary data into XML 127 | use the standard, and make web urls (web-safe version) 128 | * Made modp_url_encode escape more characters. This makes it 129 | more standard. 130 | * Add modp_url_min_encode which does a more "minimal" encoding 131 | RFC 3986 actually recommends encoding less characters (the 132 | original was based for HTML form processing). 133 | * Improved documentation 134 | 135 | 28-Aug-2006 136 | * Added javascript encoding. Convert c-string to a format suitable for 137 | embedding into javascript (dynamically generated by the server for instance). 138 | * INTERFACE CHANGE use namespaces for C++ functions, and changed their names 139 | 140 | 16-May-2006: Release 2.0.0 141 | * New Prefix: everything is prefixed with modp_bXX, where XX is the 142 | encoding type 143 | * Massive unit test coverage using CuTest library 144 | * New! bfasturl -- high performance url encode/decode! 145 | * New bfast16 -- high performance hex encode/decode 146 | * New! C++ bindings using std::string 147 | 148 | 15-Mar-2006: Release v1.3 149 | * Version 1.2 b64fast_decode wrote a few extra bytes after the 150 | data as an optimization. This have been changed so it write ONLY 151 | the extact number of byte encoded. THis makes it more compatible 152 | with existing implementations and allows some tricks. (decoding 153 | directly into a C-struct). 154 | 155 | 10-Mar-2006: Release v1.2 156 | * INTERFACE CHANGE -- b65fast_encode returns 157 | strlen of the result. Not strlen+1 like apache. 158 | * Change b64 decode to only write the exact bytes (previously 159 | wrote a few extra 0s at the end for performance reasons) 160 | * Change b85 default alphabet to exclude "," This allows use with 161 | V0/Netscape and V1 HTTP cookies. 162 | 163 | 20-Feb-2006: Release v1.1 164 | * CRITICAL BUG FIX -- in some cases b64encode will produce bad output 165 | this may only occur on some compilers 166 | * Added base85 functionality! 167 | * Cleaned up source code, added mode-lines, reindented 168 | * Renamed files to better reflect function 169 | 170 | 25-Dec-2005: Initial Release v1.0.0 171 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | ---------------------------------------- 3 | RAW 4 | ---------------------------------------- 5 | 6 | If you are pulling this from github, please run `./bootstrap.sh` to do 7 | all the gnu-isms. 8 | 9 | 10 | Mac Users: 11 | 12 | ```bash 13 | brew install m4 autoconf automake libtool 14 | ``` 15 | 16 | (maybe more?) 17 | 18 | ---------------------------------------- 19 | PLAIN INSTALL 20 | ---------------------------------------- 21 | 22 | 23 | EXPORT CFLAGS='your optimization flags' 24 | 25 | gcc defaults to "-O2 -g" you probably want "-O3 -Wall" 26 | 27 | ./configure 28 | 29 | make 30 | 31 | make check 32 | 33 | make install 34 | will produce a shared and static library and put in the right places. 35 | it will also install the include files. 36 | 37 | ---------------------------------------- 38 | CHANGING THE b64 web/url SAFE ALPHABET 39 | ---------------------------------------- 40 | 41 | If you are using base 64 encoding for use IN A URL, you 42 | CAN NOT use the standard mod_b64. You MUST use modp_b64w 43 | (the w is for "web"). Unfortunately this is not standardized 44 | and if you are working with a third party, you might need to 45 | change the "alphabet" (chars). 46 | 47 | You can change char 62,63 and the padding char with 48 | 49 | ./configure --with-b64wchars='-_.' 50 | 51 | where "-" is char 62, "_" is char 63 and "." is the padding char. 52 | 53 | You can change this if you know what you are doing. 54 | 55 | ---------------------------------------- 56 | IF YOU DON'T WANT TO DEAL WITH A LIBRARY 57 | ---------------------------------------- 58 | 59 | Base64 and base85 functions are so small, you might just want to 60 | directly add them into your existing project. That's fine, it's all 61 | under the BSD license, so go ahead. 62 | 63 | 64 | For b64: 65 | -------- 66 | After doing a "./configure && make", copy 67 | * src/modp_b64.c 68 | * src/modp_b64.h 69 | * modp_b64_data.h 70 | 71 | ***** BUT, there is an IMPORTANT GOTCHA! ***** 72 | 73 | This code has special versions that are -endian- dependant. This 74 | means different code is used on an Intel CPU than it is on a Motorola, 75 | IBM, or Sun CPU. 76 | 77 | **** IF you are using autoconf, just add AC_C_BIGENDIAN to your 78 | configure.in script and everything will work. 79 | 80 | **** IF NOT, edit modp_b64.c, and replace the 81 | #include "config.h" 82 | with 83 | #define WORDS_BIGENDIAN /* for Sun, Ibm, Motorola */ 84 | OR 85 | #undef WORDS_BIGENDIAN /* For intel, amd */ 86 | 87 | see the source code for details. Likewise you can pass in 88 | -DWORDS_BIGENDIAN or -DNWORDS_BIGENDIAN during compilation. 89 | 90 | For b85: 91 | -------- 92 | There are no endian issues. Just copy 93 | 94 | * src/modp_b85.c 95 | * src/modp_b85.h 96 | * modp_b85_data.h 97 | 98 | ---------------------------------------- 99 | UNIT TESTS 100 | ---------------------------------------- 101 | 102 | Two unit tests are included that are not installed. They are built 103 | automatically and can be run with "make test" 104 | 105 | ./speedtest tests performance of b64 and b85 106 | ./unittest tests correctness of b64 107 | ./b85test test correectness of b75 108 | 109 | 110 | If you are changing the base64 alphabet, just edit the b64gen.c program 111 | and type 'make'. 112 | 113 | If you are changing the base85 alphabet, edit the b85gen.c program and 114 | type 'make'. 115 | 116 | ALWAYS UNIT TEST ANY CHANGES. The current unittests depend on the 117 | standard alphabet, so you might need to tweek them if to make custom 118 | alterations. 119 | 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nick Galbreath 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 | 23 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src test 2 | 3 | CLEANFILES=test-driver test/modp_b64r_test.c test/modp_b64w_test.c config.h.in~ 4 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | I'm using the changelog for news. 2 | Read that. 3 | 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | See README.md 2 | x -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fast c-string transformations 2 | 3 | [![Build Status](https://travis-ci.org/client9/stringencoders.svg?branch=master)](https://travis-ci.org/client9/stringencoders) 4 | 5 | Hello! 6 | 7 | I don't use this library anymore and try to avoid C programming if possible. That said, 8 | I'm very happy to accept pull-requests and collaborators. 9 | 10 | ## Install from Source 11 | 12 | * You'll need to install autoconf, automake and libtool 13 | * run `./bootstrap.sh` 14 | * run `./configure` 15 | * run `make && make check` 16 | 17 | ## Known Issues: 18 | 19 | * `modp_base64_decode` expects **aligned** strings as input. For Intel, is 20 | doesn't matter. But for ARM chips it can segfault. 21 | * `modp_numtoa.c` functions may produce different rounding than whatever 22 | `printf` is on your system. 23 | * On mingw (windows) compiling with `-D__USE_MINGW_ANSI_STDIO` gives the 24 | standard `prinf` behavior. 25 | 26 | ## Alpine Linux / musl-libc 27 | 28 | * As mentioned, the tests for `modp_numtoa.c` may fail due to a different 29 | rounding algorithm. 30 | * https://wiki.alpinelinux.org/wiki/How_to_get_regular_stuff_working 31 | * `apk add gcc bash autoconf automake libtools util-linux pciutils usbutils coreutils binutils findutils grep` 32 | 33 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | autoreconf --install --force 3 | automake --add-missing >/dev/null 2>&1 4 | -------------------------------------------------------------------------------- /configure-gcc-hardened.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | # 4 | # See https://wiki.debian.org/Hardening for details 5 | # 6 | # -Wno-padded padding can change by OS/version this check is really 7 | # for embedded systems so it's ok to skip 8 | # 9 | # -Wno-covered-switch-default Don't warn if we have a switch that 10 | # covers all of an enum AND we have a default. enums are only losely 11 | # typed, it's good to have a default: assert(0) in case someone does 12 | # a bad cast, etc also this conflicts with GCC checks. 13 | # 14 | export CFLAGS="-g -O3 -pie -fPIE -fPIC -fstack-protector --param ssp-buffer-size=4 -Wall -Wextra -Wformat -Wformat-security -Werror -Wcast-align -Wshadow -Wpointer-arith -Wcast-qual -Wstack-protector -D_FORTIFY_SOURCE=2 -ansi" 15 | ./configure --with-pic --disable-shared --enable-static 16 | make clean 17 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(stringencoders, [v3.10.3], [nickg -at- client9 -dot- com]) 2 | AC_PREREQ(2.68) 3 | AM_INIT_AUTOMAKE 4 | AC_PROG_LIBTOOL 5 | AC_CONFIG_HEADERS(config.h) 6 | AC_CONFIG_MACRO_DIR([m4]) 7 | 8 | AC_PROG_CC 9 | AC_PROG_CXX 10 | AC_PROG_INSTALL 11 | 12 | AC_C_CONST 13 | AC_C_BIGENDIAN 14 | AC_TYPE_SIZE_T 15 | AC_CHECK_FUNCS([memset htonl strlen]) 16 | AC_ARG_ENABLE(gcov, AC_HELP_STRING([--enable-gcov],[turn on code coverage analysis tools])) 17 | 18 | B64WCHARS="-_." 19 | AC_ARG_WITH([b64wchars], AC_HELP_STRING([--with-b64wchars=3CHARS],[change b64 web extra chars, default is '-_.']), 20 | [B64WCHARS=$withval], []) 21 | 22 | EXTRACFLAGS="-Isrc -Wall -Wextra -Werror -Wshadow -Wpointer-arith -Wcast-qual -Wconversion" 23 | # -Wstrict-prototypes 24 | # -Wmissing-prototypes 25 | 26 | if test "x$enable_gcov" = "xyes"; 27 | then 28 | EXTRACFLAGS="$EXTRACFLAGS -fprofile-arcs -ftest-coverage" 29 | dnl Turn off optimization so code coverage tool 30 | dnl can get accurate line numbers 31 | CFLAGS=`echo "$EXTRACFLAGS" | sed -e 's/-O[0-9]*//g'` 32 | CFLAGS="$CFLAGS -O0 -fno-inline" 33 | fi 34 | CFLAGS="$EXTRACFLAGS $CFLAGS" 35 | CXXFLAGS="$CFLAGS" 36 | AC_SUBST(B64WCHARS) 37 | AC_CONFIG_FILES([ 38 | Makefile 39 | src/Makefile 40 | test/Makefile 41 | src/stringencoders.pc 42 | ]) 43 | AC_PROG_MAKE_SET 44 | AC_OUTPUT 45 | -------------------------------------------------------------------------------- /doxy/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 15 | 16 | comments powered by Disqus 17 | 18 | 19 | 20 | 22 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /doxy/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $title 6 | 7 | 8 | 52 | 53 | 54 | 65 | 66 | 67 |
68 | 69 |
70 |

client9

71 |
72 | Software Engineering by Nick Galbreath 73 | 80 |
81 |

stringencoders

82 |
83 | 84 |
85 |
86 | -------------------------------------------------------------------------------- /indent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | if [ -z "${INDENT}" ]; then 4 | INDENT=clang-format 5 | fi 6 | ${INDENT} --version 7 | find . -name '*.[ch]' | xargs ${INDENT} -i -style=WebKit 8 | git status --porcelain 9 | 10 | -------------------------------------------------------------------------------- /javascript/base64-speed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | base64 encode speeed 5 | 6 | 7 |
 8 | 
41 | 
42 | 43 | 44 | -------------------------------------------------------------------------------- /javascript/base64-test.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 202 | 203 | 204 |

Base64 window.[atob|btoa] tests

205 |

206 |

207 |
    208 | 209 | 210 | -------------------------------------------------------------------------------- /javascript/base64.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
     7 | 
    16 | 
    17 | 18 | 19 | -------------------------------------------------------------------------------- /javascript/base64.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010 Nick Galbreath 3 | * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, 9 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following 12 | * conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | * OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | 27 | /* base64 encode/decode compatible with window.btoa/atob 28 | * 29 | * window.atob/btoa is a Firefox extension to convert binary data (the "b") 30 | * to base64 (ascii, the "a"). 31 | * 32 | * It is also found in Safari and Chrome. It is not available in IE. 33 | * 34 | * if (!window.btoa) window.btoa = base64.encode 35 | * if (!window.atob) window.atob = base64.decode 36 | * 37 | * The original spec's for atob/btoa are a bit lacking 38 | * https://developer.mozilla.org/en/DOM/window.atob 39 | * https://developer.mozilla.org/en/DOM/window.btoa 40 | * 41 | * window.btoa and base64.encode takes a string where charCodeAt is [0,255] 42 | * If any character is not [0,255], then an DOMException(5) is thrown. 43 | * 44 | * window.atob and base64.decode take a base64-encoded string 45 | * If the input length is not a multiple of 4, or contains invalid characters 46 | * then an DOMException(5) is thrown. 47 | */ 48 | var base64 = {}; 49 | base64.PADCHAR = '='; 50 | base64.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 51 | 52 | base64.makeDOMException = function() { 53 | // sadly in FF,Safari,Chrome you can't make a DOMException 54 | var e, tmp; 55 | 56 | try { 57 | return new DOMException(DOMException.INVALID_CHARACTER_ERR); 58 | } catch (tmp) { 59 | // not available, just passback a duck-typed equiv 60 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error 61 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error/prototype 62 | var ex = new Error("DOM Exception 5"); 63 | 64 | // ex.number and ex.description is IE-specific. 65 | ex.code = ex.number = 5; 66 | ex.name = ex.description = "INVALID_CHARACTER_ERR"; 67 | 68 | // Safari/Chrome output format 69 | ex.toString = function() { return 'Error: ' + ex.name + ': ' + ex.message; }; 70 | return ex; 71 | } 72 | } 73 | 74 | base64.getbyte64 = function(s,i) { 75 | // This is oddly fast, except on Chrome/V8. 76 | // Minimal or no improvement in performance by using a 77 | // object with properties mapping chars to value (eg. 'A': 0) 78 | var idx = base64.ALPHA.indexOf(s.charAt(i)); 79 | if (idx === -1) { 80 | throw base64.makeDOMException(); 81 | } 82 | return idx; 83 | } 84 | 85 | base64.decode = function(s) { 86 | // convert to string 87 | s = '' + s; 88 | var getbyte64 = base64.getbyte64; 89 | var pads, i, b10; 90 | var imax = s.length 91 | if (imax === 0) { 92 | return s; 93 | } 94 | 95 | if (imax % 4 !== 0) { 96 | throw base64.makeDOMException(); 97 | } 98 | 99 | pads = 0 100 | if (s.charAt(imax - 1) === base64.PADCHAR) { 101 | pads = 1; 102 | if (s.charAt(imax - 2) === base64.PADCHAR) { 103 | pads = 2; 104 | } 105 | // either way, we want to ignore this last block 106 | imax -= 4; 107 | } 108 | 109 | var x = []; 110 | for (i = 0; i < imax; i += 4) { 111 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | 112 | (getbyte64(s,i+2) << 6) | getbyte64(s,i+3); 113 | x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff, b10 & 0xff)); 114 | } 115 | 116 | switch (pads) { 117 | case 1: 118 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6); 119 | x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff)); 120 | break; 121 | case 2: 122 | b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12); 123 | x.push(String.fromCharCode(b10 >> 16)); 124 | break; 125 | } 126 | return x.join(''); 127 | } 128 | 129 | base64.getbyte = function(s,i) { 130 | var x = s.charCodeAt(i); 131 | if (x > 255) { 132 | throw base64.makeDOMException(); 133 | } 134 | return x; 135 | } 136 | 137 | base64.encode = function(s) { 138 | if (arguments.length !== 1) { 139 | throw new SyntaxError("Not enough arguments"); 140 | } 141 | var padchar = base64.PADCHAR; 142 | var alpha = base64.ALPHA; 143 | var getbyte = base64.getbyte; 144 | 145 | var i, b10; 146 | var x = []; 147 | 148 | // convert to string 149 | s = '' + s; 150 | 151 | var imax = s.length - s.length % 3; 152 | 153 | if (s.length === 0) { 154 | return s; 155 | } 156 | for (i = 0; i < imax; i += 3) { 157 | b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2); 158 | x.push(alpha.charAt(b10 >> 18)); 159 | x.push(alpha.charAt((b10 >> 12) & 0x3F)); 160 | x.push(alpha.charAt((b10 >> 6) & 0x3f)); 161 | x.push(alpha.charAt(b10 & 0x3f)); 162 | } 163 | switch (s.length - imax) { 164 | case 1: 165 | b10 = getbyte(s,i) << 16; 166 | x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + 167 | padchar + padchar); 168 | break; 169 | case 2: 170 | b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8); 171 | x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + 172 | alpha.charAt((b10 >> 6) & 0x3f) + padchar); 173 | break; 174 | } 175 | return x.join(''); 176 | } 177 | -------------------------------------------------------------------------------- /javascript/qunit.css: -------------------------------------------------------------------------------- 1 | 2 | ol#qunit-tests { 3 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 4 | margin:0; 5 | padding:0; 6 | list-style-position:inside; 7 | 8 | font-size: smaller; 9 | } 10 | ol#qunit-tests li{ 11 | padding:0.4em 0.5em 0.4em 2.5em; 12 | border-bottom:1px solid #fff; 13 | font-size:small; 14 | list-style-position:inside; 15 | } 16 | ol#qunit-tests li ol{ 17 | box-shadow: inset 0px 2px 13px #999; 18 | -moz-box-shadow: inset 0px 2px 13px #999; 19 | -webkit-box-shadow: inset 0px 2px 13px #999; 20 | margin-top:0.5em; 21 | margin-left:0; 22 | padding:0.5em; 23 | background-color:#fff; 24 | border-radius:15px; 25 | -moz-border-radius: 15px; 26 | -webkit-border-radius: 15px; 27 | } 28 | ol#qunit-tests li li{ 29 | border-bottom:none; 30 | margin:0.5em; 31 | background-color:#fff; 32 | list-style-position: inside; 33 | padding:0.4em 0.5em 0.4em 0.5em; 34 | } 35 | 36 | ol#qunit-tests li li.pass{ 37 | border-left:26px solid #C6E746; 38 | background-color:#fff; 39 | color:#5E740B; 40 | } 41 | ol#qunit-tests li li.fail{ 42 | border-left:26px solid #EE5757; 43 | background-color:#fff; 44 | color:#710909; 45 | } 46 | ol#qunit-tests li.pass{ 47 | background-color:#D2E0E6; 48 | color:#528CE0; 49 | } 50 | ol#qunit-tests li.fail{ 51 | background-color:#EE5757; 52 | color:#000; 53 | } 54 | ol#qunit-tests li strong { 55 | cursor:pointer; 56 | } 57 | h1#qunit-header{ 58 | background-color:#0d3349; 59 | margin:0; 60 | padding:0.5em 0 0.5em 1em; 61 | color:#fff; 62 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 63 | border-top-right-radius:15px; 64 | border-top-left-radius:15px; 65 | -moz-border-radius-topright:15px; 66 | -moz-border-radius-topleft:15px; 67 | -webkit-border-top-right-radius:15px; 68 | -webkit-border-top-left-radius:15px; 69 | text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px; 70 | } 71 | h2#qunit-banner{ 72 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 73 | height:5px; 74 | margin:0; 75 | padding:0; 76 | } 77 | h2#qunit-banner.qunit-pass{ 78 | background-color:#C6E746; 79 | } 80 | h2#qunit-banner.qunit-fail, #qunit-testrunner-toolbar { 81 | background-color:#EE5757; 82 | } 83 | #qunit-testrunner-toolbar { 84 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 85 | padding:0; 86 | /*width:80%;*/ 87 | padding:0em 0 0.5em 2em; 88 | font-size: small; 89 | } 90 | h2#qunit-userAgent { 91 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 92 | background-color:#2b81af; 93 | margin:0; 94 | padding:0; 95 | color:#fff; 96 | font-size: small; 97 | padding:0.5em 0 0.5em 2.5em; 98 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 99 | } 100 | p#qunit-testresult{ 101 | font-family:"Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 102 | margin:0; 103 | font-size: small; 104 | color:#2b81af; 105 | border-bottom-right-radius:15px; 106 | border-bottom-left-radius:15px; 107 | -moz-border-radius-bottomright:15px; 108 | -moz-border-radius-bottomleft:15px; 109 | -webkit-border-bottom-right-radius:15px; 110 | -webkit-border-bottom-left-radius:15px; 111 | background-color:#D2E0E6; 112 | padding:0.5em 0.5em 0.5em 2.5em; 113 | } 114 | strong b.fail{ 115 | color:#710909; 116 | } 117 | strong b.pass{ 118 | color:#5E740B; 119 | } 120 | -------------------------------------------------------------------------------- /make-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | set -e 4 | 5 | INDENT=clang-format-3.8 ./indent.sh 6 | git status --porcelain | wc -l 7 | 8 | autoreconf --install --force 9 | automake --add-missing >/dev/null 2>&1 10 | ./configure 11 | make 12 | make check 13 | 14 | -------------------------------------------------------------------------------- /makerelease.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FILE=stringencoders-v3.11.0 4 | rm -rf ${FILE} 5 | git clone --depth=1 git@github.com:client9/stringencoders.git ${FILE} 6 | (cd ${FILE} && ./bootstrap.sh) 7 | find $FILE -name ".git" | xargs rm -rf 8 | 9 | rm -f ${FILE}/Doxyfile 10 | rm -f ${FILE}/makerelease.sh 11 | rm -rf ${FILE}/doxy 12 | 13 | tar -czvf ${FILE}.tar.gz ${FILE} 14 | rm -rf ${FILE} 15 | echo "DONE" 16 | ls -lh ${FILE}.tar.gz 17 | -------------------------------------------------------------------------------- /python/b85.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # This is the MIT License 5 | # http://www.opensource.org/licenses/mit-license.php 6 | # 7 | # Copyright (c) 2008 Nick Galbreath 8 | # 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in 17 | # all copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | # THE SOFTWARE. 26 | # 27 | 28 | gsCharToInt = [ 29 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 30 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 31 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 0, 256, 1, 32 | 2, 3, 256, 4, 5, 6, 7, 8, 256, 9, 10, 11, 33 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 256, 34 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 | 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 36 | 47, 48, 49, 50, 51, 52, 53, 54, 256, 55, 56, 57, 37 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 38 | 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 39 | 82, 83, 84, 256, 256, 256, 256, 256, 256, 256, 256, 256, 40 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 41 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 42 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 43 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 44 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 45 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 46 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 47 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 48 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 49 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 50 | 256, 256, 256, 256] 51 | 52 | gsIntToChar = [ 53 | '!', '#', '$', '%', '\'', '(', ')', '*', '+', '-', 54 | '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', 55 | '8', '9', ':', '<', '=', '>', '?', '@', 'A', 'B', 56 | 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 57 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 58 | 'W', 'X', 'Y', 'Z', '[', ']', '^', '_', '`', 'a', 59 | 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 60 | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 61 | 'v', 'w', 'x', 'y', 'z' 62 | ] 63 | 64 | from struct import unpack, pack 65 | # covert 4 characters into 5 66 | def b85_encode(s): 67 | parts = [] 68 | numchunks = len(s) // 4 69 | format = '!' + str(numchunks) + 'I' 70 | for x in unpack(format, s): 71 | # network order (big endian), 32-bit unsigned integer 72 | # note: x86 is little endian 73 | parts.append(gsIntToChar[x // 52200625]) 74 | parts.append(gsIntToChar[(x // 614125) % 85]) 75 | parts.append(gsIntToChar[(x // 7225) % 85]) 76 | parts.append(gsIntToChar[(x // 85) % 85]) 77 | parts.append(gsIntToChar[x % 85]) 78 | return ''.join(parts) 79 | 80 | # 81 | # also does not use the 'struct' module which may be desirable 82 | # to some 83 | # 84 | def b85_encode2(s): 85 | parts = [] 86 | for i in xrange(0,len(s), 4): 87 | chunk = s[i:i+4] 88 | x = ord(chunk[3]) + 256*(ord(chunk[2]) + 256*(ord(chunk[1]) + 256*ord(chunk[0]))) 89 | 90 | # network order (big endian), 32-bit unsigned integer 91 | # note: x86 is little endian 92 | parts.append(gsIntToChar[x // 52200625]) 93 | parts.append(gsIntToChar[(x // 614125) % 85]) 94 | parts.append(gsIntToChar[(x // 7225) % 85]) 95 | parts.append(gsIntToChar[(x // 85) % 85]) 96 | parts.append(gsIntToChar[x % 85]) 97 | return ''.join(parts) 98 | 99 | # convert 5 characters to 4 100 | def b85_decode(s): 101 | parts = [] 102 | for i in xrange(0, len(s), 5): 103 | bsum = 0; 104 | for j in xrange(0,5): 105 | val = gsCharToInt[ord(s[i+j])] 106 | bsum = 85*bsum + val 107 | tmp = pack('!I', bsum) 108 | parts.append(tmp) 109 | #parts += tmp 110 | #parts += unpack('cccc', tmp) 111 | return ''.join(parts) 112 | 113 | # convert 5 characters to 4 114 | def b85_decode2(s): 115 | parts = [] 116 | for i in xrange(0, len(s), 5): 117 | bsum = 0; 118 | for j in xrange(0,5): 119 | val = gsCharToInt[ord(s[i+j])] 120 | bsum = 85*bsum + val 121 | parts.append(chr((bsum >> 24) & 0xff)) 122 | parts.append(chr((bsum >> 16) & 0xff)) 123 | parts.append(chr((bsum >> 8) & 0xff)) 124 | parts.append(chr(bsum & 0xff)) 125 | 126 | return ''.join(parts) 127 | 128 | import unittest 129 | class B85Test(unittest.TestCase): 130 | 131 | def testDecode1(self): 132 | s = b85_decode('!!!!#') 133 | self.assertEquals(4, len(s)) 134 | self.assertEquals(0, ord(s[0])) 135 | self.assertEquals(0, ord(s[1])) 136 | self.assertEquals(0, ord(s[2])) 137 | self.assertEquals(1, ord(s[3])) 138 | 139 | e = b85_encode(s) 140 | self.assertEquals('!!!!#', e) 141 | 142 | 143 | if __name__ == '__main__': 144 | from time import clock 145 | #unittest.main() 146 | 147 | s = '!!!!#' * 10 148 | 149 | t0 = clock() 150 | for i in xrange(1000000): 151 | b85_decode(s) 152 | t1 = clock() 153 | print "decode v1", t1-t0 154 | 155 | t0 = clock() 156 | for i in xrange(1000000): 157 | b85_decode2(s) 158 | t1 = clock() 159 | print "decode v2", t1-t0 160 | 161 | 162 | s = b85_decode('!!!!#' * 10) 163 | 164 | t0 = clock() 165 | for i in xrange(1000000): 166 | b85_encode(s) 167 | t1 = clock() 168 | print "encode v1", t1-t0 169 | 170 | t0 = clock() 171 | for i in xrange(1000000): 172 | b85_encode2(s) 173 | t1 = clock() 174 | print "encode v2", t1-t0 175 | 176 | 177 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | include_HEADERS = \ 3 | extern_c_begin.h extern_c_end.h \ 4 | modp_b16.h modp_b64.h modp_b64w.h modp_b64r.h \ 5 | modp_b85.h modp_burl.h modp_bjavascript.h \ 6 | modp_numtoa.h modp_ascii.h modp_b2.h \ 7 | modp_qsiter.h modp_xml.h modp_html.h modp_json.h 8 | 9 | lib_LTLIBRARIES = libmodpbase64.la 10 | libmodpbase64_la_SOURCES = \ 11 | modp_b2.c modp_b2.h modp_b2_data.h \ 12 | modp_b16.c modp_b16.h modp_b16_data.h \ 13 | modp_b64.c modp_b64.h modp_b64_data.h \ 14 | modp_b64w.c modp_b64w.h modp_b64w_data.h \ 15 | modp_b64r.c modp_b64r.h modp_b64r_data.h \ 16 | modp_b85.h modp_b85.c modp_b85_data.h \ 17 | modp_burl.h modp_burl.c modp_burl_data.h \ 18 | modp_bjavascript.h modp_bjavascript.c modp_bjavascript_data.h \ 19 | modp_numtoa.h modp_numtoa.c \ 20 | modp_qsiter.h modp_qsiter.c \ 21 | modp_xml.h modp_xml.c \ 22 | modp_ascii.h modp_ascii.c modp_ascii_data.h \ 23 | modp_utf8.h modp_utf8.c \ 24 | modp_html.h modp_html.c \ 25 | modp_json.h modp_json.c 26 | 27 | pkgconfigdir = $(libdir)/pkgconfig 28 | pkgconfig_DATA = stringencoders.pc 29 | 30 | #libmodpbase64_la_DEPENDENCIES = \ 31 | # modp_b2_data.h modp_b2_gen \ 32 | # modp_b16_data.h modp_b16_gen \ 33 | # modp_b64_data.h modp_b64w_data.h modp_b64r_data.h modp_b64_gen \ 34 | # modp_b85_data.h modp_b85_gen \ 35 | # modp_ascii_data.h modp_ascii_gen 36 | 37 | CLEANFILES = *.log \ 38 | *~ src/*~ test/*~ \ 39 | *.tmp src/*.tmp test/*.tmp \ 40 | doxy/html/* \ 41 | doxy/*.tmp \ 42 | m4 \ 43 | *.loT \ 44 | *.ll *.ll.out \ 45 | *.gcda *.gcno *.gcov stringencoders.info \ 46 | modp_b16_data.h modp_b64_data.h modp_b85_data.h \ 47 | modp_b64w_data.h modp_b64w.c test/modp_b64w_test.c \ 48 | modp_b64r_data.h modp_b64r.c test/modp_b64r_test.c \ 49 | modp_ascii_data.h modp_b2_data.h \ 50 | modp_xml_test modp_qsiter_test modp_html_test modp_json_test \ 51 | cxx_test 52 | 53 | modp_b2.c: modp_b2.h modp_b2_data.h 54 | 55 | modp_b16.c: modp_b16.h modp_b16_data.h 56 | 57 | modp_b64.c: modp_b64.h modp_b64_data.h 58 | 59 | modp_b64r.c: modp_b64.c modp_b64r.h modp_b64r_data.h 60 | perl -p -i -e 's/b64/b64r/g' < modp_b64.c > modp_b64r.c 61 | 62 | modp_b64w.c: modp_b64.c modp_b64w.h modp_b64w_data.h 63 | perl -p -i -e 's/b64/b64w/g' < modp_b64.c > modp_b64w.c 64 | 65 | modp_b85.c: modp_b85.h modp_b85_data.h 66 | 67 | modp_burl.c: modp_burl.h modp_burl_data.h 68 | 69 | modp_bjavascript.c: modp_bjavascript.h modp_bjavascript_data.h 70 | 71 | modp_json.c: modp_json.h modp_json_data.h 72 | 73 | modp_ascii.c: modp_ascii.h modp_ascii_data.h 74 | 75 | modp_qsiter.c: modp_qsiter.h 76 | 77 | modp_xml.c: modp_xml.h 78 | 79 | modp_b2_data.h: modp_b2_gen 80 | ./modp_b2_gen > modp_b2_data.h 81 | 82 | modp_b16_data.h: modp_b16_gen 83 | ./modp_b16_gen > modp_b16_data.h 84 | 85 | modp_b64_data.h: modp_b64_gen 86 | ./modp_b64_gen > modp_b64_data.h 87 | 88 | modp_ascii_data.h: modp_ascii_gen 89 | ./modp_ascii_gen > modp_ascii_data.h 90 | 91 | # 92 | # Recall B64WCHARS by default is "-_." 93 | # 94 | modp_b64w_data.h: modp_b64_gen 95 | ./modp_b64_gen $(B64WCHARS) > modp_b64w_data.h 96 | 97 | # 98 | # RFC 4648 alphabet is -_= 99 | # http://www.ietf.org/rfc/rfc4648.txt 100 | modp_b64r_data.h: modp_b64_gen 101 | ./modp_b64_gen "-_=" > modp_b64r_data.h 102 | 103 | modp_b85_data.h: modp_b85_gen 104 | ./modp_b85_gen > modp_b85_data.h 105 | 106 | modp_burl_data.h: modp_burl_gen 107 | ./modp_burl_gen > modp_burl_data.h 108 | 109 | modp_bjavascript_data.h: modp_bjavascript_gen 110 | ./modp_bjavascript_gen > modp_bjavascript_data.h 111 | 112 | modp_json_data.h: modp_json_gen.py 113 | ./modp_json_gen.py 114 | 115 | noinst_PROGRAMS = \ 116 | modp_b2_gen modp_b16_gen modp_b64_gen modp_b85_gen \ 117 | modp_burl_gen modp_ascii_gen modp_bjavascript_gen 118 | 119 | modp_b2_gen_SOURCES = arraytoc.c modp_b2_gen.c 120 | 121 | modp_b16_gen_SOURCES = arraytoc.c modp_b16_gen.c 122 | 123 | modp_b64_gen_SOURCES = arraytoc.c modp_b64_gen.c 124 | 125 | modp_b85_gen_SOURCES = arraytoc.c modp_b85_gen.c 126 | 127 | modp_burl_gen_SOURCES = arraytoc.c modp_burl_gen.c 128 | 129 | modp_ascii_gen_SOURCES = arraytoc.c modp_ascii_gen.c 130 | 131 | modp_bjavascript_gen_SOURCES = arraytoc.c modp_bjavascript_gen.c 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/arraytoc.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | #include 3 | 4 | /* dump uint32_t as hex digits */ 5 | void uint32_array_to_c_hex(const uint32_t* ary, size_t sz, const char* name) 6 | { 7 | size_t i = 0; 8 | 9 | printf("static const uint32_t %s[%d] = {\n ", name, (int)sz); 10 | for (;;) { 11 | printf("0x%08x", ary[i]); 12 | ++i; 13 | if (i == sz) 14 | break; 15 | if (i % 6 == 0) { 16 | printf(",\n "); 17 | } else { 18 | printf(", "); 19 | } 20 | } 21 | printf("\n};\n"); 22 | } 23 | 24 | /** 25 | * prints char array as a c program snippet 26 | */ 27 | void char_array_to_c(const char* ary, size_t sz, const char* name) 28 | { 29 | uint8_t tmp; 30 | size_t i = 0; 31 | 32 | printf("static const uint8_t %s[%d] = {\n ", name, (int)sz); 33 | 34 | for (;;) { 35 | if (ary[i] == 0) { 36 | printf("'\\0'"); 37 | } else if (ary[i] == '\n') { 38 | printf("'\\n'"); 39 | } else if (ary[i] == '\t') { 40 | printf("'\\t'"); 41 | } else if (ary[i] == '\r') { 42 | printf("'\\r'"); 43 | } else if (ary[i] == '\'') { 44 | printf("'\\''"); 45 | } else if (ary[i] == '\\') { 46 | printf("'\\\\'"); 47 | } else if (ary[i] < 32 || ary[i] > 126) { 48 | tmp = (uint8_t)ary[i]; 49 | printf("0x%02x", tmp); 50 | } else { 51 | printf("'%c'", (char)ary[i]); 52 | } 53 | ++i; 54 | if (i == sz) 55 | break; 56 | if (i % 10 == 0) { 57 | printf(",\n "); 58 | } else { 59 | printf(", "); 60 | } 61 | } 62 | printf("\n};\n"); 63 | } 64 | 65 | /** 66 | * prints an uint array as a c program snippet 67 | */ 68 | void uint32_array_to_c(const uint32_t* ary, size_t sz, const char* name) 69 | { 70 | size_t i = 0; 71 | 72 | printf("static const uint32_t %s[%d] = {\n ", name, (int)sz); 73 | for (;;) { 74 | printf("%u", ary[i]); 75 | ++i; 76 | if (i == sz) 77 | break; 78 | if (i % 12 == 0) { 79 | printf(",\n "); 80 | } else { 81 | printf(", "); 82 | } 83 | } 84 | printf("\n};\n"); 85 | } 86 | -------------------------------------------------------------------------------- /src/arraytoc.h: -------------------------------------------------------------------------------- 1 | #ifndef COM_MODP_STRINGENCODERS_ARRAYTOC 2 | #define COM_MODP_STRINGENCODERS_ARRAYTOC 3 | 4 | #include "modp_stdint.h" 5 | 6 | #ifdef __cplusplus 7 | #define BEGIN_C extern "C" { 8 | #define END_C } 9 | #else 10 | #define BEGIN_C 11 | #define END_C 12 | #endif 13 | 14 | BEGIN_C 15 | 16 | /** \brief output a uint32_t array into source code 17 | * 18 | * 19 | * \param[in] ary the input array 20 | * \param[in] size number of elements in array 21 | * \param[in] name the name of the struct for the source code 22 | * 23 | */ 24 | void uint32_array_to_c(const uint32_t* ary, size_t size, const char* name); 25 | 26 | /** \brief output an uint32_t array into source code as hex values 27 | * 28 | * \param[in] ary the input array 29 | * \param[in] size number of elements in array 30 | * \param[in] name the name of the struct for source code 31 | * 32 | */ 33 | void uint32_array_to_c_hex(const uint32_t* ary, size_t size, const char* name); 34 | 35 | /** \brief output a char array into source code 36 | * 37 | * \param[in] ary the input array 38 | * \param[in] size number of elements in array 39 | * \param[in] name the name of the struct for source code 40 | */ 41 | void char_array_to_c(const char* ary, size_t size, const char* name); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/extern_c_begin.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | -------------------------------------------------------------------------------- /src/extern_c_end.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | } 3 | #endif 4 | -------------------------------------------------------------------------------- /src/html_named_entities_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | class Trie(object): 5 | def __init__(self): 6 | self.struct = [ 7 | [ ] 8 | ] 9 | 10 | def dump(self): 11 | count = 0 12 | for i in self.struct: 13 | count += len(i) 14 | print i 15 | print len(self.struct) 16 | print count 17 | 18 | def longest_match(self, s): 19 | """ 20 | sample code 21 | """ 22 | leaf = self.struct[0] 23 | matches = [] 24 | for ch in s: 25 | newleaf = None 26 | for node in leaf: 27 | if ch == node['value']: 28 | found = True 29 | if node['userdata'] is not None: 30 | matches.append(node['userdata']) 31 | if node['next'] == 0: 32 | return matches 33 | newleaf = self.struct[node['next']] 34 | break 35 | if newleaf: 36 | leaf = newleaf 37 | else: 38 | break 39 | return matches 40 | 41 | def compile(self): 42 | """ 43 | The current data struct is a a ragged array 44 | 0 - [ ] 45 | 1 - [ ] 46 | 2 - [ ] 47 | 3 - [ ] 48 | i.e. an array of vectors which are ugly to 49 | statically allocate in C 50 | http://stackoverflow.com/questions/1083658/jagged-array-in-c 51 | 52 | value, more, next, [userdata or 0] 53 | """ 54 | offsets = [ 0 ] 55 | count = 0 56 | for leaf in self.struct: 57 | count += len(leaf) 58 | offsets.append(count) 59 | print """ 60 | #ifndef _MODP_HTML_NAMED_ENTITIES_H 61 | #define _MODP_HTML_NAMED_ENTITIES_H 62 | #include 63 | 64 | typedef struct trienode { 65 | char value; /* 1 byte -- char value - we deal only in pure ASCII */ 66 | char more; /* 1 byte -- should be read next value in array (boundary marker) */ 67 | short next; /* 2 byte -- position of next leaf */ 68 | int codepoint; /* 4 byte -- codepoint or 0 if none */ 69 | } trienode_t; 70 | 71 | static const trienode_t entities[]; 72 | static int html_named_entity_decode(const char* s, size_t len, size_t* consumed); 73 | 74 | static int html_named_entity_decode(const char* s, size_t len, size_t* consumed) 75 | { 76 | int codepoint = 0; 77 | size_t pos = 0; 78 | int i = 0; 79 | 80 | *consumed = 0; 81 | 82 | while (pos < len) { 83 | if (s[pos] == entities[i].value) { 84 | if (entities[i].codepoint) { 85 | codepoint = entities[i].codepoint; 86 | *consumed = pos + 1; 87 | } 88 | if (entities[i].next != 0) { 89 | i = entities[i].next; 90 | pos += 1; 91 | continue; 92 | } else { 93 | break; 94 | } 95 | } 96 | if (entities[i].more == 0) { 97 | break; 98 | } 99 | ++i; 100 | } 101 | return codepoint; 102 | } 103 | /* 104 | #include 105 | int main(int argc, char* argv[]) { 106 | size_t consumed; 107 | int codepoint; 108 | codepoint = html_named_entity_decode(argv[1], strlen(argv[1]), &consumed); 109 | printf("cp = %d, consumed = %d\\n", codepoint, consumed); 110 | return 0; 111 | } 112 | */ 113 | static const trienode_t entities[] = { 114 | """ 115 | for leaf in self.struct: 116 | nodelen = 0 117 | for node in leaf: 118 | nodelen += 1 119 | if node['full'] != None: 120 | comment = ' /* &' + node['full'] + ' */' 121 | else: 122 | comment = '' 123 | 124 | print "{{ {0}, {1}, {2}, {3} }},{4}".format(ord(node['value']), 125 | int(nodelen != len(leaf)), 126 | offsets[node['next']], 127 | node['userdata'], 128 | comment 129 | ) 130 | print "};" 131 | print "#endif" 132 | 133 | def add(self, s, userdata): 134 | idx = 0 135 | leaf = self.struct[0] 136 | count = 0 137 | for ch in s[0:-1]: 138 | #print "CHAR " + i 139 | key = None 140 | for node in leaf: 141 | if ch == node['value']: 142 | key = node 143 | break 144 | if key is None: 145 | #print "key is none" 146 | newleaf = [ ] 147 | self.struct.append(newleaf) 148 | idx = len(self.struct) -1 149 | leaf.append( { 150 | "full": None, 151 | "value": ch, 152 | "userdata": 0, 153 | "next": idx 154 | } ) 155 | leaf = newleaf 156 | elif key['next'] != 0: 157 | # just follow 158 | #print "got key index of " + str(key[1]) 159 | leaf = self.struct[key['next']] 160 | else: 161 | newleaf = [ ] 162 | self.struct.append(newleaf) 163 | idx = len(self.struct) -1 164 | key['next'] = idx 165 | leaf = newleaf 166 | 167 | key = None 168 | ch = s[-1] 169 | for node in leaf: 170 | if ch == node['value']: 171 | key = node 172 | break 173 | if key is None: 174 | leaf.append( { 175 | 'full': s, 176 | 'userdata': userdata, 177 | 'next': 0, 178 | 'value': s[-1] 179 | }) 180 | else: 181 | key['full'] = s 182 | key['userdata'] = userdata 183 | 184 | 185 | 186 | import json 187 | with open('entities.json', 'r') as fd: 188 | obj = json.load(fd) 189 | 190 | t = Trie() 191 | total = 0 192 | for name, data in obj.iteritems(): 193 | total += len(name) -1 194 | t.add(name[1:], data['codepoints'][0]) 195 | 196 | #for i in ["fo", "fa", "foo"]: 197 | # t.add(i) 198 | 199 | #t.dump() 200 | #print t.longest_match("amp;") 201 | 202 | t.compile() 203 | 204 | -------------------------------------------------------------------------------- /src/modp_ascii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * modp_ascii.c 3 | *
      4 |  * MODP_ASCII - Ascii transformations (upper/lower, etc)
      5 |  * https://github.com/client9/stringencoders
      6 |  *
      7 |  * Copyright © 2007-16  Nick Galbreath -- nickg [at] client9 [dot] com
      8 |  * MIT LICENSE
      9 |  *
     10 |  * 
    11 | */ 12 | 13 | #include "modp_ascii.h" 14 | #include "modp_ascii_data.h" 15 | #include "modp_stdint.h" 16 | 17 | void modp_toupper_copy(char* dest, const char* str, size_t len) 18 | { 19 | size_t i; 20 | uint32_t eax, ebx; 21 | const uint8_t* ustr = (const uint8_t*)str; 22 | const size_t leftover = len % 4; 23 | const size_t imax = len / 4; 24 | const uint32_t* s = (const uint32_t*)str; 25 | uint32_t* d = (uint32_t*)dest; 26 | for (i = 0; i != imax; ++i) { 27 | eax = s[i]; 28 | /* 29 | * This is based on the algorithm by Paul Hsieh 30 | * http://www.azillionmonkeys.com/qed/asmexample.html 31 | */ 32 | ebx = (0x7f7f7f7fu & eax) + 0x05050505u; 33 | ebx = (0x7f7f7f7fu & ebx) + 0x1a1a1a1au; 34 | ebx = ((ebx & ~eax) >> 2) & 0x20202020u; 35 | *d++ = eax - ebx; 36 | } 37 | 38 | i = imax * 4; 39 | dest = (char*)d; 40 | switch (leftover) { 41 | case 3: 42 | *dest++ = (char)gsToUpperMap[ustr[i++]]; 43 | /* fall through */ 44 | case 2: 45 | *dest++ = (char)gsToUpperMap[ustr[i++]]; 46 | /* fall through */ 47 | case 1: 48 | *dest++ = (char)gsToUpperMap[ustr[i]]; 49 | /* fall through */ 50 | case 0: 51 | *dest = '\0'; 52 | } 53 | } 54 | 55 | void modp_tolower_copy(char* dest, const char* str, size_t len) 56 | { 57 | size_t i; 58 | uint32_t eax, ebx; 59 | const uint8_t* ustr = (const uint8_t*)str; 60 | const size_t leftover = len % 4; 61 | const size_t imax = len / 4; 62 | const uint32_t* s = (const uint32_t*)str; 63 | uint32_t* d = (uint32_t*)dest; 64 | for (i = 0; i != imax; ++i) { 65 | eax = s[i]; 66 | /* 67 | * This is based on the algorithm by Paul Hsieh 68 | * http://www.azillionmonkeys.com/qed/asmexample.html 69 | */ 70 | ebx = (0x7f7f7f7fu & eax) + 0x25252525u; 71 | ebx = (0x7f7f7f7fu & ebx) + 0x1a1a1a1au; 72 | ebx = ((ebx & ~eax) >> 2) & 0x20202020u; 73 | *d++ = eax + ebx; 74 | } 75 | 76 | i = imax * 4; 77 | dest = (char*)d; 78 | switch (leftover) { 79 | case 3: 80 | *dest++ = (char)gsToLowerMap[ustr[i++]]; 81 | /* fall through */ 82 | case 2: 83 | *dest++ = (char)gsToLowerMap[ustr[i++]]; 84 | /* fall through */ 85 | case 1: 86 | *dest++ = (char)gsToLowerMap[ustr[i]]; 87 | /* fall through */ 88 | case 0: 89 | *dest = '\0'; 90 | } 91 | } 92 | 93 | void modp_toupper(char* str, size_t len) 94 | { 95 | modp_toupper_copy(str, str, len); 96 | } 97 | 98 | void modp_tolower(char* str, size_t len) 99 | { 100 | modp_tolower_copy(str, str, len); 101 | } 102 | 103 | void modp_toprint_copy(char* dest, const char* str, size_t len) 104 | { 105 | size_t i; 106 | uint8_t c1, c2, c3, c4; 107 | 108 | const size_t leftover = len % 4; 109 | const size_t imax = len - leftover; 110 | const uint8_t* s = (const uint8_t*)str; 111 | for (i = 0; i != imax; i += 4) { 112 | /* 113 | * it's important to make these variables 114 | * it helps the optimizer to figure out what to do 115 | */ 116 | c1 = s[i]; 117 | c2 = s[i + 1]; 118 | c3 = s[i + 2]; 119 | c4 = s[i + 3]; 120 | dest[0] = (char)gsToPrintMap[c1]; 121 | dest[1] = (char)gsToPrintMap[c2]; 122 | dest[2] = (char)gsToPrintMap[c3]; 123 | dest[3] = (char)gsToPrintMap[c4]; 124 | dest += 4; 125 | } 126 | 127 | switch (leftover) { 128 | case 3: 129 | *dest++ = (char)gsToPrintMap[s[i++]]; 130 | /* fall through */ 131 | case 2: 132 | *dest++ = (char)gsToPrintMap[s[i++]]; 133 | /* fall through */ 134 | case 1: 135 | *dest++ = (char)gsToPrintMap[s[i]]; 136 | /* fall through */ 137 | case 0: 138 | *dest = '\0'; 139 | } 140 | } 141 | 142 | void modp_toprint(char* str, size_t len) 143 | { 144 | modp_toprint_copy(str, str, len); 145 | } 146 | 147 | size_t modp_rtrim(char* str, size_t len) 148 | { 149 | while (len) { 150 | char c = str[len - 1]; 151 | if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { 152 | str[len - 1] = '\0'; 153 | len -= 1; 154 | } else { 155 | break; 156 | } 157 | } 158 | return len; 159 | } 160 | -------------------------------------------------------------------------------- /src/modp_ascii.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_ascii.h 3 | * \brief Simple ASCII manipulations including upper and lower casing, 4 | * white space trimming, and conversion to "printable" characters. 5 | * 6 | * blah blah blah 7 | */ 8 | 9 | /* 10 | *
     11 |  * MODP_ASCII -- Simple ascii manipulation (uppercase, lowercase, etc)
     12 |  * https://github.com/client9/stringencoders
     13 |  *
     14 |  * Copyright © 2007-2016, Nick Galbreath -- nickg [at] client9 [dot] com
     15 |  * All rights reserved.
     16 |  *
     17 |  * Released under MIT license.  See LICENSE for details.
     18 |  * 
    19 | * 20 | */ 21 | 22 | #ifndef COM_MODP_STRINGENCODERS_ASCII 23 | #define COM_MODP_STRINGENCODERS_ASCII 24 | 25 | #include "extern_c_begin.h" 26 | #include "modp_stdint.h" 27 | 28 | /* 29 | * \param[in,out] str the input string 30 | * \param[in] len the length of input string (the strlen) 31 | */ 32 | void modp_toupper(char* str, size_t len); 33 | 34 | /** \brief make lower case copy of input string 35 | * 36 | * \param[out] dest output buffer, with at least 'len + 1' bytes allocated 37 | * \param[in] str the input string 38 | * \param[in] len the length of input string (the strlen) 39 | * 40 | * Please make sure dest has been allocation with at least 'len+1' 41 | * bytes. This appends a trailing NULL character at the end of 42 | * dest! 43 | * 44 | * This is based on the algorithm by Paul Hsieh 45 | * http://www.azillionmonkeys.com/qed/asmexample.html 46 | */ 47 | void modp_toupper_copy(char* dest, const char* str, size_t len); 48 | 49 | /** \brief lower case a string in place 50 | * 51 | * \param[in,out] str the input string 52 | * \param[in] len the length of input string (the strlen) 53 | * 54 | */ 55 | void modp_tolower(char* str, size_t len); 56 | 57 | /** \brief make lower case copy of input string 58 | * 59 | * \param[out] dest output buffer, with at least 'len + 1' bytes allocated 60 | * \param[in] str the input string 61 | * \param[in] len the length of input string (the strlen) 62 | * 63 | * Please make sure dest has been allocation with at least 'len+1' 64 | * bytes. This appends a trailing NULL character at the end of 65 | * dest! 66 | * 67 | * This is based on the algorithm by Paul Hsieh 68 | * http://www.azillionmonkeys.com/qed/asmexample.html 69 | */ 70 | void modp_tolower_copy(char* dest, const char* str, size_t len); 71 | 72 | /** \brief turn a string into 7-bit printable ascii. 73 | * 74 | * By "printable" we means all characters between 32 and 126. 75 | * All other values are turned into '?' 76 | * 77 | * \param[in,out] str the input string 78 | * \param[in] len the length of input string (the strlen) 79 | * 80 | */ 81 | void modp_toprint(char* str, size_t len); 82 | 83 | /** \brief make a printable copy of a string 84 | * 85 | * By "printable" we means all characters between 32 and 126. 86 | * All other values are turned into '?' 87 | * 88 | * \param[out] dest output buffer, with at least 'len + 1' bytes allocated 89 | * \param[in] str the input string 90 | * \param[in] len the length of input string (the strlen) 91 | * 92 | * Please make sure dest has been allocation with at least 'len+1' 93 | * bytes. This appends a trailing NULL character at the end of 94 | * dest! 95 | */ 96 | void modp_toprint_copy(char* dest, const char* str, size_t len); 97 | 98 | /** 99 | * \brief remove trailing whitespace from a string 100 | * \param[in,out] str string to be stripped 101 | * \param[in] len the size of the input 102 | * \return the size of the output, not including any ending null byte. 103 | */ 104 | size_t modp_rtrim(char* str, size_t len); 105 | 106 | #include "extern_c_end.h" 107 | 108 | #ifdef __cplusplus 109 | #include 110 | 111 | namespace modp { 112 | 113 | inline std::string& toupper(std::string& str) 114 | { 115 | modp_toupper(const_cast(str.c_str()), str.size()); 116 | return str; 117 | } 118 | 119 | inline std::string toupper(const std::string& str) 120 | { 121 | std::string s(str.size(), '\0'); 122 | modp_toupper_copy(const_cast(s.data()), str.data(), str.size()); 123 | return s; 124 | } 125 | 126 | inline std::string tolower(const std::string& str) 127 | { 128 | std::string s(str.size(), '\0'); 129 | modp_tolower_copy(const_cast(s.data()), str.data(), str.size()); 130 | return s; 131 | } 132 | 133 | inline std::string& tolower(std::string& str) 134 | { 135 | modp_tolower(const_cast(str.c_str()), str.size()); 136 | return str; 137 | } 138 | 139 | inline std::string toprint(const std::string& str) 140 | { 141 | std::string s(str.size(), '\0'); 142 | modp_toprint_copy(const_cast(s.data()), str.data(), str.size()); 143 | return s; 144 | } 145 | 146 | inline std::string& toprint(std::string& str) 147 | { 148 | modp_toprint(const_cast(str.c_str()), str.size()); 149 | return str; 150 | } 151 | 152 | inline std::string& rtrim(std::string& s) 153 | { 154 | size_t d = modp_rtrim(const_cast(s.data()), s.size()); 155 | s.erase(d, std::string::npos); 156 | return s; 157 | } 158 | } 159 | 160 | #endif /* __cplusplus */ 161 | 162 | #endif /* MODP_ASCII */ 163 | -------------------------------------------------------------------------------- /src/modp_ascii_gen.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | #include 3 | 4 | static void modp_toupper_map(void) 5 | { 6 | size_t i = 0; 7 | char map[256]; 8 | for (i = 0; i < sizeof(map); ++i) { 9 | if (i >= 'a' && i <= 'z') { 10 | map[i] = (char)(i - 32); 11 | } else { 12 | map[i] = (char)(i); 13 | } 14 | } 15 | 16 | char_array_to_c(map, sizeof(map), "gsToUpperMap"); 17 | } 18 | 19 | static void modp_tolower_map(void) 20 | { 21 | size_t i = 0; 22 | char map[256]; 23 | for (i = 0; i < sizeof(map); ++i) { 24 | if (i >= 'A' && i <= 'Z') { 25 | map[i] = (char)(i + 32); 26 | } else { 27 | map[i] = (char)i; 28 | } 29 | } 30 | 31 | char_array_to_c(map, sizeof(map), "gsToLowerMap"); 32 | } 33 | 34 | static void modp_toprint_map(void) 35 | { 36 | size_t i = 0; 37 | char map[256]; 38 | for (i = 0; i < sizeof(map); ++i) { 39 | if (i < 32 || i > 126) { 40 | map[i] = '?'; 41 | } else { 42 | map[i] = (char)i; 43 | } 44 | } 45 | 46 | char_array_to_c(map, sizeof(map), "gsToPrintMap"); 47 | } 48 | 49 | int main(void) 50 | { 51 | modp_toupper_map(); 52 | modp_tolower_map(); 53 | modp_toprint_map(); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/modp_b16.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | *
      4 |  * MODP_B16 - High performance base16 encoder/decoder
      5 |  * https://github.com/client9/stringencoders
      6 |  *
      7 |  * Copyright © 2005-2016  Nick Galbreath
      8 |  * All rights reserved.
      9 |  * Released under MIT license. See LICENSE for details.
     10 |  * 
    11 | */ 12 | #include "modp_b16.h" 13 | #include "config.h" 14 | #include "modp_b16_data.h" 15 | #include "modp_stdint.h" 16 | 17 | size_t modp_b16_encode(char* dest, const char* str, size_t len) 18 | { 19 | size_t i; 20 | const size_t buckets = len >> 2; /* i.e. i / 4 */ 21 | const size_t leftover = len & 0x03; /* i.e. i % 4 */ 22 | const uint8_t* srcChar; 23 | uint8_t* p = (uint8_t*)dest; 24 | uint8_t t1, t2, t3, t4; 25 | const uint32_t* srcInt = (const uint32_t*)str; 26 | uint32_t x; 27 | for (i = 0; i < buckets; ++i) { 28 | x = *srcInt++; 29 | /* t1 = *s++; t2 = *s++; t3 = *s++; t4 = *s++; */ 30 | #ifdef WORDS_BIGENDIAN 31 | t1 = (uint8_t)(x >> 24); 32 | t2 = (uint8_t)(x >> 16); 33 | t3 = (uint8_t)(x >> 8); 34 | t4 = (uint8_t)x; 35 | #else 36 | t4 = (uint8_t)(x >> 24); 37 | t3 = (uint8_t)(x >> 16); 38 | t2 = (uint8_t)(x >> 8); 39 | t1 = (uint8_t)x; 40 | #endif 41 | *p++ = gsHexEncodeC1[t1]; 42 | *p++ = gsHexEncodeC2[t1]; 43 | *p++ = gsHexEncodeC1[t2]; 44 | *p++ = gsHexEncodeC2[t2]; 45 | *p++ = gsHexEncodeC1[t3]; 46 | *p++ = gsHexEncodeC2[t3]; 47 | *p++ = gsHexEncodeC1[t4]; 48 | *p++ = gsHexEncodeC2[t4]; 49 | } 50 | 51 | srcChar = (const uint8_t*)srcInt; 52 | switch (leftover) { 53 | case 0: 54 | break; 55 | case 1: 56 | t1 = (uint8_t)*srcChar; 57 | *p++ = gsHexEncodeC1[t1]; 58 | *p++ = gsHexEncodeC2[t1]; 59 | break; 60 | case 2: 61 | t1 = (uint8_t)*srcChar++; 62 | t2 = (uint8_t)*srcChar; 63 | *p++ = gsHexEncodeC1[t1]; 64 | *p++ = gsHexEncodeC2[t1]; 65 | *p++ = gsHexEncodeC1[t2]; 66 | *p++ = gsHexEncodeC2[t2]; 67 | break; 68 | default: /* case 3 */ 69 | t1 = (uint8_t)*srcChar++; 70 | t2 = (uint8_t)*srcChar++; 71 | t3 = (uint8_t)*srcChar; 72 | *p++ = gsHexEncodeC1[t1]; 73 | *p++ = gsHexEncodeC2[t1]; 74 | *p++ = gsHexEncodeC1[t2]; 75 | *p++ = gsHexEncodeC2[t2]; 76 | *p++ = gsHexEncodeC1[t3]; 77 | *p++ = gsHexEncodeC2[t3]; 78 | } 79 | *p = '\0'; 80 | return (size_t)(p - (uint8_t*)dest); 81 | } 82 | 83 | size_t modp_b16_decode(char* dest, const char* str, size_t len) 84 | { 85 | size_t i; 86 | uint8_t t0, t1, t2, t3; 87 | uint8_t* p = (uint8_t*)dest; 88 | uint32_t val1, val2; 89 | const uint8_t* s = (const uint8_t*)str; 90 | const size_t buckets = len >> 2; /* i.e. len / 4 */ 91 | const size_t leftover = len & 0x03; /* i.e. len % 4 */ 92 | if (leftover & 0x01) { /* i.e if leftover is odd, */ 93 | /* leftover==1 || leftover == 3 */ 94 | return (size_t)-1; 95 | } 96 | 97 | /* read 4 bytes, output 2. 98 | * Note on PPC G4, GCC 4.0, it's quite a bit faster to 99 | * NOT use t0,t1,t2,t3, and just put the *s++ in the gsHexDecodeMap 100 | * lookup 101 | */ 102 | for (i = 0; i < buckets; ++i) { 103 | t0 = *s++; 104 | t1 = *s++; 105 | t2 = *s++; 106 | t3 = *s++; 107 | val1 = gsHexDecodeD2[t0] | gsHexDecodeMap[t1]; 108 | val2 = gsHexDecodeD2[t2] | gsHexDecodeMap[t3]; 109 | if (val1 > 0xff || val2 > 0xff) { 110 | return (size_t)-1; 111 | } 112 | *p++ = (uint8_t)val1; 113 | *p++ = (uint8_t)val2; 114 | } 115 | 116 | if (leftover == 2) { 117 | val1 = gsHexDecodeD2[s[0]] | gsHexDecodeMap[s[1]]; 118 | if (val1 > 0xff) { 119 | return (size_t)-1; 120 | } 121 | *p++ = (uint8_t)val1; 122 | } 123 | 124 | return (size_t)(p - (uint8_t*)dest); 125 | } 126 | -------------------------------------------------------------------------------- /src/modp_b16.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_b16.h 3 | * \brief High performance encoding and decoding of base 16 4 | * (hexadecimal 0-9, A-F) 5 | * 6 | */ 7 | 8 | /* 9 | *
     10 |  * MODP_B16 -- High performance base16 (hex) Encoder/Decoder
     11 |  * https://github.com/client9/stringencoders
     12 |  *
     13 |  * Copyright © 2005-2016, Nick Galbreath
     14 |  * All rights reserved.
     15 |  *
     16 |  * Released under MIT license.  See LICENSE for details.
     17 |  * 
    18 | * 19 | */ 20 | 21 | #ifndef COM_MODP_STRINGENCODERS_B16 22 | #define COM_MODP_STRINGENCODERS_B16 23 | 24 | #include "extern_c_begin.h" 25 | #include "modp_stdint.h" 26 | 27 | /** 28 | * encode a string into hex (base 16, 0-9,a-f) 29 | * 30 | * \param[out] dest the output string. Must have at least modp_b16_encode_len 31 | * bytes allocated 32 | * \param[in] str the input string 33 | * \param[in] len of the input string 34 | * \return strlen of dest 35 | */ 36 | size_t modp_b16_encode(char* dest, const char* str, size_t len); 37 | 38 | /** 39 | * Decode a hex-encoded string. 40 | * 41 | * \param[out] dest output, must have at least modp_b16_decode_len bytes allocated, 42 | * input must be a multiple of 2, and be different than the source buffer. 43 | * \param[in] src the hex encoded source 44 | * \param[in] len the length of the source 45 | * \return the length of the the output, or -1 if an error 46 | */ 47 | size_t modp_b16_decode(char* dest, const char* src, size_t len); 48 | 49 | /** 50 | * Encode length. 51 | * 2 x the length of A, round up the next high multiple of 2 52 | * +1 for null byte added 53 | */ 54 | #define modp_b16_encode_len(A) (2 * A + 1) 55 | 56 | /** 57 | * Encode string length 58 | */ 59 | #define modp_b16_encode_strlen(A) (2 * A) 60 | 61 | /** 62 | * Decode string length 63 | */ 64 | #define modp_b16_decode_len(A) ((A + 1) / 2) 65 | 66 | #include "extern_c_end.h" 67 | 68 | #ifdef __cplusplus 69 | #include 70 | #include 71 | 72 | namespace modp { 73 | 74 | inline std::string b16_encode(const char* s, size_t len) 75 | { 76 | std::string x(modp_b16_encode_len(len), '\0'); 77 | size_t d = modp_b16_encode(const_cast(x.data()), s, len); 78 | if (d == (size_t)-1) { 79 | x.clear(); 80 | } else { 81 | x.erase(d, std::string::npos); 82 | } 83 | return x; 84 | } 85 | 86 | inline std::string b16_encode(const char* s) 87 | { 88 | return b16_encode(s, strlen(s)); 89 | } 90 | 91 | inline std::string b16_encode(const std::string& s) 92 | { 93 | return b16_encode(s.data(), s.size()); 94 | } 95 | 96 | /** 97 | * hex encode a string (self-modified) 98 | * \param[in,out] s the input string to be encoded 99 | * \return a reference to the input string. 100 | */ 101 | inline std::string& b16_encode(std::string& s) 102 | { 103 | std::string x(b16_encode(s.data(), s.size())); 104 | s.swap(x); 105 | return s; 106 | } 107 | 108 | inline std::string b16_decode(const char* s, size_t len) 109 | { 110 | std::string x(len / 2 + 1, '\0'); 111 | size_t d = modp_b16_decode(const_cast(x.data()), s, len); 112 | if (d == (size_t)-1) { 113 | x.clear(); 114 | } else { 115 | x.erase(d, std::string::npos); 116 | } 117 | return x; 118 | } 119 | 120 | inline std::string b16_decode(const char* s) 121 | { 122 | return b16_decode(s, strlen(s)); 123 | } 124 | 125 | /** 126 | * Decode a hex-encoded string. On error, input string is cleared. 127 | * This function does not allocate memory. 128 | * 129 | * \param[in,out] s the input string 130 | * \return a reference to the input string 131 | */ 132 | inline std::string& b16_decode(std::string& s) 133 | { 134 | std::string x(b16_decode(s.data(), s.size())); 135 | s.swap(x); 136 | return s; 137 | } 138 | 139 | inline std::string b16_decode(const std::string& s) 140 | { 141 | return b16_decode(s.data(), s.size()); 142 | } 143 | 144 | } /* namespace modp */ 145 | 146 | #endif /* ifdef __cplusplus */ 147 | 148 | #endif /* ifndef modp_b16 */ 149 | -------------------------------------------------------------------------------- /src/modp_b16_gen.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | #include 3 | 4 | static void hexencodemap_char(void) 5 | { 6 | static const uint8_t sHexChars[] = "0123456789ABCDEF"; 7 | int i; 8 | uint8_t e1[256]; 9 | uint8_t e2[256]; 10 | 11 | for (i = 0; i < 256; ++i) { 12 | e1[i] = 0; 13 | e2[i] = 0; 14 | } 15 | 16 | for (i = 0; i < 256; ++i) { 17 | e1[i] = sHexChars[i >> 4]; 18 | e2[i] = sHexChars[i & 0x0f]; 19 | } 20 | 21 | char_array_to_c((char*)e1, sizeof(e1), "gsHexEncodeC1"); 22 | char_array_to_c((char*)e2, sizeof(e2), "gsHexEncodeC2"); 23 | } 24 | 25 | /* exact same thing as one used on urlencode */ 26 | static void hexdecodemap(void) 27 | { 28 | uint32_t i; 29 | uint32_t map1[256]; 30 | uint32_t map2[256]; 31 | for (i = 0; i < 256; ++i) { 32 | map1[i] = 256; 33 | map2[i] = 256; 34 | } 35 | 36 | /* digits */ 37 | for (i = '0'; i <= '9'; ++i) { 38 | map1[i] = i - '0'; 39 | map2[i] = map1[i] << 4; 40 | } 41 | 42 | /* upper */ 43 | for (i = 'A'; i <= 'F'; ++i) { 44 | map1[i] = i - 'A' + 10; 45 | map2[i] = map1[i] << 4; 46 | } 47 | 48 | /* lower */ 49 | for (i = 'a'; i <= 'f'; ++i) { 50 | map1[i] = i - 'a' + 10; 51 | map2[i] = map1[i] << 4; 52 | } 53 | 54 | uint32_array_to_c(map1, sizeof(map1) / sizeof(uint32_t), "gsHexDecodeMap"); 55 | 56 | uint32_array_to_c(map2, sizeof(map2) / sizeof(uint32_t), "gsHexDecodeD2"); 57 | } 58 | 59 | int main(void) 60 | { 61 | hexencodemap_char(); 62 | 63 | hexdecodemap(); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/modp_b2.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ 2 | /* vi: set expandtab shiftwidth=4 tabstop=4: */ 3 | 4 | /** 5 | * \file modp_b2.c 6 | *
     7 |  * MODP_B2 - Ascii Binary string encode/decode
     8 |  * https://github.com/client9/stringencoders
     9 |  *
    10 |  * Copyright © 2005-2016  Nick Galbreath
    11 |  * All rights reserved.
    12 |  *
    13 |  * Released under MIT license. See LICENSE for details.
    14 |  *
    15 |  */
    16 | #include "modp_b2.h"
    17 | #include "config.h"
    18 | #include "modp_b2_data.h"
    19 | #include "modp_stdint.h"
    20 | #include 
    21 | 
    22 | size_t modp_b2_encode(char* dest, const char* str, size_t len)
    23 | {
    24 |     const uint8_t* orig = (const uint8_t*)str;
    25 | #if 0
    26 |     /* THIS IS A STANDARD VERSION */
    27 |     static const uint8_t gsBinaryChars[] = "01";
    28 |     int i,j;
    29 |     for (i = 0; i < len; ++i) {
    30 |         for (j = 0; j <= 7; ++j) {
    31 |             *dest++ = gsBinaryChars[(orig[i] >> (7-j)) & 1];
    32 |         }
    33 |     }
    34 | #else
    35 |     /* THIS IS 10X FASTER */
    36 |     size_t i;
    37 |     for (i = 0; i < len; ++i) {
    38 |         memcpy((void*)dest, modp_b2_encodemap[orig[i]], (size_t)8);
    39 |         dest += 8;
    40 |     }
    41 | #endif
    42 |     *dest = '\0';
    43 |     return len * 8;
    44 | }
    45 | 
    46 | size_t modp_b2_decode(char* dest, const char* str, size_t len)
    47 | {
    48 |     char d;
    49 |     size_t i;
    50 |     int j;
    51 |     const size_t buckets = len / 8;
    52 |     const size_t leftover = len % 8;
    53 |     if (leftover != 0) {
    54 |         return (size_t)-1;
    55 |     }
    56 | 
    57 |     for (i = 0; i < buckets; ++i) {
    58 |         d = 0;
    59 |         for (j = 0; j <= 7; ++j) {
    60 |             char c = *str++;
    61 |             if (c == '1') {
    62 |                 d ^= (char)(1 << (7 - j));
    63 |             }
    64 |         }
    65 |         *dest++ = d;
    66 |     }
    67 | 
    68 |     return buckets;
    69 | }
    70 | 
    
    
    --------------------------------------------------------------------------------
    /src/modp_b2.h:
    --------------------------------------------------------------------------------
      1 | /**
      2 |  * \file modp_b2.h
      3 |  * \brief Encode and decode of base 2 strings ("00001110" to 0x43)
      4 |  *
      5 |  */
      6 | 
      7 | /*
      8 |  * 
      9 |  * MODP_B2 -- Base 2 (binary) encode/decoder
     10 |  * https://github.com/client9/stringencoders
     11 |  *
     12 |  * Copyright © 2007-2016, Nick Galbreath
     13 |  * All rights reserved.
     14 |  *
     15 |  * Released under MIT license.  See LICENSE for details.
     16 |  * 
    17 | * 18 | */ 19 | 20 | #ifndef COM_MODP_STRINGENCODERS_B2 21 | #define COM_MODP_STRINGENCODERS_B2 22 | 23 | #include "extern_c_begin.h" 24 | #include "modp_stdint.h" 25 | 26 | /** 27 | * encode a string into binary (base 2, '0' and '1') 28 | * 29 | * \param[out] dest the output string. Must have at least modp_b16_encode_len 30 | * bytes allocated 31 | * \param[in] str the input string 32 | * \param[in] len of the input string 33 | * \return strlen of dest 34 | */ 35 | size_t modp_b2_encode(char* dest, const char* str, size_t len); 36 | 37 | /** 38 | * Decode a hex-encoded string. 39 | * 40 | * \param[out] dest output, must have at least modp_b16_decode_len bytes allocated, 41 | * input must be a multiple of 2, and be different than the source buffer. 42 | * \param[in] src the hex encoded source 43 | * \param[in] len the length of the source 44 | * \return the length of the the output, or 0 if an error (input size not a multiple of 8) 45 | */ 46 | size_t modp_b2_decode(char* dest, const char* src, size_t len); 47 | 48 | /** 49 | * Encode length. 50 | * 2 x the length of A, round up the next high multiple of 2 51 | * +1 for null byte added 52 | */ 53 | #define modp_b2_encode_len(A) (8 * A + 1) 54 | 55 | /** 56 | * Encode string length 57 | */ 58 | #define modp_b2_encode_strlen(A) (8 * A) 59 | 60 | /** 61 | * Decode string length 62 | */ 63 | #define modp_b2_decode_len(A) ((A + 1) / 8) 64 | 65 | #include "extern_c_end.h" 66 | 67 | #ifdef __cplusplus 68 | #include 69 | 70 | namespace modp { 71 | /** 72 | * hex encode a string (self-modified) 73 | * \param[in,out] s the input string to be encoded 74 | * \return a reference to the input string. 75 | */ 76 | inline std::string& b2_encode(std::string& s) 77 | { 78 | std::string x(modp_b2_encode_len(s.size()), '\0'); 79 | size_t d = modp_b2_encode(const_cast(x.data()), s.data(), s.size()); 80 | if (d == (size_t)-1) { 81 | x.clear(); 82 | } else { 83 | x.erase(d, std::string::npos); 84 | } 85 | s.swap(x); 86 | return s; 87 | } 88 | 89 | /** 90 | * 91 | * \param[in] s original data source 92 | * \return new b2 encoding string 93 | */ 94 | inline std::string b2_encode(const std::string& s) 95 | { 96 | std::string str(s); 97 | b2_encode(str); 98 | return str; 99 | } 100 | 101 | /** 102 | * Decode a hex-encoded string. On error, input string is cleared. 103 | * This function does not allocate memory. 104 | * 105 | * \param[in,out] s the input string 106 | * \return a reference to the input string 107 | */ 108 | inline std::string& b2_decode(std::string& s) 109 | { 110 | size_t d = modp_b2_decode(const_cast(s.data()), s.data(), s.size()); 111 | if (d == (size_t)-1) { 112 | s.clear(); 113 | } else { 114 | s.erase(d, std::string::npos); 115 | } 116 | return s; 117 | } 118 | 119 | inline std::string b2_decode(const std::string& s) 120 | { 121 | std::string x(s); 122 | b2_decode(x); 123 | return x; 124 | } 125 | 126 | } /* namespace modp */ 127 | 128 | #endif /* cplusplus */ 129 | 130 | #endif /* ifndef modp_b2 */ 131 | -------------------------------------------------------------------------------- /src/modp_b2_gen.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | #include 3 | 4 | /** \brief make map of a byte to a string of 8 chars 5 | * 6 | * 7 | */ 8 | static void binary_encodemap(void) 9 | { 10 | static const uint8_t sBinaryChars[] = "01"; 11 | int i, j; 12 | uint8_t buf[9]; 13 | 14 | printf("%s", "static const char* modp_b2_encodemap[] = {\n"); 15 | buf[8] = 0; 16 | for (i = 0; i < 256; ++i) { 17 | for (j = 0; j < 8; ++j) { 18 | buf[j] = sBinaryChars[(i >> (7 - j)) & 1]; 19 | } 20 | printf("\"%s\"", buf); 21 | if (i != 255) { 22 | printf("%s", ", "); 23 | } 24 | if ((i + 1) % 6 == 0) { 25 | printf("%s", "\n"); 26 | } 27 | } 28 | printf("%s", "};\n"); 29 | } 30 | 31 | int main(void) 32 | { 33 | binary_encodemap(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/modp_b36.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | *
      4 |  * MODP_B36 - High performance base36 encoder/decoder
      5 |  * https://github.com/client9/stringencoders
      6 |  *
      7 |  * Copyright © 2006-2016  Nick Galbreath
      8 |  * All rights reserved.
      9 |  *
     10 |  * Released under MIT license. See LICENSE for details.
     11 |  * 
    12 | */ 13 | 14 | /* exported public header */ 15 | #include "modp_b36.h" 16 | #include "modp_stdint.h" 17 | /* private header */ 18 | #include "modp_b36_data.h" 19 | 20 | /* 21 | * Might need changing depending on platform 22 | * we need htonl, and ntohl 23 | */ 24 | #include 25 | 26 | /** 27 | * you can decode IN PLACE! 28 | * no memory allocated 29 | */ 30 | size_t modp_b36_decode(char* out, const char* data, size_t len) 31 | { 32 | size_t i; 33 | int j; 34 | const size_t buckets = len / 7; 35 | const uint8_t* d2 = (const uint8_t*)data; 36 | if (len % 7 != 0) { 37 | return (size_t)-1; 38 | } 39 | 40 | uint32_t* o2 = (uint32_t*)out; 41 | for (i = 0; i < buckets; ++i) { 42 | uint32_t tmp = 0; 43 | for (j = 0; j < 7; ++j) { 44 | uint32_t digit = gsCharToInt[(uint32_t)*d2++]; 45 | if (digit >= 36) { 46 | return (size_t)-1; 47 | } 48 | tmp = tmp * 36 + digit; 49 | } 50 | *o2++ = htonl(tmp); 51 | } 52 | return 4 * buckets; 53 | } 54 | 55 | /** 56 | * src != out 57 | */ 58 | size_t modp_b36_encode(char* out, const char* src, size_t len) 59 | { 60 | const uint32_t* sary = (const uint32_t*)src; 61 | const size_t buckets = len / 4; 62 | if (len % 4 != 0) { 63 | return (size_t)-1; 64 | } 65 | 66 | size_t i; 67 | for (i = 0; i < buckets; ++i) { 68 | uint32_t tmp = *sary++; 69 | tmp = htonl(tmp); 70 | 71 | /* this crazy function */ 72 | #if 0 73 | *out++ = (char)gsIntToChar[(tmp / 52200625)]; // don't need % 36 here, always < 36 74 | *out++ = (char)gsIntToChar[(tmp / 614125) % 36]; 75 | *out++ = (char)gsIntToChar[(tmp / 7225) % 36]; 76 | *out++ = (char)gsIntToChar[(tmp / 36) % 36]; 77 | *out++ = (char)gsIntToChar[tmp % 36]; 78 | #else 79 | /* is really this */ 80 | *(out + 6) = gsIntToChar[tmp % 36]; 81 | tmp /= 36; 82 | *(out + 5) = gsIntToChar[tmp % 36]; 83 | tmp /= 36; 84 | *(out + 4) = gsIntToChar[tmp % 36]; 85 | tmp /= 36; 86 | *(out + 3) = gsIntToChar[tmp % 36]; 87 | tmp /= 36; 88 | *(out + 2) = gsIntToChar[tmp % 36]; 89 | tmp /= 36; 90 | *(out + 1) = gsIntToChar[tmp % 36]; 91 | tmp /= 36; 92 | *out = gsIntToChar[tmp]; 93 | out += 7; 94 | #endif 95 | // NOTES 96 | // Version 1 under -O3 is about 10-20 PERCENT faster than version 2 97 | // BUT Version 1 is 10 TIMES SLOWER when used with -Os !!! 98 | // Reason: gcc does a lot of tricks to remove the divisions 99 | // op with multiplies and shift. 100 | // In V1 with -O3 this works. Under -Os it reverts to very 101 | // slow division. 102 | // In V2 -O3 it does the same thing, but under Os, it's smart 103 | // enough to know we want the quotient and remainder and only 104 | // one div call per line. 105 | } 106 | *out = 0; // final null 107 | return buckets * 7; 108 | } 109 | -------------------------------------------------------------------------------- /src/modp_b36.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_b36.h 3 | * \brief Base 36 encoding and decoding 4 | * 5 | * This provides a endian-safe base36 encode/decode operations. This 6 | * means, the result will be the same on x86 or ibm/sparc chips. 7 | */ 8 | 9 | /* 10 | *
     11 |  * High Performance Base36 Encoder / Decoder
     12 |  *
     13 |  * Copyright © 2013-2016 Nick Galbreath
     14 |  * All rights reserved.
     15 |  *
     16 |  * https://github.com/client9/stringencoders
     17 |  *
     18 |  * Released under MIT license.  See LICENSE for details.
     19 |  * 
    20 | * 21 | * This provides a endian-safe base36 encode/decode operations. This 22 | * means, the result will be the same on x86 or ibm/sparc chips. 23 | * 24 | * (Note: making it endian-specifc only results in a 5% savings in 25 | * the decode operation, so why bother) 26 | */ 27 | 28 | #ifndef COM_MODP_STRINGENCODERS_B36 29 | #define COM_MODP_STRINGENCODERS_B36 30 | #include "extern_c_begin.h" 31 | #include "modp_stdint.h" 32 | 33 | /** 34 | * \brief base 36 encode 35 | * 36 | * \param[out] dest should have at least b36fast_encode_len memory allocated 37 | * \param[in] src input string 38 | * \param[in] len input string length, must be a multiple of 4 39 | * \return the strlen of the destination, or -1 if error 40 | * 41 | */ 42 | size_t modp_b36_encode(char* dest, const char* src, size_t len); 43 | 44 | /** 45 | * \brief Base 36 decode 46 | * \param[out] dest -- destination locations. May equal input. 47 | * \param[in] src -- source b36data 48 | * \param len -- length of source 49 | * \return -1 on decoding error, length of output otherwise 50 | * No ending null is added 51 | */ 52 | size_t modp_b36_decode(char* dest, const char* src, size_t len); 53 | 54 | /** 55 | * \brief Returns the amount of memory to allocate for encoding the input 56 | * string. 57 | * 58 | */ 59 | #define modp_b36_encode_len(A) ((A + 3) / 4 * 5 + 1) 60 | 61 | /** 62 | * \brief Return output strlen, without a NULL 63 | */ 64 | #define modp_b36_encode_strlen(A) ((A + 3) / 4 * 5) 65 | 66 | /** 67 | * \brief Return the amount of memory to allocate for decoding a base 36 68 | * encoded string. 69 | * 70 | */ 71 | #define modp_b36_decode_len(A) ((A + 4) / 5 * 4) 72 | 73 | #include "extern_c_end.h" 74 | 75 | #ifdef __cplusplus 76 | #include 77 | #include 78 | 79 | namespace modp { 80 | 81 | /** 82 | * 83 | * \param[in] s the input data 84 | * \param[in] len the length of input 85 | * \return b36 encoded string 86 | */ 87 | inline std::string b36_encode(const char* s, size_t len) 88 | { 89 | std::string x(modp_b36_encode_len(len), '\0'); 90 | size_t d = modp_b36_encode(const_cast(x.data()), s, len); 91 | if (d == (size_t)-1) { 92 | x.clear(); 93 | } else { 94 | x.erase(d, std::string::npos); 95 | } 96 | return x; 97 | } 98 | 99 | /** 100 | * \param[in] null-terminated c-string input 101 | * \return b36 encoded string 102 | */ 103 | inline std::string b36_encode(const char* s) 104 | { 105 | return b36_encode(s, strlen(s)); 106 | } 107 | 108 | /** 109 | * /param[in,out] s the string to encode 110 | * /return a reference to the input string, empty if error 111 | */ 112 | inline std::string& b36_encode(std::string& s) 113 | { 114 | std::string x(b36_encode(s.data(), s.size())); 115 | s.swap(x); 116 | return s; 117 | } 118 | 119 | /** 120 | * \param[in] s the input string 121 | * \return base36 encoded string 122 | */ 123 | inline std::string b36_encode(const std::string& s) 124 | { 125 | return b36_encode(s.data(), s.size()); 126 | } 127 | 128 | /** 129 | * Base36 decode a string. 130 | * This function does not allocate memory. 131 | * 132 | * \param s the string to decode 133 | * \return a reference to the input string. The string is empty 134 | * if an error occurred. 135 | */ 136 | inline std::string& b36_decode(std::string& s) 137 | { 138 | size_t d = modp_b36_decode(const_cast(s.data()), s.data(), s.size()); 139 | if (d == (size_t)-1) { 140 | s.clear(); 141 | } else { 142 | s.erase(d, std::string::npos); 143 | } 144 | return s; 145 | } 146 | 147 | inline std::string b36_decode(const std::string& s) 148 | { 149 | std::string x(s); 150 | b36_decode(x); 151 | return x; 152 | } 153 | 154 | inline std::string b36_decode(const char* s, size_t len) 155 | { 156 | std::string x(s, len); 157 | return b36_decode(x); 158 | } 159 | 160 | inline std::string b36_decode(const char* s) 161 | { 162 | std::string x(s); 163 | return b36_decode(x); 164 | } 165 | 166 | } /* namespace modp */ 167 | 168 | #endif /* ifdef __cplusplus */ 169 | 170 | #endif /* ifndef MODP_B36 */ 171 | -------------------------------------------------------------------------------- /src/modp_b64.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_b64.h 3 | * \brief High performance base 64 encode and decode 4 | * 5 | */ 6 | 7 | /* 8 | * \file 9 | *
     10 |  * High performance base64 encoder / decoder
     11 |  *
     12 |  * Copyright © 2005-2016 Nick Galbreath
     13 |  * All rights reserved.
     14 |  *
     15 |  * https://github.com/client9/stringencoders
     16 |  *
     17 |  * Released under MIT license.  See LICENSE for details.
     18 |  * 
    19 | * 20 | * This uses the standard base 64 alphabet. If you are planning 21 | * to embed a base 64 encoding inside a URL use modp_b64w instead. 22 | * 23 | * ATTENTION: the algorithm may require ALIGNED strings. For Intel 24 | * chips alignment doens't (perhaps a performance issues). But for 25 | * Sparc and maybe ARM, use of unaligned strings can core dump. 26 | * see https://github.com/client9/stringencoders/issues/1 27 | * see https://github.com/client9/stringencoders/issues/42 28 | */ 29 | 30 | #ifndef COM_MODP_STRINGENCODERS_B64 31 | #define COM_MODP_STRINGENCODERS_B64 32 | 33 | #include "extern_c_begin.h" 34 | #include "modp_stdint.h" 35 | 36 | /** 37 | * \brief Encode a raw binary string into base 64. 38 | * \param[out] dest should be allocated by the caller to contain 39 | * at least modp_b64_encode_len(len) bytes (see below) 40 | * This will contain the null-terminated b64 encoded result 41 | * \param[in] src contains the bytes 42 | * \param[in] len contains the number of bytes in the src 43 | * \return length of the destination string plus the ending null byte 44 | * i.e. the result will be equal to strlen(dest) + 1 45 | * 46 | * Example 47 | * 48 | * \code 49 | * char* src = ...; 50 | * int srclen = ...; //the length of number of bytes in src 51 | * char* dest = (char*) malloc(modp_b64_encode_len); 52 | * int len = modp_b64_encode(dest, src, sourcelen); 53 | * if (len == -1) { 54 | * printf("Error\n"); 55 | * } else { 56 | * printf("b64 = %s\n", dest); 57 | * } 58 | * \endcode 59 | * 60 | */ 61 | size_t modp_b64_encode(char* dest, const char* str, size_t len); 62 | 63 | /** 64 | * Decode a base64 encoded string 65 | * 66 | * \param[out] dest should be allocated by the caller to contain at least 67 | * len * 3 / 4 bytes. The destination cannot be the same as the source 68 | * They must be different buffers. 69 | * \param[in] src should contain exactly len bytes of b64 characters. 70 | * if src contains -any- non-base characters (such as white 71 | * space, -1 is returned. 72 | * \param[in] len is the length of src 73 | * 74 | * \return the length (strlen) of the output, or -1 if unable to 75 | * decode 76 | * 77 | * \code 78 | * char* src = ...; 79 | * int srclen = ...; // or if you don't know use strlen(src) 80 | * char* dest = (char*) malloc(modp_b64_decode_len(srclen)); 81 | * int len = modp_b64_decode(dest, src, sourcelen); 82 | * if (len == -1) { error } 83 | * \endcode 84 | */ 85 | size_t modp_b64_decode(char* dest, const char* src, size_t len); 86 | 87 | /** 88 | * Given a source string of length len, this returns the amount of 89 | * memory the destination string should have. 90 | * 91 | * remember, this is integer math 92 | * 3 bytes turn into 4 chars 93 | * ceiling[len / 3] * 4 + 1 94 | * 95 | * +1 is for any extra null. 96 | */ 97 | #define modp_b64_encode_len(A) ((A + 2) / 3 * 4 + 1) 98 | 99 | /** 100 | * Given a base64 string of length len, 101 | * this returns the amount of memory required for output string 102 | * It maybe be more than the actual number of bytes written. 103 | * NOTE: remember this is integer math 104 | * this allocates a bit more memory than traditional versions of b64 105 | * decode 4 chars turn into 3 bytes 106 | * floor[len * 3/4] + 2 107 | */ 108 | #define modp_b64_decode_len(A) (A / 4 * 3 + 2) 109 | 110 | /** 111 | * Will return the strlen of the output from encoding. 112 | * This may be less than the required number of bytes allocated. 113 | * 114 | * This allows you to 'deserialized' a struct 115 | * \code 116 | * char* b64encoded = "..."; 117 | * int len = strlen(b64encoded); 118 | * 119 | * struct datastuff foo; 120 | * if (modp_b64_encode_strlen(sizeof(struct datastuff)) != len) { 121 | * // wrong size 122 | * return false; 123 | * } else { 124 | * // safe to do; 125 | * if (modp_b64_decode((char*) &foo, b64encoded, len) == -1) { 126 | * // bad characters 127 | * return false; 128 | * } 129 | * } 130 | * // foo is filled out now 131 | * \endcode 132 | */ 133 | #define modp_b64_encode_strlen(A) ((A + 2) / 3 * 4) 134 | 135 | #include "extern_c_end.h" 136 | 137 | #ifdef __cplusplus 138 | #include 139 | #include 140 | 141 | namespace modp { 142 | /** \brief b64 encode a cstr with len 143 | * 144 | * \param[in] s the input string to encode 145 | * \param[in] len the length of the input string 146 | * \return a newly allocated b64 string. Empty if failed. 147 | */ 148 | inline std::string b64_encode(const char* s, size_t len) 149 | { 150 | std::string x(modp_b64_encode_len(len), '\0'); 151 | size_t d = modp_b64_encode(const_cast(x.data()), s, len); 152 | if (d == (size_t)-1) { 153 | x.clear(); 154 | } else { 155 | x.erase(d, std::string::npos); 156 | } 157 | return x; 158 | } 159 | 160 | /** \brief b64 encode a cstr 161 | * 162 | * \param[in] s the input string to encode 163 | * \return a newly allocated b64 string. Empty if failed. 164 | */ 165 | inline std::string b64_encode(const char* s) 166 | { 167 | return b64_encode(s, strlen(s)); 168 | } 169 | 170 | /** \brief b64 encode a const std::string 171 | * 172 | * \param[in] s the input string to encode 173 | * \return a newly allocated b64 string. Empty if failed. 174 | */ 175 | inline std::string b64_encode(const std::string& s) 176 | { 177 | return b64_encode(s.data(), s.size()); 178 | } 179 | 180 | /** 181 | * base 64 encode a string (self-modifing) 182 | * 183 | * This function is for C++ only (duh) 184 | * 185 | * \param[in,out] s the string to be decoded 186 | * \return a reference to the input string 187 | */ 188 | inline std::string& b64_encode(std::string& s) 189 | { 190 | std::string x(b64_encode(s.data(), s.size())); 191 | s.swap(x); 192 | return s; 193 | } 194 | 195 | inline std::string b64_decode(const char* src, size_t len) 196 | { 197 | std::string x(modp_b64_decode_len(len) + 1, '\0'); 198 | size_t d = modp_b64_decode(const_cast(x.data()), src, len); 199 | if (d == (size_t)-1) { 200 | x.clear(); 201 | } else { 202 | x.erase(d, std::string::npos); 203 | } 204 | return x; 205 | } 206 | 207 | inline std::string b64_decode(const char* src) 208 | { 209 | return b64_decode(src, strlen(src)); 210 | } 211 | 212 | /** 213 | * base 64 decode a string (self-modifing) 214 | * On failure, the string is empty. 215 | * 216 | * This function is for C++ only (duh) 217 | * 218 | * \param[in,out] s the string to be decoded 219 | * \return a reference to the input string 220 | */ 221 | inline std::string& b64_decode(std::string& s) 222 | { 223 | std::string x(b64_decode(s.data(), s.size())); 224 | s.swap(x); 225 | return s; 226 | } 227 | 228 | inline std::string b64_decode(const std::string& s) 229 | { 230 | return b64_decode(s.data(), s.size()); 231 | } 232 | } 233 | 234 | #endif /* __cplusplus */ 235 | 236 | #endif /* MODP_B64 */ 237 | -------------------------------------------------------------------------------- /src/modp_b64_gen.c: -------------------------------------------------------------------------------- 1 | /** 2 | * B64FAST - High performance base64 encoder/decoder 3 | * Version 1.1 -- 20-Feb-2005 4 | * 5 | * Copyright 2005-2016 Nick Galbreath -- nickg [at] client9 [dot] com 6 | * All rights reserved. 7 | * 8 | * https://github.com/client9/stringencoders 9 | * 10 | * Released under MIT license. See LICENSE for details. 11 | * 12 | * Data table generator. This generates a ".h" file for use 13 | * in compiling b64fast.c. This does not need to be exported. 14 | * 15 | */ 16 | 17 | /****************************/ 18 | /* To change the alphabet */ 19 | /* Edit the following lines */ 20 | /* and do a 'make' */ 21 | /****************************/ 22 | 23 | /****************************/ 24 | 25 | #include "arraytoc.h" 26 | #include "modp_stdint.h" 27 | #include 28 | #include 29 | #include 30 | 31 | static uint8_t b64chars[64] = { 32 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 33 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 34 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 35 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 36 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 37 | }; 38 | 39 | static uint8_t padchar = '='; 40 | 41 | static void printStart(void) 42 | { 43 | printf("#include \"modp_stdint.h\"\n"); 44 | printf("#define CHAR62 '%c'\n", b64chars[62]); 45 | printf("#define CHAR63 '%c'\n", b64chars[63]); 46 | printf("#define CHARPAD '%c'\n", padchar); 47 | } 48 | 49 | static void clearDecodeTable(uint32_t* ary) 50 | { 51 | int i = 0; 52 | for (i = 0; i < 256; ++i) { 53 | ary[i] = 0x01FFFFFF; 54 | } 55 | } 56 | 57 | int main(int argc, char** argv) 58 | { 59 | uint32_t x; 60 | uint32_t i = 0; 61 | char cary[256]; 62 | uint32_t ary[256]; 63 | 64 | /* over-ride standard alphabet */ 65 | if (argc == 2) { 66 | uint8_t* replacements = (uint8_t*)argv[1]; 67 | if (strlen((char*)replacements) != 3) { 68 | fprintf(stderr, "input must be a string of 3 characters '-', '.' or '_'\n"); 69 | exit(1); 70 | } 71 | fprintf(stderr, "fusing '%s' as replacements in base64 encoding\n", replacements); 72 | b64chars[62] = replacements[0]; 73 | b64chars[63] = replacements[1]; 74 | padchar = replacements[2]; 75 | } 76 | 77 | printStart(); 78 | 79 | for (i = 0; i < 256; ++i) { 80 | cary[i] = (char)(b64chars[i >> 2 & 0x3f]); 81 | } 82 | char_array_to_c(cary, sizeof(cary), "e0"); 83 | 84 | for (i = 0; i < 256; ++i) { 85 | cary[i] = (char)b64chars[(i & 0x3F)]; 86 | } 87 | char_array_to_c(cary, sizeof(cary), "e1"); 88 | 89 | for (i = 0; i < 256; ++i) { 90 | cary[i] = (char)b64chars[(i & 0x3F)]; 91 | } 92 | char_array_to_c(cary, sizeof(cary), "e2"); 93 | 94 | printf("\n\n#ifdef WORDS_BIGENDIAN\n"); 95 | printf("\n\n/* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */\n\n"); 96 | 97 | clearDecodeTable(ary); 98 | for (i = 0; i < 64; ++i) { 99 | x = b64chars[i]; 100 | ary[x] = i << 18; 101 | } 102 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d0"); 103 | printf("\n\n"); 104 | 105 | clearDecodeTable(ary); 106 | for (i = 0; i < 64; ++i) { 107 | x = b64chars[i]; 108 | ary[x] = i << 12; 109 | } 110 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d1"); 111 | printf("\n\n"); 112 | 113 | clearDecodeTable(ary); 114 | for (i = 0; i < 64; ++i) { 115 | x = b64chars[i]; 116 | ary[x] = i << 6; 117 | } 118 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d2"); 119 | printf("\n\n"); 120 | 121 | clearDecodeTable(ary); 122 | for (i = 0; i < 64; ++i) { 123 | x = b64chars[i]; 124 | ary[x] = i; 125 | } 126 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d3"); 127 | printf("\n\n"); 128 | 129 | printf("#else\n"); 130 | 131 | printf("\n\n/* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */\n\n"); 132 | 133 | clearDecodeTable(ary); 134 | for (i = 0; i < 64; ++i) { 135 | x = b64chars[i]; 136 | ary[x] = i << 2; 137 | } 138 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d0"); 139 | printf("\n\n"); 140 | 141 | clearDecodeTable(ary); 142 | for (i = 0; i < 64; ++i) { 143 | x = b64chars[i]; 144 | ary[x] = ((i & 0x30) >> 4) | ((i & 0x0F) << 12); 145 | } 146 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d1"); 147 | printf("\n\n"); 148 | 149 | clearDecodeTable(ary); 150 | for (i = 0; i < 64; ++i) { 151 | x = b64chars[i]; 152 | ary[x] = ((i & 0x03) << 22) | ((i & 0x3c) << 6); 153 | } 154 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d2"); 155 | printf("\n\n"); 156 | 157 | clearDecodeTable(ary); 158 | for (i = 0; i < 64; ++i) { 159 | x = b64chars[i]; 160 | ary[x] = i << 16; 161 | } 162 | uint32_array_to_c_hex(ary, sizeof(ary) / sizeof(uint32_t), "d3"); 163 | printf("\n\n"); 164 | 165 | printf("#endif\n"); 166 | 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /src/modp_b64w.h: -------------------------------------------------------------------------------- 1 | /** 2 | *
      3 |  * High performance WEB-SAFE base64 encoder / decoder
      4 |  *
      5 |  * Copyright © 2005-2016 Nick Galbreath -- nickg [at] client9 [dot] com
      6 |  * All rights reserved.
      7 |  *
      8 |  * https://github.com/client9/stringencoders/
      9 |  *
     10 |  * Released under MIT license.  See LICENSE for details.
     11 |  * 
    12 | * 13 | * This uses a "URL-safe" or "WEB-safe" encoding. The standard 14 | * base 64 encoding uses the characters '+', '/' and '=' have special 15 | * restrictions when used inside a URL. 16 | * 17 | * This uses "+" to "-", "/" to "_", and "=" to "." as the replacement 18 | * alphabet. 19 | * 20 | * It's easy to change this to use "URL safe" characters and to remove 21 | * padding. See the modp_b64.c source code for details. 22 | * 23 | */ 24 | 25 | #ifndef COM_MODP_STRINGENCODERS_B64W 26 | #define COM_MODP_STRINGENCODERS_B64W 27 | 28 | #include "extern_c_begin.h" 29 | #include "modp_stdint.h" 30 | 31 | /** 32 | * \brief Encode a raw binary string into web-safe base 64. 33 | * \param[out] dest should be allocated by the caller to contain 34 | * at least modp_b64w_encode_len(len) bytes (see below) 35 | * This will contain the null-terminated b64w encoded result 36 | * \param[in] src contains the bytes 37 | * \param[in] len contains the number of bytes in the src 38 | * \return length of the destination string plus the ending null byte 39 | * i.e. the result will be equal to strlen(dest) + 1 40 | * 41 | * Example 42 | * 43 | * \code 44 | * char* src = ...; 45 | * int srclen = ...; //the length of number of bytes in src 46 | * char* dest = (char*) malloc(modp_b64w_encode_len); 47 | * int len = modp_b64w_encode(dest, src, sourcelen); 48 | * if (len == -1) { 49 | * printf("Error\n"); 50 | * } else { 51 | * printf("b64w = %s\n", dest); 52 | * } 53 | * \endcode 54 | * 55 | */ 56 | size_t modp_b64w_encode(char* dest, const char* src, size_t len); 57 | 58 | /** 59 | * \brief Decode a web-safe base64 encoded string 60 | * 61 | * \param[out] dest should be allocated by the caller to contain at least 62 | * len * 3 / 4 bytes. 63 | * \param[in] src should contain exactly len bytes of b64w characters. 64 | * if src contains -any- non-base characters (such as white 65 | * space, -1 is returned. 66 | * \param[in] len is the length of src 67 | * 68 | * \return the length (strlen) of the output, or -1 if unable to 69 | * decode 70 | * 71 | * \code 72 | * char* src = ...; 73 | * int srclen = ...; // or if you don't know use strlen(src) 74 | * char* dest = (char*) malloc(modp_b64w_decode_len(srclen)); 75 | * int len = modp_b64w_decode(dest, src, sourcelen); 76 | * if (len == -1) { error } 77 | * \endcode 78 | */ 79 | size_t modp_b64w_decode(char* dest, const char* src, size_t len); 80 | 81 | /** 82 | * Given a source string of length len, this returns the amount of 83 | * memory the destination string should have. 84 | * 85 | * remember, this is integer math 86 | * 3 bytes turn into 4 chars 87 | * ceiling[len / 3] * 4 + 1 88 | * 89 | * +1 is for any extra null. 90 | */ 91 | #define modp_b64w_encode_len(A) ((A + 2) / 3 * 4 + 1) 92 | 93 | /** 94 | * Given a base64 string of length len, 95 | * this returns the amount of memory required for output string 96 | * It maybe be more than the actual number of bytes written. 97 | * NOTE: remember this is integer math 98 | * this allocates a bit more memory than traditional versions of b64w 99 | * decode 4 chars turn into 3 bytes 100 | * floor[len * 3/4] + 2 101 | */ 102 | #define modp_b64w_decode_len(A) (A / 4 * 3 + 2) 103 | 104 | /** 105 | * Will return the strlen of the output from encoding. 106 | * This may be less than the required number of bytes allocated. 107 | * 108 | * This allows you to 'deserialized' a struct: 109 | * \code 110 | * char* b64wencoded = "..."; 111 | * int len = strlen(b64wencoded); 112 | * 113 | * struct datastuff foo; 114 | * if (modp_b64w_encode_strlen(sizeof(struct datastuff)) != len) { 115 | * // wrong size 116 | * return false; 117 | * } else { 118 | * // safe to do; 119 | * if (modp_b64w_decode((char*) &foo, b64wencoded, len) == -1) { 120 | * // bad characters 121 | * return false; 122 | * } 123 | * } 124 | * // foo is filled out now 125 | * \endcode 126 | */ 127 | #define modp_b64w_encode_strlen(A) ((A + 2) / 3 * 4) 128 | 129 | #include "extern_c_end.h" 130 | 131 | #ifdef __cplusplus 132 | #include 133 | #include 134 | 135 | namespace modp { 136 | 137 | /** \brief b64w encode a cstr with len 138 | * 139 | * \param[in] s the input string to encode 140 | * \param[in] len the length of the input string 141 | * \return a newly allocated b64w string. Empty if failed. 142 | */ 143 | inline std::string b64w_encode(const char* s, size_t len) 144 | { 145 | std::string x(modp_b64w_encode_len(len), '\0'); 146 | size_t d = modp_b64w_encode(const_cast(x.data()), s, len); 147 | if (d == (size_t)-1) { 148 | x.clear(); 149 | } else { 150 | x.erase(d, std::string::npos); 151 | } 152 | return x; 153 | } 154 | 155 | /** \brief b64w encode a cstr 156 | * 157 | * \param[in] s the input string to encode 158 | * \return a newly allocated b64w string. Empty if failed. 159 | */ 160 | inline std::string b64w_encode(const char* s) 161 | { 162 | return b64w_encode(s, strlen(s)); 163 | } 164 | 165 | /** \brief b64w encode a const std::string 166 | * 167 | * \param[in] s the input string to encode 168 | * \return a newly allocated b64w string. Empty if failed. 169 | */ 170 | inline std::string b64w_encode(const std::string& s) 171 | { 172 | return b64w_encode(s.data(), s.size()); 173 | } 174 | 175 | /** \brief self-modifing b64w encode 176 | * 177 | * web-safe base 64 decode a string (self-modifing) 178 | * On failure, the string is empty. 179 | * 180 | * \param[in,out] s the string to be decoded 181 | * \return a reference to the input string 182 | */ 183 | inline std::string& b64w_encode(std::string& s) 184 | { 185 | std::string x(b64w_encode(s.data(), s.size())); 186 | s.swap(x); 187 | return s; 188 | } 189 | 190 | inline std::string b64w_decode(const char* src, size_t len) 191 | { 192 | std::string x(modp_b64w_decode_len(len) + 1, '\0'); 193 | size_t d = modp_b64w_decode(const_cast(x.data()), src, len); 194 | if (d == (size_t)-1) { 195 | x.clear(); 196 | } else { 197 | x.erase(d, std::string::npos); 198 | } 199 | return x; 200 | } 201 | 202 | inline std::string b64w_decode(const char* src) 203 | { 204 | return b64w_decode(src, strlen(src)); 205 | } 206 | 207 | /** 208 | * base 64 decode a string (self-modifing) 209 | * On failure, the string is empty. 210 | * 211 | * This function is for C++ only (duh) 212 | * 213 | * \param[in,out] s the string to be decoded 214 | * \return a reference to the input string 215 | */ 216 | inline std::string& b64w_decode(std::string& s) 217 | { 218 | std::string x(b64w_decode(s.data(), s.size())); 219 | s.swap(x); 220 | return s; 221 | } 222 | 223 | inline std::string b64w_decode(const std::string& s) 224 | { 225 | return b64w_decode(s.data(), s.size()); 226 | } 227 | } 228 | 229 | #endif /* __cplusplus */ 230 | 231 | #endif /* MODP_B64W */ 232 | -------------------------------------------------------------------------------- /src/modp_b85.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | *
      4 |  * MODP_B85 - High performance base85 encoder/decoder
      5 |  * https://github.com/client9/stringencoders/
      6 |  *
      7 |  * Copyright © 2006-2016  Nick Galbreath -- nickg [at] client9 [dot] com
      8 |  * All rights reserved.
      9 |  * Released under MIT license. See LICENSE for details.
     10 |  * 
    11 | */ 12 | 13 | /* exported public header */ 14 | #include "modp_b85.h" 15 | #include "modp_stdint.h" 16 | /* private header */ 17 | #include "modp_b85_data.h" 18 | 19 | /* 20 | * Might need changing depending on platform 21 | * we need htonl, and ntohl 22 | */ 23 | #include 24 | 25 | /** 26 | * you can decode IN PLACE! 27 | * no memory allocated 28 | */ 29 | size_t modp_b85_decode(char* out, const char* data, size_t len) 30 | { 31 | size_t i; 32 | int j; 33 | uint32_t tmp; 34 | uint32_t digit; 35 | uint32_t* o2; 36 | const size_t buckets = len / 5; 37 | const uint8_t* d2 = (const uint8_t*)data; 38 | 39 | if (len % 5 != 0) { 40 | return (size_t)-1; 41 | } 42 | 43 | o2 = (uint32_t*)out; 44 | for (i = 0; i < buckets; ++i) { 45 | tmp = 0; 46 | for (j = 0; j < 5; ++j) { 47 | digit = gsCharToInt[(uint32_t)*d2++]; 48 | if (digit >= 85) { 49 | return (size_t)-1; 50 | } 51 | tmp = tmp * 85 + digit; 52 | } 53 | *o2++ = htonl(tmp); 54 | } 55 | return 4 * buckets; 56 | } 57 | 58 | /** 59 | * src != out 60 | */ 61 | size_t modp_b85_encode(char* out, const char* src, size_t len) 62 | { 63 | size_t i; 64 | uint32_t tmp; 65 | const uint32_t* sary = (const uint32_t*)src; 66 | const size_t buckets = len / 4; 67 | if (len % 4 != 0) { 68 | return (size_t)-1; 69 | } 70 | 71 | for (i = 0; i < buckets; ++i) { 72 | tmp = *sary++; 73 | tmp = htonl(tmp); 74 | 75 | /* this crazy function */ 76 | #if 1 77 | *out++ = (char)gsIntToChar[(tmp / 52200625)]; /* don't need % 85 here, always < 85 */ 78 | *out++ = (char)gsIntToChar[(tmp / 614125) % 85]; 79 | *out++ = (char)gsIntToChar[(tmp / 7225) % 85]; 80 | *out++ = (char)gsIntToChar[(tmp / 85) % 85]; 81 | *out++ = (char)gsIntToChar[tmp % 85]; 82 | #else 83 | /* is really this */ 84 | *(out + 4) = gsIntToChar[tmp % 85]; 85 | tmp /= 85; 86 | *(out + 3) = gsIntToChar[tmp % 85]; 87 | tmp /= 85; 88 | *(out + 2) = gsIntToChar[tmp % 85]; 89 | tmp /= 85; 90 | *(out + 1) = gsIntToChar[tmp % 85]; 91 | tmp /= 85; 92 | *out = gsIntToChar[tmp]; 93 | out += 5; 94 | #endif 95 | /* NOTES 96 | * Version 1 under -O3 is about 10-20 PERCENT faster than version 2 97 | * BUT Version 1 is 10 TIMES SLOWER when used with -Os !!! 98 | * Reason: gcc does a lot of tricks to remove the divisions 99 | * op with multiplies and shift. 100 | * In V1 with -O3 this works. Under -Os it reverts to very 101 | * slow division. 102 | * In V2 -O3 it does the same thing, but under Os, it's smart 103 | * enough to know we want the quotient and remainder and only 104 | * one div call per line. 105 | */ 106 | } 107 | *out = 0; /* final null */ 108 | return buckets * 5; 109 | } 110 | -------------------------------------------------------------------------------- /src/modp_b85.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_b85.h 3 | * \brief Base 85 encoding and decoding 4 | * 5 | * This provides a endian-safe base85 encode/decode operations. This 6 | * means, the result will be the same on x86 or ibm/sparc chips. 7 | */ 8 | 9 | /* 10 | *
     11 |  * High Performance Base85 Encoder / Decoder
     12 |  *
     13 |  * Copyright © 2006-2016 Nick Galbreath -- nickg [at] client9 [dot] com
     14 |  * All rights reserved.
     15 |  *
     16 |  * https://github.com/client9/stringencoders/
     17 |  *
     18 |  * Released under MIT license.  See LICENSE for details.
     19 |  * 
    20 | * 21 | * This provides a endian-safe base85 encode/decode operations. This 22 | * means, the result will be the same on x86 or ibm/sparc chips. 23 | * 24 | * (Note: making it endian-specifc only results in a 5% savings in 25 | * the decode operation, so why bother) 26 | */ 27 | 28 | #ifndef COM_MODP_STRINGENCODERS_B85 29 | #define COM_MODP_STRINGENCODERS_B85 30 | #include "extern_c_begin.h" 31 | #include "modp_stdint.h" 32 | 33 | /** 34 | * \brief base 85 encode 35 | * 36 | * \param[out] dest should have at least b85fast_encode_len memory allocated 37 | * \param[in] src input string 38 | * \param[in] len input string length, must be a multiple of 4 39 | * \return the strlen of the destination, or -1 if error 40 | * 41 | */ 42 | size_t modp_b85_encode(char* dest, const char* src, size_t len); 43 | 44 | /** 45 | * \brief Base 85 decode 46 | * \param[out] dest -- destination locations. May equal input. 47 | * \param[in] src -- source b85data 48 | * \param len -- length of source 49 | * \return -1 on decoding error, length of output otherwise 50 | * No ending null is added 51 | */ 52 | size_t modp_b85_decode(char* dest, const char* src, size_t len); 53 | 54 | /** 55 | * \brief Returns the amount of memory to allocate for encoding the input 56 | * string. 57 | * 58 | */ 59 | #define modp_b85_encode_len(A) ((A + 3) / 4 * 5 + 1) 60 | 61 | /** 62 | * \brief Return output strlen, without a NULL 63 | */ 64 | #define modp_b85_encode_strlen(A) ((A + 3) / 4 * 5) 65 | 66 | /** 67 | * \brief Return the amount of memory to allocate for decoding a base 85 68 | * encoded string. 69 | * 70 | */ 71 | #define modp_b85_decode_len(A) ((A + 4) / 5 * 4) 72 | 73 | #include "extern_c_end.h" 74 | 75 | #ifdef __cplusplus 76 | #include 77 | #include 78 | 79 | namespace modp { 80 | 81 | /** 82 | * 83 | * \param[in] s the input data 84 | * \param[in] len the length of input 85 | * \return b85 encoded string 86 | */ 87 | inline std::string b85_encode(const char* s, size_t len) 88 | { 89 | std::string x(modp_b85_encode_len(len), '\0'); 90 | size_t d = modp_b85_encode(const_cast(x.data()), s, len); 91 | if (d == (size_t)-1) { 92 | x.clear(); 93 | } else { 94 | x.erase(d, std::string::npos); 95 | } 96 | return x; 97 | } 98 | 99 | /** 100 | * \param[in] null-terminated c-string input 101 | * \return b85 encoded string 102 | */ 103 | inline std::string b85_encode(const char* s) 104 | { 105 | return b85_encode(s, strlen(s)); 106 | } 107 | 108 | /** 109 | * /param[in,out] s the string to encode 110 | * /return a reference to the input string, empty if error 111 | */ 112 | inline std::string& b85_encode(std::string& s) 113 | { 114 | std::string x(b85_encode(s.data(), s.size())); 115 | s.swap(x); 116 | return s; 117 | } 118 | 119 | /** 120 | * \param[in] s the input string 121 | * \return base85 encoded string 122 | */ 123 | inline std::string b85_encode(const std::string& s) 124 | { 125 | return b85_encode(s.data(), s.size()); 126 | } 127 | 128 | /** 129 | * Base85 decode a string. 130 | * This function does not allocate memory. 131 | * 132 | * \param s the string to decode 133 | * \return a reference to the input string. The string is empty 134 | * if an error occurred. 135 | */ 136 | inline std::string& b85_decode(std::string& s) 137 | { 138 | size_t d = modp_b85_decode(const_cast(s.data()), s.data(), 139 | s.size()); 140 | if (d == (size_t)-1) { 141 | s.clear(); 142 | } else { 143 | s.erase(d, std::string::npos); 144 | } 145 | return s; 146 | } 147 | 148 | inline std::string b85_decode(const std::string& s) 149 | { 150 | std::string x(s); 151 | b85_decode(x); 152 | return x; 153 | } 154 | 155 | inline std::string b85_decode(const char* s, size_t len) 156 | { 157 | std::string x(s, len); 158 | return b85_decode(x); 159 | } 160 | 161 | inline std::string b85_decode(const char* s) 162 | { 163 | std::string x(s); 164 | return b85_decode(x); 165 | } 166 | 167 | } /* namespace modp */ 168 | 169 | #endif /* ifdef __cplusplus */ 170 | 171 | #endif /* ifndef MODP_B85 */ 172 | -------------------------------------------------------------------------------- /src/modp_b85_gen.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | #include 3 | #include 4 | #include 5 | /** 6 | * raw data to base85 char map 7 | */ 8 | static char gsIntToChar[85]; 9 | 10 | /** 11 | * base 85 char to int 12 | */ 13 | static uint32_t gsCharToInt[256]; 14 | 15 | /* 16 | * Set up the above arrays 17 | */ 18 | static void initTables(void) 19 | { 20 | int i = 0; 21 | int j = 0; 22 | for (i = 0; i < 256; i++) { 23 | gsCharToInt[i] = 99; 24 | } 25 | 26 | /* i < 33 or '!' is unprintable 27 | * 127 is an unprintable character 28 | */ 29 | for (i = '!', j = 0; j < 85 && i < 127; ++i) { 30 | 31 | /* You can have 8 restrictions in the following line. 32 | * Traditional postscript removes: ';', '&', '\', '"' 33 | * so that 'last' character is 'y' ('z' is special) 34 | * For web/cookie applications, I recommend those plus ',' 35 | */ 36 | if (i == ';' || i == '&' || i == '\\' || i == '"' || i == ',') { 37 | continue; 38 | } 39 | gsIntToChar[j] = (char)i; 40 | gsCharToInt[i] = (uint32_t)j; 41 | ++j; 42 | } 43 | 44 | if (j != 85) { 45 | fprintf(stderr, "Error in base85 table. You probably had too many restrictions\n"); 46 | exit(1); 47 | } 48 | } 49 | 50 | /** 51 | * beginning headers 52 | */ 53 | static void printStart(void) 54 | { 55 | printf("/* do not edit -- autogenerated from b85gen */\n"); 56 | } 57 | 58 | int main(void) 59 | { 60 | initTables(); 61 | printStart(); 62 | uint32_array_to_c(gsCharToInt, sizeof(gsCharToInt) / sizeof(uint32_t), "gsCharToInt"); 63 | char_array_to_c(gsIntToChar, sizeof(gsIntToChar), "gsIntToChar"); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /src/modp_bjavascript.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | *
     4 |  * modp_bjavascript.c High performance URL encoder/decoder
     5 |  * https://github.com/client9/stringencoders
     6 |  *
     7 |  * Copyright © 2006-2016  Nick Galbreath
     8 |  * All rights reserved.
     9 |  * Released under MIT license. See LICENSE for details.
    10 |  * 
    11 | */ 12 | #include "modp_bjavascript.h" 13 | #include "modp_bjavascript_data.h" 14 | #include "modp_stdint.h" 15 | 16 | size_t modp_bjavascript_encode(char* dest, const char* src, size_t len) 17 | { 18 | const char* deststart = dest; 19 | const uint8_t* s = (const uint8_t*)src; 20 | const uint8_t* srcend = s + len; 21 | uint8_t x; 22 | uint8_t val; 23 | 24 | /* if 0, do nothing 25 | * if 'A', hex escape 26 | * else, \\ + value 27 | */ 28 | while (s < srcend) { 29 | x = *s++; 30 | val = gsJavascriptEncodeMap[x]; 31 | if (val == 0) { 32 | *dest++ = (char)x; 33 | } else if (val == 'A') { 34 | *dest++ = '\\'; 35 | *dest++ = 'x'; 36 | *dest++ = (char)(gsHexEncodeMap1[x]); 37 | *dest++ = (char)(gsHexEncodeMap2[x]); 38 | } else { 39 | *dest++ = '\\'; 40 | *dest++ = (char)val; 41 | } 42 | } 43 | *dest = '\0'; 44 | return (size_t)(dest - deststart); 45 | } 46 | 47 | size_t modp_bjavascript_encode_strlen(const char* src, size_t len) 48 | { 49 | const uint8_t* s = (const uint8_t*)src; 50 | const uint8_t* srcend = s + len; 51 | size_t count = 0; 52 | uint8_t val; 53 | 54 | while (s < srcend) { 55 | val = gsJavascriptEncodeMap[*s++]; 56 | if (val == 0) { 57 | count++; 58 | } else if (val == 'A') { 59 | count += 4; 60 | } else { 61 | count += 2; 62 | } 63 | } 64 | return count; 65 | } 66 | -------------------------------------------------------------------------------- /src/modp_bjavascript.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_bjavascript.h 3 | * \brief "C-string" to "javascript-string" encoder 4 | * 5 | * Used in emitting dynamically-generated javascript. Given a regular 6 | * C-string which might contain binary, the encoder will emit a string 7 | * that can be used inside a javascript string. For example: 8 | * 9 | * \code 10 | * printf("var foo = '%s';", modp_bjavascript_encode(mystring, len)); 11 | * \endcode 12 | * 13 | * The "b" in "modp_bjavascript" is due to legacy reasons. It doesn't 14 | * mean anything 15 | * 16 | * There is no decoder. 17 | */ 18 | 19 | /* 20 | *
     21 |  * High Performance c-string to javascript-string encoder
     22 |  *
     23 |  * Copyright © 2006-2016  Nick Galbreath
     24 |  * All rights reserved.
     25 |  *
     26 |  * https://github.com/client9/stringencoders
     27 |  *
     28 |  * Released under MIT license.  See LICENSE for details.
     29 |  * 
    30 | */ 31 | 32 | #ifndef COM_MODP_STRINGENCODERS_BJAVASCRIPT 33 | #define COM_MODP_STRINGENCODERS_BJAVASCRIPT 34 | 35 | #include "modp_stdint.h" 36 | 37 | #include "extern_c_begin.h" 38 | 39 | /** 40 | * "javascript" encode a stirng 41 | * This takes a c-string and does character escaping 42 | * so it can be put into a var js_string = '...'; 43 | * 44 | * \param[out] dest output string. Must 45 | * \param[in] str The input string 46 | * \param[in] len The length of the input string, excluding any 47 | * final null byte. 48 | */ 49 | size_t modp_bjavascript_encode(char* dest, const char* str, size_t len); 50 | 51 | #define modp_bjavascript_encode_len(A) (4 * A + 1) 52 | 53 | /** 54 | * Given the exact size of output string. 55 | * 56 | * Can be used to allocate the right amount of memory for 57 | * modp_burl_encode. Be sure to add 1 byte for final null. 58 | * 59 | * This is somewhat expensive since it examines every character 60 | * in the input string 61 | * 62 | * \param[in] str The input string 63 | * \param[in] len THe length of the input string, excluding any 64 | * final null byte (i.e. strlen(str)) 65 | * \return the size of the output string, excluding the final 66 | * null byte. 67 | */ 68 | size_t modp_bjavascript_encode_strlen(const char* str, size_t len); 69 | 70 | #include "extern_c_end.h" 71 | 72 | #ifdef __cplusplus 73 | #include 74 | #include 75 | namespace modp { 76 | 77 | inline std::string javascript_encode(const char* s, size_t len) 78 | { 79 | std::string x(modp_bjavascript_encode_len(len), '\0'); 80 | size_t d = modp_bjavascript_encode(const_cast(x.data()), s, len); 81 | x.erase(d, std::string::npos); 82 | return x; 83 | } 84 | 85 | inline std::string javascript_encode(const char* s) 86 | { 87 | return javascript_encode(s, strlen(s)); 88 | } 89 | 90 | inline std::string& javascript_encode(std::string& s) 91 | { 92 | std::string x(javascript_encode(s.data(), s.size())); 93 | s.swap(x); 94 | return s; 95 | } 96 | 97 | inline std::string javascript_encode(const std::string& s) 98 | { 99 | return javascript_encode(s.data(), s.size()); 100 | } 101 | 102 | } /* namespace modp */ 103 | #endif /* __cplusplus */ 104 | 105 | #endif /* modp_bjavascript */ 106 | -------------------------------------------------------------------------------- /src/modp_bjavascript_data.h: -------------------------------------------------------------------------------- 1 | static const uint8_t gsJavascriptEncodeMap[256] = { 2 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'b', 't', 3 | 'n', 'v', 'f', 'r', 'A', 'A', 'A', 'A', 'A', 'A', 4 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 5 | 'A', 'A', '\0', '\0', '"', '\0', '\0', '\0', '\0', '\'', 6 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 7 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 8 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 9 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 10 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 11 | '\0', '\0', '\\', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 12 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 13 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 14 | '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'A', 'A', 'A', 15 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 16 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 17 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 18 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 19 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 20 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 21 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 22 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 23 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 24 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 25 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 26 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 27 | 'A', 'A', 'A', 'A', 'A', 'A' 28 | }; 29 | static const uint8_t gsHexEncodeMap1[256] = { 30 | '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 31 | '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', 32 | '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', 33 | '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', 34 | '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', 35 | '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', 36 | '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', 37 | '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', 38 | '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', 39 | '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', 40 | '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', 41 | '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', 42 | '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', 43 | '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', 44 | '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', 45 | '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', 46 | 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 47 | 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 48 | 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 49 | 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 50 | 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 51 | 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 52 | 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'E', 'E', 53 | 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 54 | 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 55 | 'F', 'F', 'F', 'F', 'F', 'F' 56 | }; 57 | static const uint8_t gsHexEncodeMap2[256] = { 58 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 59 | 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', 60 | '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 61 | 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', 62 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', 63 | '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 64 | 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', 65 | '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 66 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 67 | 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', 68 | '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 69 | 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', 70 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', 71 | '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 72 | 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', 73 | '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 74 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 75 | 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', 76 | '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 77 | 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', 78 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', 79 | '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 80 | 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', 81 | '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 82 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 83 | 'A', 'B', 'C', 'D', 'E', 'F' 84 | }; 85 | -------------------------------------------------------------------------------- /src/modp_bjavascript_gen.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ 2 | /* vi: set expandtab shiftwidth=4 tabstop=4: */ 3 | 4 | #include "arraytoc.h" 5 | 6 | static void hexencodemap(void) 7 | { 8 | static const char sHexChars[] = "0123456789ABCDEF"; 9 | int i; 10 | char hexEncode1[256]; 11 | char hexEncode2[256]; 12 | for (i = 0; i < 256; ++i) { 13 | hexEncode1[i] = sHexChars[i >> 4]; 14 | hexEncode2[i] = sHexChars[i & 0x0f]; 15 | } 16 | 17 | char_array_to_c(hexEncode1, sizeof(hexEncode1), "gsHexEncodeMap1"); 18 | char_array_to_c(hexEncode2, sizeof(hexEncode2), "gsHexEncodeMap2"); 19 | } 20 | 21 | static void jsencodemap(void) 22 | { 23 | int i; 24 | char jsEncodeMap[256]; 25 | 26 | /* set everything to "as is" */ 27 | for (i = 0; i < 256; ++i) { 28 | jsEncodeMap[i] = 0; 29 | } 30 | 31 | /* chars that need hex escaping */ 32 | for (i = 0; i < 32; ++i) { 33 | jsEncodeMap[i] = 'A'; 34 | } 35 | for (i = 127; i < 256; ++i) { 36 | jsEncodeMap[i] = 'A'; 37 | } 38 | 39 | /* items that have special escaping */ 40 | jsEncodeMap[0x08] = 'b'; 41 | jsEncodeMap[0x09] = 't'; 42 | jsEncodeMap[0x0a] = 'n'; 43 | jsEncodeMap[0x0b] = 'v'; 44 | jsEncodeMap[0x0c] = 'f'; 45 | jsEncodeMap[0x0d] = 'r'; 46 | jsEncodeMap[0x5c] = '\\'; /* blackslash gets escaped */ 47 | jsEncodeMap[0x22] = '"'; /* dquote gets escaped */ 48 | jsEncodeMap[0x27] = '\''; /* squote gets escaped */ 49 | 50 | char_array_to_c(jsEncodeMap, sizeof(jsEncodeMap), "gsJavascriptEncodeMap"); 51 | } 52 | 53 | int main(void) 54 | { 55 | jsencodemap(); 56 | hexencodemap(); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/modp_burl.c: -------------------------------------------------------------------------------- 1 | /* 2 | *
      3 |  * BFASTURL.c High performance URL encoder/decoder
      4 |  * https://github.com/client9/stringencoders
      5 |  *
      6 |  * Copyright © 2006-2016  Nick Galbreath
      7 |  * All rights reserved.
      8 |  * Released under MIT license. See LICENSE for details.
      9 |  * 
    10 | */ 11 | 12 | #include "modp_stdint.h" 13 | 14 | #include "modp_burl.h" 15 | #include "modp_burl_data.h" 16 | 17 | size_t modp_burl_encode(char* dest, const char* src, size_t len) 18 | { 19 | 20 | const char* deststart = dest; 21 | const uint8_t* s = (const uint8_t*)src; 22 | const uint8_t* srcend = s + len; 23 | char c; 24 | uint8_t x; 25 | 26 | if (len == 0) { 27 | *dest = '\0'; 28 | return (size_t)0; 29 | } 30 | 31 | while (s < srcend) { 32 | x = *s++; 33 | c = (char)gsUrlEncodeMap[x]; 34 | if (c) { 35 | *dest++ = c; 36 | } else { 37 | *dest++ = '%'; 38 | *dest++ = (char)gsHexEncodeMap1[x]; 39 | *dest++ = (char)gsHexEncodeMap2[x]; 40 | /* 41 | is the equiv of this 42 | static const char sHexChars[] = "0123456789ABCDEF"; 43 | *dest++ = (char)sHexChars[x >> 4]; 44 | *dest++ = (char)sHexChars[x & 0x0F]; 45 | */ 46 | } 47 | } 48 | *dest = '\0'; 49 | return (size_t)(dest - deststart); /* compute "strlen" of dest. */ 50 | } 51 | 52 | /** 53 | * The implementation is identical except it uses a 54 | * different array 55 | */ 56 | size_t modp_burl_min_encode(char* dest, const char* src, size_t len) 57 | { 58 | 59 | const char* deststart = dest; 60 | const uint8_t* s = (const uint8_t*)src; 61 | const uint8_t* srcend = s + len; 62 | char c; 63 | uint8_t x; 64 | 65 | if (len == 0) { 66 | *dest = '\0'; 67 | return (size_t)0; 68 | } 69 | 70 | while (s < srcend) { 71 | x = *s++; 72 | c = (char)(gsUrlEncodeMinMap[x]); /** CHANGE HERE **/ 73 | if (c) { 74 | *dest++ = c; 75 | } else { 76 | *dest++ = '%'; 77 | *dest++ = (char)gsHexEncodeMap1[x]; 78 | *dest++ = (char)(gsHexEncodeMap2[x]); 79 | /* 80 | is the equiv of this 81 | static const char sHexChars[] = "0123456789ABCDEF"; 82 | *dest++ = sHexChars[x >> 4]; 83 | *dest++ = sHexChars[x & 0x0F]; 84 | */ 85 | } 86 | } 87 | *dest = '\0'; 88 | return (size_t)(dest - deststart); /* compute "strlen" of dest. */ 89 | } 90 | 91 | /** 92 | * Give exact size of encoded output string 93 | * without doing the encoding 94 | */ 95 | size_t modp_burl_encode_strlen(const char* src, const size_t len) 96 | { 97 | size_t count = 0; 98 | const char* srcend = src + len; 99 | 100 | if (len == 0) { 101 | return (size_t)0; 102 | } 103 | 104 | while (src < srcend) { 105 | if (gsUrlEncodeMap[(uint8_t)*src++]) { 106 | count++; 107 | } else { 108 | count += 3; 109 | } 110 | } 111 | return count; 112 | } 113 | 114 | /** 115 | * Give exact size of encoded output string 116 | * without doing the encoding 117 | */ 118 | size_t modp_burl_min_encode_strlen(const char* src, const size_t len) 119 | { 120 | size_t count = 0; 121 | const char* srcend = src + len; 122 | 123 | if (len == 0) { 124 | return (size_t)0; 125 | } 126 | 127 | while (src < srcend) { 128 | if (gsUrlEncodeMinMap[(uint8_t)*src++]) { 129 | count++; 130 | } else { 131 | count += 3; 132 | } 133 | } 134 | return count; 135 | } 136 | 137 | size_t modp_burl_decode(char* dest, const char* s, size_t len) 138 | { 139 | uint32_t d = 0; /* used for decoding %XX */ 140 | const uint8_t* src = (const uint8_t*)s; 141 | const char* deststart = dest; 142 | const uint8_t* srcend = (const uint8_t*)(src + len); 143 | const uint8_t* srcendloop = (const uint8_t*)(srcend - 2); 144 | 145 | if (len == 0) { 146 | *dest = '\0'; 147 | return (size_t)0; 148 | } 149 | 150 | while (src < srcendloop) { 151 | switch (*src) { 152 | case '+': 153 | *dest++ = ' '; 154 | src++; 155 | break; 156 | case '%': 157 | d = (gsHexDecodeMap[(uint32_t)(*(src + 1))] << 4) | gsHexDecodeMap[(uint32_t)(*(src + 2))]; 158 | if (d < 256) { /* if one of the hex chars is bad, d >= 256 */ 159 | *dest = (char)d; 160 | dest++; 161 | src += 3; 162 | } else { 163 | *dest++ = '%'; 164 | src++; 165 | } 166 | break; 167 | default: 168 | *dest++ = (char)*src++; 169 | } 170 | } 171 | 172 | /* handle last two chars 173 | * dont decode "%XX" 174 | */ 175 | while (src < srcend) { 176 | switch (*src) { 177 | case '+': 178 | *dest++ = ' '; 179 | src++; 180 | break; 181 | default: 182 | *dest++ = (char)(*src++); 183 | } 184 | } 185 | 186 | *dest = '\0'; 187 | return (size_t)(dest - deststart); /* compute "strlen" of dest. */ 188 | } 189 | 190 | size_t modp_burl_decode_raw(char* dest, const char* s, size_t len) 191 | { 192 | uint32_t d = 0; /* used for decoding %XX */ 193 | const uint8_t* src = (const uint8_t*)s; 194 | const char* deststart = dest; 195 | const uint8_t* srcend = (const uint8_t*)(src + len); 196 | const uint8_t* srcendloop = (const uint8_t*)(srcend - 2); 197 | 198 | if (len == 0) { 199 | *dest = '\0'; 200 | return (size_t)0; 201 | } 202 | 203 | while (src < srcendloop) { 204 | if (*src == '%') { 205 | d = (gsHexDecodeMap[(uint32_t)(*(src + 1))] << 4) | gsHexDecodeMap[(uint32_t)(*(src + 2))]; 206 | if (d < 256) { /* if one of the hex chars is bad, d >= 256 */ 207 | *dest = (char)d; 208 | dest++; 209 | src += 3; 210 | } else { 211 | *dest++ = '%'; 212 | src++; 213 | } 214 | } else { 215 | *dest++ = (char)*src++; 216 | } 217 | } 218 | 219 | /* handle last two chars 220 | * dont decode "%XX" 221 | */ 222 | while (src < srcend) { 223 | *dest++ = (char)(*src++); 224 | } 225 | 226 | *dest = '\0'; 227 | return (size_t)(dest - deststart); /* compute "strlen" of dest. */ 228 | } 229 | -------------------------------------------------------------------------------- /src/modp_burl_gen.c: -------------------------------------------------------------------------------- 1 | #include "arraytoc.h" 2 | 3 | static void hexencodemap(void) 4 | { 5 | static const char sHexChars[] = "0123456789ABCDEF"; 6 | int i; 7 | char hexEncode1[256]; 8 | char hexEncode2[256]; 9 | for (i = 0; i < 256; ++i) { 10 | hexEncode1[i] = sHexChars[i >> 4]; 11 | hexEncode2[i] = sHexChars[i & 0x0f]; 12 | } 13 | 14 | char_array_to_c(hexEncode1, sizeof(hexEncode1), "gsHexEncodeMap1"); 15 | char_array_to_c(hexEncode2, sizeof(hexEncode2), "gsHexEncodeMap2"); 16 | } 17 | 18 | static void urlencodemap(void) 19 | { 20 | uint32_t i; 21 | char urlEncodeMap[256]; 22 | 23 | /* 0 means unsafe */ 24 | for (i = 0; i < 256; ++i) { 25 | urlEncodeMap[i] = 0; 26 | } 27 | 28 | /* upper case */ 29 | for (i = 'A'; i <= 'Z'; ++i) { 30 | urlEncodeMap[i] = (char)i; 31 | } 32 | /* lower case */ 33 | for (i = 'a'; i <= 'z'; ++i) { 34 | urlEncodeMap[i] = (char)i; 35 | } 36 | /* numbers */ 37 | for (i = '0'; i <= '9'; ++i) { 38 | urlEncodeMap[i] = (char)i; 39 | } 40 | /* safe chars */ 41 | urlEncodeMap[(int)'.'] = '.'; 42 | urlEncodeMap[(int)'-'] = '-'; 43 | urlEncodeMap[(int)'_'] = '_'; 44 | /* space is special */ 45 | urlEncodeMap[(int)' '] = '+'; 46 | 47 | char_array_to_c(urlEncodeMap, sizeof(urlEncodeMap), "gsUrlEncodeMap"); 48 | } 49 | 50 | static void urlencodeminmap(void) 51 | { 52 | int i; 53 | char urlEncodeMap[256]; 54 | const char safechar[] = { '_', '.', '-', '~', 55 | '!', '$', '(', ')', '*', ',', ';', 56 | ':', '@', '/', '?' }; 57 | 58 | int imax = sizeof(safechar); 59 | 60 | /* 0 means unsafe */ 61 | for (i = 0; i < 256; ++i) { 62 | urlEncodeMap[i] = 0; 63 | } 64 | 65 | /* upper case */ 66 | for (i = 'A'; i <= 'Z'; ++i) { 67 | urlEncodeMap[i] = (char)i; 68 | } 69 | /* lower case */ 70 | for (i = 'a'; i <= 'z'; ++i) { 71 | urlEncodeMap[i] = (char)i; 72 | } 73 | /* numbers */ 74 | for (i = '0'; i <= '9'; ++i) { 75 | urlEncodeMap[i] = (char)i; 76 | } 77 | 78 | /* space */ 79 | urlEncodeMap[(int)' '] = '+'; 80 | 81 | for (i = 0; i < imax; ++i) { 82 | urlEncodeMap[(int)(safechar[i])] = safechar[i]; 83 | } 84 | 85 | char_array_to_c(urlEncodeMap, sizeof(urlEncodeMap), "gsUrlEncodeMinMap"); 86 | } 87 | 88 | static void hexdecodemap(void) 89 | { 90 | uint32_t i; 91 | uint32_t map[256]; 92 | for (i = 0; i <= 255; ++i) { 93 | map[i] = 256; 94 | } 95 | 96 | /* digits */ 97 | for (i = '0'; i <= '9'; ++i) { 98 | map[i] = i - '0'; 99 | } 100 | 101 | /* upper */ 102 | for (i = 'A'; i <= 'F'; ++i) { 103 | map[i] = i - 'A' + 10; 104 | } 105 | 106 | /* lower */ 107 | for (i = 'a'; i <= 'f'; ++i) { 108 | map[i] = i - 'a' + 10; 109 | } 110 | 111 | uint32_array_to_c(map, sizeof(map) / sizeof(uint32_t), "gsHexDecodeMap"); 112 | } 113 | 114 | int main(void) 115 | { 116 | urlencodemap(); 117 | urlencodeminmap(); 118 | hexdecodemap(); 119 | hexencodemap(); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /src/modp_html.c: -------------------------------------------------------------------------------- 1 | /* 2 | *
      3 |  * modp_html xml decoders
      4 |  * https://github.com/client9/stringencoders
      5 |  *
      6 |  * Copyright © 2013-2016  Nick Galbreath
      7 |  * All rights reserved.
      8 |  * Released under MIT license. See LICENSE for details.
      9 |  * 
    10 | */ 11 | #include "modp_html.h" 12 | #include "modp_html_named_entities.h" 13 | 14 | static const int gsHexDecodeMap[256] = { 15 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 16 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 17 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 18 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 19 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, 20 | 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, 21 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 22 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 23 | 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, 24 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 25 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 26 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 27 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 28 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 29 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 30 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 31 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 32 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 33 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 34 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 35 | 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 36 | 256, 256, 256, 256 37 | }; 38 | 39 | int modp_html_decode_char_at(const char* src, size_t len, size_t* consumed) 40 | { 41 | if (len == 0 || src == NULL) { 42 | *consumed = 0; 43 | return -1; 44 | } 45 | 46 | *consumed = 1; 47 | if (*src != '&' || len < 2) { 48 | return (uint8_t)(*src); 49 | } 50 | 51 | int val = 0; 52 | size_t i; 53 | int ch; 54 | if (*(src + 1) == '#') { 55 | val = 0; 56 | if (*(src + 2) == 'x' || *(src + 2) == 'X') { 57 | i = 3; 58 | ch = (uint8_t)(*(src + 3)); 59 | ch = gsHexDecodeMap[ch]; 60 | if (ch == 256) { 61 | /* degenerate case '&#[?]' */ 62 | return '&'; 63 | } 64 | val = ch; 65 | i = 4; 66 | while (i < len) { 67 | ch = (uint8_t)src[i]; 68 | if (ch == ';') { 69 | *consumed = i + 1; 70 | return val; 71 | } 72 | ch = gsHexDecodeMap[ch]; 73 | if (ch == 256) { 74 | *consumed = i; 75 | return val; 76 | } 77 | val = (val * 16) + ch; 78 | if (val > 0x1000FF) { 79 | return '&'; 80 | } 81 | ++i; 82 | } 83 | *consumed = i; 84 | return val; 85 | } else { 86 | i = 2; 87 | ch = (uint8_t)src[i]; 88 | if (ch < '0' || ch > '9') { 89 | return '&'; 90 | } 91 | val = ch - '0'; 92 | i += 1; 93 | while (i < len) { 94 | ch = (uint8_t)src[i]; 95 | if (ch == ';') { 96 | *consumed = i + 1; 97 | return val; 98 | } 99 | if (ch < '0' || ch > '9') { 100 | *consumed = i; 101 | return val; 102 | } 103 | val = (val * 10) + (ch - '0'); 104 | if (val > 0x1000FF) { 105 | return '&'; 106 | } 107 | ++i; 108 | } 109 | *consumed = i; 110 | return val; 111 | } 112 | } else { 113 | /* case &[^#] -- check for named entity */ 114 | /* named entities are surprisingly complicated 115 | * * case sensitive 116 | * * may or maybe end in ";" 117 | * * longest match 118 | */ 119 | int codepoint = html_named_entity_decode(src + 1, len - 1, consumed); 120 | if (codepoint == 0) { 121 | *consumed = 1; 122 | return '&'; 123 | } else { 124 | *consumed += 1; 125 | return codepoint; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/modp_html.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_html.h 3 | * \brief Experimental HTML decoder 4 | * 5 | * This is mostly experimental. 6 | */ 7 | 8 | /* 9 | *
    10 |  * High Performance HTML Decoder (for now)
    11 |  *
    12 |  * Copyright © 2013-2016 Nick Galbreath
    13 |  * All rights reserved.
    14 |  *
    15 |  * https://github.com/client9/stringencoders
    16 |  *
    17 |  * Released under MIT license.  See LICENSE for details.
    18 |  * 
    19 | */ 20 | 21 | #ifndef COM_MODP_STRINGENCODERS_HTML 22 | #define COM_MODP_STRINGENCODERS_HTML 23 | 24 | #include "modp_stdint.h" 25 | 26 | #ifdef __cplusplus 27 | #define BEGIN_C extern "C" { 28 | #define END_C } 29 | #else 30 | #define BEGIN_C 31 | #define END_C 32 | #endif 33 | 34 | BEGIN_C 35 | 36 | /** 37 | * \brief HTML decode a single character 38 | * 39 | * \param[in] str The input string 40 | * \param[in] len The length of the input string, excluding any 41 | * final null byte. 42 | * \param[out] Number of characters consumed 43 | * \return unicode character value or -1 if error 44 | * 45 | * Decode numerical entities (decimal or hexadecimal), 46 | * and all named characters 47 | * 48 | */ 49 | int modp_html_decode_char_at(const char* str, size_t len, size_t* consumed); 50 | 51 | END_C 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/modp_json.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_json.h 3 | * \brief ad-hoc json generator 4 | * 5 | * Used to serialize data structures. 6 | * 7 | * There is no decoder. 8 | */ 9 | 10 | /* 11 | *
     12 |  * High Performance c-string to javascript-string encoder
     13 |  *
     14 |  * Copyright © 2014-2016 Nick Galbreath
     15 |  * All rights reserved.
     16 |  *
     17 |  * https://github.com/client9/stringencoders
     18 |  *
     19 |  * Released under MIT license.  See LICENSE for details.
     20 |  * 
    21 | */ 22 | 23 | #ifndef COM_MODP_STRINGENCODERS_BJSON 24 | #define COM_MODP_STRINGENCODERS_BJSON 25 | 26 | #ifdef __cplusplus 27 | #ifndef MODP_C_BEGIN_DECLS 28 | #define MODP_C_BEGIN_DECLS extern "C" { 29 | #define MODP_C_END_DECLS } 30 | #endif 31 | #else 32 | #define MODP_C_BEGIN_DECLS 33 | #define MODP_C_END_DECLS 34 | #endif 35 | 36 | MODP_C_BEGIN_DECLS 37 | 38 | #ifndef JSON_MAX_DEPTH 39 | #define JSON_MAX_DEPTH 10 40 | #endif 41 | 42 | /* pull in size_t */ 43 | #include 44 | #include 45 | 46 | typedef struct { 47 | int depth; 48 | int state[JSON_MAX_DEPTH]; 49 | size_t size; 50 | char* dest; 51 | } modp_json_ctx; 52 | 53 | void modp_json_init(modp_json_ctx* ctx, char* dest); 54 | size_t modp_json_end(modp_json_ctx* ctx); 55 | void modp_json_map_open(modp_json_ctx* ctx); 56 | void modp_json_map_close(modp_json_ctx* ctx); 57 | void modp_json_ary_open(modp_json_ctx* ctx); 58 | void modp_json_ary_close(modp_json_ctx* ctx); 59 | 60 | /* 61 | * 62 | * Note: to add a 'null string' explicitly use 'add_null' and do NOT 63 | * pass in a null pointer here. 64 | */ 65 | void modp_json_add_string(modp_json_ctx* ctx, const char*, size_t); 66 | 67 | void modp_json_add_cstring(modp_json_ctx* ctx, const char*); 68 | 69 | /* 70 | * Sets a json 'false' value if val = 0, other wise sets a 'true' value 71 | */ 72 | void modp_json_add_bool(modp_json_ctx* ctx, int val); 73 | 74 | void modp_json_add_double(modp_json_ctx* ctx, double d); 75 | 76 | void modp_json_add_int32(modp_json_ctx* ctx, int val); 77 | 78 | void modp_json_add_uint32(modp_json_ctx* ctx, uint32_t val); 79 | 80 | /** 81 | * JSON/Javascript only supports a single number type represented by a 82 | * 64-bit IEEE floating-point value. This means JSON can not exactly 83 | * represent a full 64-bit integer since the mantissa of a double is 84 | * only 53 bits. If the input integer needs more than 53 bits then 85 | * the value is stored as string "1234567899329342" instead of a 86 | * raw/naked numeric value. If you wish to anyways represent 64-bit 87 | * integers as a string, use stringonly=1. If you wish to never 88 | * casting to a string, use add_uint32 or add_int32 which can be 89 | * expressed directly or consider loosing precession and cast to a 90 | * double value. 91 | * 92 | */ 93 | void modp_json_add_uint64(modp_json_ctx* ctx, uint64_t val, 94 | int stringonly); 95 | 96 | /* 97 | * explicitly add a null type 98 | */ 99 | void modp_json_add_null(modp_json_ctx* ctx); 100 | 101 | MODP_C_END_DECLS 102 | 103 | #endif /* modp_bjson */ 104 | -------------------------------------------------------------------------------- /src/modp_json_data.h: -------------------------------------------------------------------------------- 1 | static const uint8_t gsJSONEncodeMap[256] = { 2 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 3 | 'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u', 4 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 5 | 'u', 'u', 'a', 'a', '"', 'a', 'a', 'a', 'a', 'a', 6 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 7 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 8 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 9 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 10 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 11 | 'a', 'a', '\\', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 12 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 13 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 14 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'u', 'u', 15 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 16 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 17 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 18 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 19 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 20 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 21 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 22 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 23 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 24 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 25 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 26 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 27 | 'u', 'u', 'u', 'u', 'u', 'u', 28 | }; 29 | 30 | static const size_t gsJSONEncodeLenMap[256] = { 31 | 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 32 | 2, 6, 2, 2, 6, 6, 6, 6, 6, 6, 33 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 34 | 6, 6, 1, 1, 2, 1, 1, 1, 1, 1, 35 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 37 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 38 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 39 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40 | 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 41 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 42 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 43 | 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 44 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 45 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 46 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 47 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 48 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 49 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 50 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 51 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 52 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 53 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 54 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 55 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 56 | 6, 6, 6, 6, 6, 6, 57 | }; 58 | -------------------------------------------------------------------------------- /src/modp_json_gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | def intarray_to_c(ary, name): 4 | parts = [] 5 | parts.append("static const size_t {0}[{1}] = {{".format(name,len(ary))) 6 | count = 0 7 | for val in ary: 8 | if (count % 10 == 0): 9 | parts.append("\n ") 10 | parts.append("{0}, ".format(val)) 11 | count += 1 12 | parts.append("\n};\n") 13 | return ''.join(parts) 14 | 15 | def chararray_to_c(ary, name): 16 | parts = [] 17 | parts.append("static const uint8_t {0}[{1}] = {{".format(name, 18 | len(ary))) 19 | count = 0; 20 | for val in ary: 21 | if (count % 10 == 0): 22 | parts.append("\n ") 23 | parts.append("{0:>6}".format("'" + val + "',")) 24 | count += 1 25 | 26 | parts.append("\n};\n") 27 | return ''.join(parts) 28 | 29 | def json_encodelen_map(): 30 | lenmap = [ 6 for i in range(256) ] 31 | for i in range(32,128): 32 | lenmap[i] = 1 33 | for i in [0x08, 0x09, 0x0a, 0x0c, 0x0d, 0x5c, 0x22]: 34 | lenmap[i] = 2 35 | return lenmap 36 | 37 | def json_encode_map(): 38 | encodemap = [ 'u' for i in range(256) ] 39 | 40 | # things to quad-hex encode \u00XY 41 | for i in range(32,128): 42 | encodemap[i] = 'a'; 43 | 44 | # special escapes 45 | encodemap[0x08] = 'b' 46 | encodemap[0x09] = 't' 47 | encodemap[0x0a] = 'n' 48 | encodemap[0x0c] = 'f' 49 | encodemap[0x0d] = 'r' 50 | encodemap[0x5c] = "\\\\" 51 | encodemap[0x22] = "\"" 52 | 53 | return encodemap 54 | 55 | if __name__ == '__main__': 56 | 57 | with open('modp_json_data.h', 'w') as fd: 58 | fd.write(chararray_to_c(json_encode_map(), "gsJSONEncodeMap")) 59 | fd.write("\n") 60 | fd.write(intarray_to_c(json_encodelen_map(), "gsJSONEncodeLenMap")) 61 | -------------------------------------------------------------------------------- /src/modp_mainpage.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \mainpage 3 | * 4 | * The modp_b family of encoders/decoders. 5 | * 6 | * Most have a similar interface: 7 | * - modp_bXXX_encode(char* dest, char* src, int len) -- encodes src, and puts the result in dest. The caller allocates dest. It returns the strlen of the output. 8 | * - modp_bXXX_encode_len(int len) -- returns the amount of memory needed to be allocated BEFORE calling _encode. 9 | * - modp_bXXX_encode_strlen(int len) -- returns the strlen of the encoded output (but without doing the encode operation) 10 | * - modp_bXXX_decode(char* dest, char* src, int len) -- decodes src and puts result in dest. Returns the number of bytes written. 11 | * - modp_bXXX_decode_len(int len) -- the amount of memory needed to decode. 12 | * 13 | * The header files all include a sample C++ std::string wrapper. 14 | * 15 | * In addition: 16 | * - modp_numtoa.h defines fast integer and float types to char buffer converts. 17 | * - modp_ascii.h defines fast toupper, tolower transformations. 18 | * 19 | * \section modp_b64 20 | * 21 | * Converts 3 bytes into 4 characters, for 1.33 expansion ratio. This 22 | * version is ridiculously fast -- on some platforms the decode 23 | * operation is 4x faster than a standard implementation. 24 | * 25 | * See modp_b64.h for details 26 | * 27 | * \section modp_b64w 28 | * 29 | * Does the same type of transformation as modp_b64 but uses a 30 | * slightly different alphabet to make it "safe" to use inside a URL. 31 | * The mapping is: "/" to "_", * "+" to "-", * "=" to "." If you are 32 | * intergating with another base64 encoder, you may need to change 33 | * this. 34 | * 35 | * See modp_b64w.h for details. 36 | * 37 | * 38 | * \section modp_b16 39 | * 40 | * This is the standard "binary to ascii" encoding that convert 1 byte 41 | * into two chars (0-9, a-f). It's actually slower than base64 so 42 | * there is not reason to use this except for legacy applications. 43 | * (how can this be? Because on decode we have to read 4 bytes to get 44 | * 2. and in base64 we read 4 bytes to get 3, so base64's loop is 45 | * shorter). 46 | * 47 | * See modp_b16.h for details 48 | * 49 | * \section modp_b85 50 | * 51 | * Base 85 is the "most dense ascii encoding" possible, converting 4 52 | * bytes into 5 chars (1.2). The output is 11% smaller than base 64 53 | * (1.33/1.2), but unfortunately, it's about twice as slow as base-64 54 | * encoding since true division has to be used (instead of raw bit 55 | * operations). 56 | * 57 | * See modp_b85.h for details 58 | * 59 | * \section mod_b2 60 | * 61 | * Converts the given string to a base 2 or binary encoding (all 62 | * 1s and 0s). For useful for debugging. 63 | * 64 | * See modp_b2.h for details 65 | * 66 | * \section modp_burl 67 | * 68 | * This performs url-encoding and url-decoding. While not a true base 69 | * converted like the others, it does use an optimized base-16 70 | * converter for the encoded "%XY" data. This has an alternate 71 | * encoder that provides a minimal encoding, modp_burl_min_encode. 72 | * 73 | * See modp_burl.h for details 74 | * 75 | * \section modp_bjavascript 76 | * 77 | * Converts a raw c-string into something that can be enbedded into 78 | * javascript. This might be useful for server-generated dynamic 79 | * javascript. There is no decode function provided. This is only 80 | * use when generating raw "text/javascript" files. It is NOT 81 | * safe to make javascript that will ultimately be embedded inside 82 | * HTML via script tags. 83 | * 84 | * See modp_bjavascript.h for details 85 | * 86 | * \section modp_xml 87 | * 88 | * An experimental XML decoder. 89 | * 90 | * See modp_xml.h for details 91 | * 92 | * \section modp_numtoa 93 | * 94 | * The functions modp_itoa, modp_uitoa, modp_dtoa converts signed integers, 95 | * unsigned integers, and 'double' type conversion to char buffer (string). 96 | * The advantages over sprintf/snprintf are 97 | * - core dump proof 98 | * - have a fixed maximum size (e.g. try printf("%f", 2.0e100) for example) 99 | * - 5-22x faster! 100 | * 101 | * See modp_numtoa.h for details 102 | * 103 | * \section modp_ascii 104 | * 105 | * modp_toupper and modp_tolower upper or lower case a string using 106 | * the standard C locale (i.e. 7-bit ascii). These are 2-22x faster 107 | * than using standard ctype functions. Also include is "toprint" 108 | * which replaces "unprintable" characters with a "?". 109 | * 110 | * See modp_ascii.h for details 111 | * 112 | * \section modp_qsiter 113 | * 114 | * URL Query string key-value pair iterator. Uses no heap, makes no 115 | * copy, makes no modification of input. Think of this as a 116 | * super-strtok_r. 117 | * 118 | * See modp_qsiter.h for details 119 | * 120 | */ 121 | -------------------------------------------------------------------------------- /src/modp_numtoa.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_numtoa.h 3 | * \brief Fast integer and floating-point numbers to string conversion 4 | * 5 | * This defines signed/unsigned integer, and 'double' to char buffer 6 | * converters. The standard way of doing this is with "sprintf", however 7 | * these functions are 8 | * * guaranteed maximum size output 9 | * * 5-20x faster! 10 | * * Won't core-dump 11 | * 12 | */ 13 | 14 | /** 15 | *
     16 |  * Copyright © 2007, Nick Galbreath -- nickg [at] client9 [dot] com
     17 |  * All rights reserved.
     18 |  * https://github.com/client9/stringencoders/
     19 |  * Released under the MIT license.  See LICENSE for details.
     20 |  * 
    21 | * 22 | */ 23 | 24 | #ifndef COM_MODP_STRINGENCODERS_NUMTOA_H 25 | #define COM_MODP_STRINGENCODERS_NUMTOA_H 26 | 27 | #include "extern_c_begin.h" 28 | 29 | #include "modp_stdint.h" 30 | 31 | /** \brief convert an signed integer to char buffer 32 | * 33 | * \param[in] value 34 | * \param[out] buf the output buffer. Should be 16 chars or more. 35 | */ 36 | size_t modp_itoa10(int32_t value, char* buf); 37 | 38 | /** \brief convert an unsigned integer to char buffer 39 | * 40 | * \param[in] value 41 | * \param[out] buf The output buffer, should be 16 chars or more. 42 | */ 43 | size_t modp_uitoa10(uint32_t value, char* buf); 44 | 45 | /** \brief convert an signed long integer to char buffer 46 | * 47 | * \param[in] value 48 | * \param[out] buf the output buffer. Should be 24 chars or more. 49 | */ 50 | size_t modp_litoa10(int64_t value, char* buf); 51 | 52 | /** \brief convert an unsigned long integer to char buffer 53 | * 54 | * \param[in] value 55 | * \param[out] buf The output buffer, should be 24 chars or more. 56 | */ 57 | size_t modp_ulitoa10(uint64_t value, char* buf); 58 | 59 | /** \brief convert a floating point number to char buffer with 60 | * fixed-precision format 61 | * 62 | * This is similar to "%.[0-9]f" in the printf style. It will include 63 | * trailing zeros 64 | * 65 | * If the input value is greater than 1<<31, then the output format 66 | * will be switched exponential format. 67 | * 68 | * \param[in] value 69 | * \param[out] buf The allocated output buffer. Should be 32 chars or more. 70 | * \param[in] precision Number of digits to the right of the decimal point. 71 | * Can only be 0-9. 72 | */ 73 | size_t modp_dtoa(double value, char* buf, int precision); 74 | 75 | /** \brief convert a floating point number to char buffer with a 76 | * variable-precision format, and no trailing zeros 77 | * 78 | * This is similar to "%.[0-9]f" in the printf style, except it will 79 | * NOT include trailing zeros after the decimal point. This type 80 | * of format oddly does not exists with printf. 81 | * 82 | * If the input value is greater than 1<<31, then the output format 83 | * will be switched exponential format. 84 | * 85 | * \param[in] value 86 | * \param[out] buf The allocated output buffer. Should be 32 chars or more. 87 | * \param[in] precision Number of digits to the right of the decimal point. 88 | * Can only be 0-9. 89 | */ 90 | size_t modp_dtoa2(double value, char* buf, int precision); 91 | 92 | /** 93 | * adds a 8-character hexadecimal representation of value 94 | * 95 | */ 96 | char* modp_uitoa16(uint32_t value, char* buf, int final); 97 | 98 | #include "extern_c_end.h" 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/modp_qsiter.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file 3 | *
     4 |  * modp_qs.c query string key-value pair iterator
     5 |  * https://github.com/client9/stringencoders
     6 |  *
     7 |  * Copyright © 2012-2016  Nick Galbreath
     8 |  * All rights reserved.
     9 |  * Released under MIT license. See LICENSE for details.
    10 |  * 
    11 | */ 12 | 13 | #include "modp_qsiter.h" 14 | 15 | void qsiter_reset(struct qsiter_t* qsi, const char* s, size_t len) 16 | { 17 | qsi->s = s; 18 | qsi->len = len; 19 | qsi->pos = 0; 20 | 21 | qsi->key = NULL; 22 | qsi->keylen = 0; 23 | qsi->val = NULL; 24 | qsi->vallen = 0; 25 | } 26 | 27 | int qsiter_next(struct qsiter_t* qsi) 28 | { 29 | const char* eq; 30 | const char* charstart; 31 | const char* ends; 32 | 33 | if (qsi->pos >= qsi->len) { 34 | qsi->key = NULL; 35 | qsi->keylen = 0; 36 | qsi->val = NULL; 37 | qsi->vallen = 0; 38 | return 0; 39 | } 40 | 41 | charstart = qsi->s + qsi->pos; 42 | ends = (const char*)memchr(charstart, '&', qsi->len - qsi->pos); 43 | 44 | if (ends == NULL) { 45 | eq = (const char*)memchr(charstart, '=', qsi->len - qsi->pos); 46 | if (eq == NULL) { 47 | qsi->key = charstart; 48 | qsi->keylen = (size_t)(qsi->len - qsi->pos); 49 | qsi->val = NULL; 50 | qsi->vallen = (size_t)0; 51 | } else { 52 | qsi->key = charstart; 53 | qsi->keylen = (size_t)(eq - charstart); 54 | qsi->val = eq + 1; 55 | qsi->vallen = (size_t)((qsi->s + qsi->len) - qsi->val); 56 | } 57 | qsi->pos = qsi->len; 58 | return 1; 59 | } else { 60 | /* &&foo=bar */ 61 | eq = (const char*)memchr(charstart, '=', (size_t)(ends - charstart)); 62 | if (eq == NULL) { 63 | qsi->key = charstart; 64 | qsi->keylen = (size_t)(ends - charstart); 65 | qsi->val = NULL; 66 | qsi->vallen = (size_t)0; 67 | } else { 68 | qsi->key = charstart; 69 | qsi->keylen = (size_t)(eq - charstart); 70 | qsi->val = eq + 1; 71 | qsi->vallen = (size_t)(ends - eq - 1); 72 | } 73 | qsi->pos = (size_t)((ends - qsi->s) + 1); 74 | return 1; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/modp_qsiter.h: -------------------------------------------------------------------------------- 1 | #ifndef COM_MODP_QSITER 2 | #define COM_MODP_QSITER 3 | 4 | #include 5 | 6 | #include "extern_c_begin.h" 7 | 8 | /** 9 | * \file modp_qsiter.h 10 | * \brief URL Query string key-value pair iterator. Uses no heap, makes 11 | * no copy, makes no modification of input. Think of this as a 12 | * super-strtok_r. 13 | * 14 | * This also does not do query-string un-escaping. 15 | * 16 | * \code 17 | * qsiiter_t qsi; 18 | * const char* qs = "foo=bar&ding=bar"; 19 | * qsiter_reset(&qsi, qs, strlen(qs)); 20 | * while (qsiter_next(&qsi)) { 21 | * // we only get start and length of key,value 22 | * // up to you how to copy it or not, on heap or stack 23 | * // with strcpy, strncpy, strndup, memcpy, mempcpy, strlcpy, whatever 24 | * // callers job to alloc/free memory 25 | * 26 | * const char* key = (const char*) malloc(qsi.keylen + 1); 27 | * strcpy(key, qsi->key, qsi->keylen); 28 | * const char* val = (const char*) malloc(qsi.vallen + 1); 29 | * strcpy(val, qsi->val, qsi->vallen); 30 | * printf("key = %s, value = %s\n", key, val); 31 | * free(key); 32 | * free(value); 33 | * } 34 | * \endcode 35 | * 36 | */ 37 | struct qsiter_t { 38 | const char* s; 39 | size_t pos; 40 | size_t len; 41 | 42 | const char* key; 43 | size_t keylen; 44 | 45 | const char* val; 46 | size_t vallen; 47 | }; 48 | 49 | /** 50 | * Reset a qsiter to an initial start (constructor) 51 | * 52 | * This does not modifiy the original string, nor makes a copy. 53 | * 54 | * \param[out] qsi data struct used in iterator 55 | * \param[in] s input string (does not need to be 0-terminated) 56 | * \param[in] len input string length 57 | * 58 | */ 59 | void qsiter_reset(struct qsiter_t* qsi, const char* s, size_t len); 60 | 61 | /** 62 | * Get next key/value pair in query string 63 | * 64 | * \param[out] qsi data struct 65 | * \return 1 if found a key value pair, 0 if no more data 66 | */ 67 | int qsiter_next(struct qsiter_t* qsi); 68 | 69 | #include "extern_c_end.h" 70 | 71 | #endif /* MODP_QSITER */ 72 | -------------------------------------------------------------------------------- /src/modp_stdint.h: -------------------------------------------------------------------------------- 1 | /* vi: set ft=c expandtab shiftwidth=4 tabstop=4: */ 2 | #ifndef MODP_STDINT_H_ 3 | #define MODP_STDINT_H_ 4 | 5 | /** 6 | * \file modp_stdint.h 7 | * \brief An attempt to make stringencoders compile under windows 8 | * 9 | * This attempts to define various integral types that are normally 10 | * defined in stdint.h and stdbool.h which oddly don't exit on 11 | * windows. 12 | * 13 | * Please file bugs or patches if it doesn't work! 14 | */ 15 | 16 | #include 17 | 18 | #ifndef _WIN32 19 | #include 20 | #include 21 | #else 22 | /* win64 is llp64 so these are the same for 32/64bit 23 | so no check for _WIN64 is required. 24 | */ 25 | typedef unsigned char uint8_t; 26 | typedef signed char int8_t; 27 | typedef unsigned short uint16_t; 28 | typedef signed short int16_t; 29 | typedef unsigned int uint32_t; 30 | typedef signed int int32_t; 31 | typedef unsigned __int64 uint64_t; 32 | typedef signed __int64 int64_t; 33 | 34 | /* windows doesn't do C99 and stdbool */ 35 | 36 | #ifndef __cplusplus 37 | typedef unsigned char bool; 38 | #define true 1 39 | #define false 0 40 | #endif 41 | 42 | #endif /* _WIN32 */ 43 | #endif /* MODP_STDINT_H_ */ 44 | -------------------------------------------------------------------------------- /src/modp_utf8.c: -------------------------------------------------------------------------------- 1 | #include 2 | /** 3 | * \file modp_utf8.c 4 | *
     5 |  * MODP_UTF8 - UTF8 string utilities
     6 |  * https://github.com/client9/stringencoders/
     7 |  *
     8 |  * Copyright 2013-2016  Nick Galbreath -- nickg [at] client9 [dot] com
     9 |  * All rights reserved.
    10 |  * Released under MIT license. See LICENSE for details.
    11 |  * 
    12 | */ 13 | 14 | #include "config.h" 15 | #include "modp_utf8.h" 16 | #include 17 | 18 | int modp_utf8_validate(const char* src_orig, size_t len) 19 | { 20 | const uint8_t* src = (const uint8_t*)src_orig; 21 | const uint8_t* srcend = src + len; 22 | uint8_t c, c1, c2, c3; 23 | int d; 24 | while (src < srcend) { 25 | c = *src; 26 | if (c < 0x80) { 27 | src += 1; 28 | } else if (c < 0xE0) { 29 | /* c starts with 110 */ 30 | if (srcend - src < 2) { 31 | return MODP_UTF8_SHORT; 32 | } 33 | c1 = *(src + 1); 34 | if ((c1 & 0xC0) != 0x80) { 35 | return MODP_UTF8_INVALID; 36 | } 37 | d = ((c & 0x1F) << 6) | (c1 & 0x3F); 38 | if (d < 0x80) { 39 | return MODP_UTF8_OVERLONG; 40 | } 41 | src += 2; 42 | } else if (c < 0xF0) { 43 | if (srcend - src < 3) { 44 | return MODP_UTF8_SHORT; 45 | } 46 | c1 = *(src + 1); 47 | c2 = *(src + 2); 48 | if ((c1 & 0xC0) != 0x80) { 49 | return MODP_UTF8_INVALID; 50 | } 51 | if ((c2 & 0xC0) != 0x80) { 52 | return MODP_UTF8_INVALID; 53 | } 54 | d = ((c & 0x0F) << 12) | ((c1 & 0x3F) << 6) | (c2 & 0x3F); 55 | if (d < 0x0800) { 56 | return MODP_UTF8_OVERLONG; 57 | } 58 | if (d >= 0xD800 && d <= 0xDFFF) { 59 | return MODP_UTF8_CODEPOINT; 60 | } 61 | src += 3; 62 | } else if (c < 0xF8) { 63 | if (srcend - src < 4) { 64 | return MODP_UTF8_SHORT; 65 | } 66 | c1 = *(src + 1); 67 | c2 = *(src + 2); 68 | c3 = *(src + 3); 69 | if ((c1 & 0xC0) != 0x80) { 70 | return MODP_UTF8_INVALID; 71 | } 72 | if ((c2 & 0xC0) != 0x80) { 73 | return MODP_UTF8_INVALID; 74 | } 75 | if ((c3 & 0xC0) != 0x80) { 76 | return MODP_UTF8_INVALID; 77 | } 78 | d = ((c & 0x07) << 18) | ((c1 & 0x3F) << 12) | ((c2 & 0x3F) < 6) | (c3 & 0x3F); 79 | if (d < 0x010000) { 80 | return MODP_UTF8_OVERLONG; 81 | } 82 | src += 4; 83 | } else { 84 | return MODP_UTF8_CODEPOINT; 85 | } 86 | } 87 | return MODP_UTF8_OK; 88 | } 89 | -------------------------------------------------------------------------------- /src/modp_utf8.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_utf.h 3 | * \brief Various UTF8 utilities 4 | * 5 | */ 6 | 7 | /* 8 | *
     9 |  * MODP_UTF8 -- UTF-8 utilities
    10 |  * https://github.com/client9/stringencoders
    11 |  *
    12 |  * Copyright © 2013-2016, Nick Galbreath
    13 |  * All rights reserved.
    14 |  *
    15 |  * Released under MIT license.  See LICENSE for details.
    16 |  * 
    17 | * 18 | */ 19 | 20 | #ifndef COM_MODP_UTF8 21 | #define COM_MODP_UTF8 22 | 23 | #include "extern_c_begin.h" 24 | #include "modp_stdint.h" 25 | 26 | #define MODP_UTF8_OK 0 27 | #define MODP_UTF8_SHORT 1 28 | #define MODP_UTF8_INVALID 2 29 | #define MODP_UTF8_OVERLONG 3 30 | #define MODP_UTF8_CODEPOINT 4 31 | /** 32 | * Validate a UTF-8 string. 33 | * checks for blah blah blah 34 | */ 35 | int modp_utf8_validate(const char* src, size_t len); 36 | 37 | #include "extern_c_end.h" 38 | #endif /* ifndef modp_utf8 */ 39 | -------------------------------------------------------------------------------- /src/modp_xml.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file modp_xml.h 3 | * \brief Experimental XML/HTML decoder 4 | * 5 | * This is mostly experimental. 6 | */ 7 | 8 | /* 9 | *
     10 |  * High Performance XML Decoder (for now)
     11 |  *
     12 |  * Copyright © 2012-2016  Nick Galbreath
     13 |  * All rights reserved.
     14 |  *
     15 |  * Released under MIT license. See LICENSE fro details.
     16 |  *
     17 |  * https://github.com/client9/stringencoders
     18 |  *
     19 |  * 
    20 | */ 21 | 22 | #ifndef COM_MODP_STRINGENCODERS_XML 23 | #define COM_MODP_STRINGENCODERS_XML 24 | 25 | #include "modp_stdint.h" 26 | 27 | #ifdef __cplusplus 28 | #define BEGIN_C extern "C" { 29 | #define END_C } 30 | #else 31 | #define BEGIN_C 32 | #define END_C 33 | #endif 34 | 35 | BEGIN_C 36 | 37 | /** 38 | * \brief Validates a unicode code point is valid for HTML (undefined 39 | * or non-white-space control char) 40 | * 41 | * \param[in] val a unicode char expressed as a uint32_t 42 | * \return 0 if invalid, else returns passes back the input value. 43 | * 44 | * See http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#character-references for more details 45 | * 46 | * This is only exposed for testing. It is not designed for public use. 47 | */ 48 | int modp_xml_validate_unicode(int val); 49 | 50 | /** 51 | * \brief converts a unicode char expressed as uint32_t into a UTF-8 byte sequence. 52 | * \param[out] dest assumed to have at least 4 chars available in buffer. 53 | * \param[in] uval A unicode character expressed as a uint32_t type 54 | * \return 0 if input value is invalid or not a unicode character, else 55 | * returns number of bytes written to dest. 56 | * 57 | * This is only exposed for testing. It is not designed for public use. 58 | */ 59 | size_t modp_xml_unicode_char_to_utf8(char* dest, int uval); 60 | 61 | /** 62 | * \brief parse a hex encoded entity between "&#x" and ";" 63 | * \param[in] s a buffer pointing at the first char after "&$x" 64 | * \param[in] len the length of string between "&#x" and ";" 65 | * \return -1 if invalid, otherwise the unicode character value 66 | * 67 | * This is only exposed for testing. It is not designed for public use. 68 | */ 69 | int modp_xml_parse_hex_entity(const char* s, size_t len); 70 | 71 | /** 72 | * \brief parse a numerical decimal XML entity, eg. &x39; 73 | * 74 | * \param[in] s the buffer pointing to first char after '&#'. 75 | * \param[in] len the length between '&#' and ';'. It is expected 76 | * that all chars between are to be decimal digits. 77 | * \return -1 if invalid, else the unicode numeric value 78 | * 79 | * Exposed for testing. Not designed to be useful for public consumption. 80 | */ 81 | int modp_xml_parse_dec_entity(const char* s, size_t len); 82 | 83 | /** 84 | * \brief XML decode a string 85 | * \param[out] dest output string. Must 86 | * \param[in] str The input string 87 | * \param[in] len The length of the input string, excluding any 88 | * final null byte. 89 | * \return the final size of the output, excluding any ending null byte. 90 | * 91 | * Decode numerical entities (decimal or hexadecimal), and following named 92 | * entities: 93 | * * ' 94 | * * " 95 | * * & 96 | * * < 97 | * * > 98 | * 99 | */ 100 | size_t modp_xml_decode(char* dest, const char* str, size_t len); 101 | 102 | /** 103 | * \brief XML encode a UTF-8 string 104 | * \param[out] dest output string. 105 | * \param[in] str The input string 106 | * \param[in] len The length of the input string, excluding any 107 | * final null byte. 108 | * \return the final size of the output, excluding any ending null byte. 109 | * Encodes an assumed valid UTF-8 input and escapes 110 | * * ' 111 | * * " 112 | * * & 113 | * * < 114 | * * > 115 | */ 116 | size_t modp_xml_encode(char* dest, const char* str, size_t len); 117 | 118 | size_t modp_xml_min_encode_strlen(const char* str, size_t len); 119 | 120 | END_C 121 | 122 | #ifdef __cplusplus 123 | #include 124 | #include 125 | 126 | namespace modp { 127 | 128 | /** 129 | * Url decode a string. 130 | * This function does not allocate memory. 131 | * 132 | * \param[in,out] s the string to be decoded 133 | * \return a reference to the input string. 134 | * There is no error case, bad characters are passed through 135 | */ 136 | inline std::string& xml_decode(std::string& s) 137 | { 138 | size_t d = modp_xml_decode(const_cast(s.data()), s.data(), s.size()); 139 | s.erase(d, std::string::npos); 140 | return s; 141 | } 142 | 143 | inline std::string xml_decode(const char* str) 144 | { 145 | std::string s(str); 146 | xml_decode(s); 147 | return s; 148 | } 149 | 150 | inline std::string xml_decode(const char* str, size_t len) 151 | { 152 | std::string s(str, len); 153 | xml_decode(s); 154 | return s; 155 | } 156 | 157 | inline std::string xml_decode(const std::string& s) 158 | { 159 | std::string x(s); 160 | xml_decode(x); 161 | return x; 162 | } 163 | } 164 | #endif 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /src/stringencoders.pc: -------------------------------------------------------------------------------- 1 | prefix=/usr/local 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib 4 | includedir=${prefix}/include 5 | 6 | Name: stringencoders 7 | Description: collection of high performance c-string transformations 8 | Version: v3.10.3 9 | Libs: -L${libdir} -lmodpbase64 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /src/stringencoders.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: stringencoders 7 | Description: collection of high performance c-string transformations 8 | Version: @PACKAGE_VERSION@ 9 | Libs: -L${libdir} -lmodpbase64 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | STRINGENCODERS_INCLUDE = -I$(top_srcdir)/src 3 | STRINGENCODERS_LTLIB = $(top_srcdir)/src/libmodpbase64.la 4 | 5 | check_PROGRAMS = \ 6 | modp_ascii_test \ 7 | modp_b2_test \ 8 | modp_b16_test \ 9 | modp_b64_test \ 10 | modp_b64r_test \ 11 | modp_b64w_test \ 12 | modp_b85_test \ 13 | modp_burl_test \ 14 | modp_bjavascript_test \ 15 | modp_numtoa_test \ 16 | modp_utf8_test \ 17 | modp_xml_test \ 18 | modp_html_test \ 19 | modp_json_test \ 20 | modp_qsiter_test \ 21 | cxx_test 22 | 23 | TESTS = $(check_PROGRAMS) 24 | 25 | noinst_PROGRAMS = \ 26 | speedtest \ 27 | speedtest_numtoa \ 28 | speedtest_msg 29 | 30 | speedtest_SOURCES = apr_base64.h apr_base64.c speedtest.c 31 | speedtest_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 32 | speedtest_LDADD = $(STRINGENCODERS_LTLIB) 33 | 34 | speedtest_numtoa_SOURCES = speedtest_numtoa.c 35 | speedtest_numtoa_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 36 | speedtest_numtoa_LDADD = $(STRINGENCODERS_LTLIB) 37 | 38 | speedtest_msg_SOURCES = speedtest_msg.c 39 | speedtest_msg_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 40 | speedtest_msg_LDADD = $(STRINGENCODERS_LTLIB) 41 | 42 | modp_b2_test_SOURCES = modp_b2_test.c 43 | modp_b2_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 44 | modp_b2_test_LDADD = $(STRINGENCODERS_LTLIB) 45 | 46 | modp_b16_test_SOURCES = modp_b16_test.c 47 | modp_b16_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 48 | modp_b16_test_LDADD = $(STRINGENCODERS_LTLIB) 49 | 50 | modp_b64_test_SOURCES = modp_b64_test.c 51 | modp_b64_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 52 | modp_b64_test_LDADD = $(STRINGENCODERS_LTLIB) 53 | 54 | modp_b64w_test.c: modp_b64_test.c 55 | perl -p -i -e 's/b64/b64w/g' < modp_b64_test.c > modp_b64w_test.c 56 | 57 | modp_b64w_test_SOURCES = modp_b64w_test.c 58 | modp_b64w_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 59 | modp_b64w_test_LDADD = $(STRINGENCODERS_LTLIB) 60 | 61 | modp_b64r_test.c: modp_b64_test.c 62 | perl -p -i -e 's/b64/b64r/g' < modp_b64_test.c > modp_b64r_test.c 63 | 64 | modp_b64r_test_SOURCES = modp_b64r_test.c 65 | modp_b64r_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 66 | modp_b64r_test_LDADD = $(STRINGENCODERS_LTLIB) 67 | 68 | modp_b85_test_SOURCES = modp_b85_test.c 69 | modp_b85_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 70 | modp_b85_test_LDADD = $(STRINGENCODERS_LTLIB) 71 | 72 | modp_burl_test_SOURCES = modp_burl_test.c 73 | modp_burl_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 74 | modp_burl_test_LDADD = $(STRINGENCODERS_LTLIB) 75 | 76 | modp_bjavascript_test_SOURCES = modp_bjavascript_test.c 77 | modp_bjavascript_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 78 | modp_bjavascript_test_LDADD = $(STRINGENCODERS_LTLIB) 79 | 80 | modp_ascii_test_SOURCES = modp_ascii_test.c 81 | modp_ascii_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 82 | modp_ascii_test_LDADD = $(STRINGENCODERS_LTLIB) 83 | 84 | modp_xml_test_SOURCES = modp_xml_test.c 85 | modp_xml_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 86 | modp_xml_test_LDADD = $(STRINGENCODERS_LTLIB) 87 | 88 | modp_numtoa_test_SOURCES = modp_numtoa_test.c 89 | modp_numtoa_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 90 | modp_numtoa_test_LDADD = $(STRINGENCODERS_LTLIB) 91 | 92 | modp_html_test_SOURCES = modp_html_test.c 93 | modp_html_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 94 | modp_html_test_LDADD = $(STRINGENCODERS_LTLIB) 95 | 96 | modp_qsiter_test_SOURCES = modp_qsiter_test.c 97 | modp_qsiter_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 98 | modp_qsiter_test_LDADD = $(STRINGENCODERS_LTLIB) 99 | 100 | modp_utf8_test_SOURCES = modp_utf8_test.c 101 | modp_utf8_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 102 | modp_utf8_test_LDADD = $(STRINGENCODERS_LTLIB) 103 | 104 | modp_json_test_SOURCES = modp_json_test.c 105 | modp_json_test_CPPFLAGS = $(STRINGENCODERS_INCLUDE) 106 | modp_json_test_LDADD = $(STRINGENCODERS_LTLIB) 107 | 108 | cxx_test_SOURCES = cxx_test.cc 109 | cxx_test_CPPFLAGS =$(STRINGENCODERS_INCLUDE) 110 | cxx_test_LDADD = $(STRINGENCODERS_LTLIB) 111 | 112 | clean-local: 113 | rm -f *~ 114 | -------------------------------------------------------------------------------- /test/apr_base64.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as 2 | * applicable. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * The apr_vsnprintf/apr_snprintf functions are based on, and used with the 16 | * permission of, the SIO stdio-replacement strx_* functions by Panos 17 | * Tsirigotis for xinetd. 18 | */ 19 | 20 | /** 21 | * @file apr_base64.h 22 | * @brief APR-UTIL Base64 Encoding 23 | */ 24 | #ifndef APR_BASE64_H 25 | #define APR_BASE64_H 26 | 27 | /* 28 | //#include "apu.h" 29 | //#include "apr_general.h" 30 | */ 31 | #define APU_DECLARE(x) x 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | /** 38 | * @defgroup APR_Util_Base64 Base64 Encoding 39 | * @ingroup APR_Util 40 | * @{ 41 | */ 42 | 43 | /* Simple BASE64 encode/decode functions. 44 | * 45 | * As we might encode binary strings, hence we require the length of 46 | * the incoming plain source. And return the length of what we decoded. 47 | * 48 | * The decoding function takes any non valid char (i.e. whitespace, \0 49 | * or anything non A-Z,0-9 etc as terminal. 50 | * 51 | * plain strings/binary sequences are not assumed '\0' terminated. Encoded 52 | * strings are neither. But probably should. 53 | * 54 | */ 55 | 56 | /** 57 | * Given the length of an un-encrypted string, get the length of the 58 | * encrypted string. 59 | * @param len the length of an unencrypted string. 60 | * @return the length of the string after it is encrypted 61 | */ 62 | APU_DECLARE(int) 63 | apr_base64_encode_len(int len); 64 | 65 | /** 66 | * Encode a text string using base64encoding. 67 | * @param coded_dst The destination string for the encoded string. 68 | * @param plain_src The original string in plain text 69 | * @param len_plain_src The length of the plain text string 70 | * @return the length of the encoded string 71 | */ 72 | APU_DECLARE(int) 73 | apr_base64_encode(char* coded_dst, const char* plain_src, 74 | int len_plain_src); 75 | 76 | /** 77 | * Encode an EBCDIC string using base64encoding. 78 | * @param coded_dst The destination string for the encoded string. 79 | * @param plain_src The original string in plain text 80 | * @param len_plain_src The length of the plain text string 81 | * @return the length of the encoded string 82 | */ 83 | APU_DECLARE(int) 84 | apr_base64_encode_binary(char* coded_dst, 85 | const unsigned char* plain_src, 86 | int len_plain_src); 87 | 88 | /** 89 | * Determine the length of a plain text string given the encoded version 90 | * @param coded_src The encoded string 91 | * @return the length of the plain text string 92 | */ 93 | APU_DECLARE(int) 94 | apr_base64_decode_len(const char* coded_src); 95 | 96 | /** 97 | * Decode a string to plain text 98 | * @param plain_dst The destination string for the plain text 99 | * @param coded_src The encoded string 100 | * @return the length of the plain text string 101 | */ 102 | APU_DECLARE(int) 103 | apr_base64_decode(char* plain_dst, const char* coded_src); 104 | 105 | /** 106 | * Decode an EBCDIC string to plain text 107 | * @param plain_dst The destination string for the plain text 108 | * @param coded_src The encoded string 109 | * @return the length of the plain text string 110 | */ 111 | APU_DECLARE(int) 112 | apr_base64_decode_binary(unsigned char* plain_dst, 113 | const char* coded_src); 114 | 115 | /** @} */ 116 | #ifdef __cplusplus 117 | } 118 | #endif 119 | 120 | #endif /* !APR_BASE64_H */ 121 | -------------------------------------------------------------------------------- /test/minunit.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MINUNIT_H 3 | #define MINUNIT_H 4 | 5 | /* http://www.jera.com/techinfo/jtns/jtn002.html */ 6 | 7 | #define mu_assert(test) \ 8 | do { \ 9 | if (!(test)) { \ 10 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s:%d", __FILE__, __LINE__); \ 11 | return mu_buf; \ 12 | } \ 13 | } while (0) 14 | 15 | #define mu_assert_msg(msg, test) \ 16 | do { \ 17 | if (!(test)) { \ 18 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s %s:%d", msg, __FILE__, __LINE__); \ 19 | return mu_buf; \ 20 | } \ 21 | } while (0) 22 | 23 | #define mu_assert_int_equals(lhs, rhs) \ 24 | do { \ 25 | if ((int)lhs != (int)rhs) { \ 26 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s:%d", __FILE__, __LINE__); \ 27 | return mu_buf; \ 28 | } \ 29 | } while (0) 30 | 31 | #define mu_assert_str_equals(lhs, rhs) \ 32 | do { \ 33 | if (strcmp(lhs, rhs) != 0) { \ 34 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s:%d %s != %s", __FILE__, __LINE__, lhs, rhs); \ 35 | return mu_buf; \ 36 | } \ 37 | } while (0) 38 | 39 | #define mu_assert_str_equals_msg(msg, lhs, rhs) \ 40 | do { \ 41 | if (strcmp(lhs, rhs) != 0) { \ 42 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s %s:%d %s != %s", msg, __FILE__, __LINE__, lhs, rhs); \ 43 | return mu_buf; \ 44 | } \ 45 | } while (0) 46 | 47 | #define mu_assert_int_equals_msg(msg, lhs, rhs) \ 48 | do { \ 49 | if (lhs != rhs) { \ 50 | snprintf(mu_buf, sizeof(mu_buf), "ASSERTION FAILED: %s %s:%d", msg, __FILE__, __LINE__); \ 51 | return mu_buf; \ 52 | } \ 53 | } while (0) 54 | 55 | #define mu_run_test(test) \ 56 | do { \ 57 | printf("."); \ 58 | fflush(stdout); \ 59 | char* message = test(); \ 60 | tests_run++; \ 61 | if (message) \ 62 | return message; \ 63 | } while (0) 64 | 65 | #define UNITTESTS \ 66 | int main(void) \ 67 | { \ 68 | printf("%s ", __FILE__); \ 69 | fflush(stdout); \ 70 | char* result = all_tests(); \ 71 | if (result != 0) { \ 72 | printf("%s\n", result); \ 73 | } else { \ 74 | printf("OK (%d tests)\n", tests_run); \ 75 | } \ 76 | return result != 0; \ 77 | } 78 | 79 | static int tests_run = 0; 80 | static char mu_buf[1024]; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /test/modp_b85_test.c: -------------------------------------------------------------------------------- 1 | /* we compile as C90 but use snprintf */ 2 | #define _ISOC99_SOURCE 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "minunit.h" 9 | 10 | #include "modp_b85.h" 11 | 12 | /** 13 | * checks to make sure results are the same reguardless of 14 | * CPU endian type (i.e. Intel vs. Sparc, etc) 15 | * 16 | */ 17 | static char* testEndian(void) 18 | { 19 | /* this test that "1" is "!!!!#" */ 20 | char buf[100]; 21 | char result[10]; 22 | char endian[] = { (char)0, (char)0, (char)0, (char)1 }; 23 | size_t d = modp_b85_encode(buf, endian, (size_t)4); 24 | mu_assert_int_equals(5, d); 25 | mu_assert_int_equals('!', buf[0]); 26 | mu_assert_int_equals('!', buf[1]); 27 | mu_assert_int_equals('!', buf[2]); 28 | mu_assert_int_equals('!', buf[3]); 29 | mu_assert_int_equals('#', buf[4]); 30 | 31 | memset(result, 255, sizeof(result)); 32 | d = modp_b85_decode(result, "!!!!#", (size_t)5); 33 | mu_assert_int_equals(4, d); 34 | mu_assert_int_equals(0, result[0]); 35 | mu_assert_int_equals(0, result[1]); 36 | mu_assert_int_equals(0, result[2]); 37 | mu_assert_int_equals(1, result[3]); 38 | mu_assert_int_equals(-1, result[4]); 39 | 40 | return 0; 41 | } 42 | 43 | static char* testLength(void) 44 | { 45 | /** 46 | * Decode Len 47 | * 5 bytes -> 4 in, no null 48 | */ 49 | mu_assert_int_equals(0, modp_b85_decode_len(0)); 50 | mu_assert_int_equals(4, modp_b85_decode_len(5)); 51 | mu_assert_int_equals(8, modp_b85_decode_len(10)); 52 | 53 | /* Encode Len 54 | * 4 byte -> 5 output + 1 null byte 55 | */ 56 | mu_assert_int_equals(1, modp_b85_encode_len(0)); 57 | mu_assert_int_equals(6, modp_b85_encode_len(4)); 58 | mu_assert_int_equals(11, modp_b85_encode_len(8)); 59 | return 0; 60 | } 61 | 62 | /** \brief test bad input lengths 63 | * The b85 encode only accepts multiples of 4. 64 | * 65 | * The b85 decoder only accepts a multiple of 5. 66 | * 67 | */ 68 | static char* testBadInputLength(void) 69 | { 70 | char buf[100]; 71 | mu_assert_int_equals(-1, modp_b85_encode(buf, buf, (size_t)5)); 72 | mu_assert_int_equals(-1, modp_b85_decode(buf, buf, (size_t)11)); 73 | return 0; 74 | } 75 | 76 | /** \brief test decoding invalid b85 chars 77 | * 78 | */ 79 | static char* testBadCharDecode(void) 80 | { 81 | char buf[] = { 'A', 'B', 'C', 'D', '\n', '\0' }; 82 | mu_assert_int_equals(-1, modp_b85_decode(buf, buf, (size_t)5)); 83 | return 0; 84 | } 85 | 86 | static char* testEncodeDecode(void) 87 | { 88 | char ibuf[10]; /* input */ 89 | char obuf[10]; /* output */ 90 | char rbuf[10]; /* final result */ 91 | size_t d; 92 | int i, j, k, l; 93 | for (i = 0; i < 256; ++i) { 94 | for (j = 0; j < 256; j += 16) { /* save some time +=16 */ 95 | for (k = 0; k < 256; k += 8) { /* save some time += 8 */ 96 | for (l = 0; l < 256; ++l) { 97 | ibuf[0] = (char)i; 98 | ibuf[1] = (char)j; 99 | ibuf[2] = (char)k; 100 | ibuf[3] = (char)l; 101 | memset(obuf, 255, sizeof(obuf)); 102 | d = modp_b85_encode(obuf, ibuf, (size_t)4); 103 | mu_assert_int_equals(5, d); 104 | mu_assert_int_equals(0, obuf[5]); 105 | memset(rbuf, 255, sizeof(rbuf)); 106 | d = modp_b85_decode(rbuf, obuf, (size_t)5); 107 | mu_assert_int_equals(4, d); 108 | mu_assert_int_equals(ibuf[0], rbuf[0]); 109 | mu_assert_int_equals(ibuf[1], rbuf[1]); 110 | mu_assert_int_equals(ibuf[2], rbuf[2]); 111 | mu_assert_int_equals(ibuf[3], rbuf[3]); 112 | mu_assert_int_equals(-1, rbuf[4]); 113 | } 114 | } 115 | } 116 | } 117 | return 0; 118 | } 119 | 120 | static char* all_tests(void) 121 | { 122 | mu_run_test(testEndian); 123 | mu_run_test(testLength); 124 | mu_run_test(testBadInputLength); 125 | mu_run_test(testBadCharDecode); 126 | mu_run_test(testEncodeDecode); 127 | return 0; 128 | } 129 | 130 | UNITTESTS 131 | -------------------------------------------------------------------------------- /test/modp_bjavascript_test.c: -------------------------------------------------------------------------------- 1 | /* we compile as C90 but use snprintf */ 2 | #define _ISOC99_SOURCE 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "minunit.h" 9 | 10 | #include "modp_bjavascript.h" 11 | 12 | /** 13 | * Tests input where no escaping happens 14 | */ 15 | static char* testNoEscape(void) 16 | { 17 | char buf[100]; 18 | const char* s1 = "this is a string"; 19 | const size_t len1 = strlen(s1); 20 | size_t d = modp_bjavascript_encode(buf, s1, len1); 21 | 22 | mu_assert_int_equals(len1, d); 23 | mu_assert_str_equals(buf, s1); 24 | 25 | size_t sz = modp_bjavascript_encode_strlen(s1, len1); 26 | mu_assert_int_equals(sz, len1); 27 | 28 | return 0; 29 | } 30 | 31 | static char* testSimpleEscape(void) 32 | { 33 | char buf[100]; 34 | const char* s1 = "\\this\nis a string\n"; 35 | const char* s2 = "\\\\this\\nis a string\\n"; 36 | const size_t len1 = strlen(s1); 37 | const size_t len2 = strlen(s2); 38 | size_t d = modp_bjavascript_encode(buf, s1, len1); 39 | 40 | mu_assert_int_equals(len2, d); 41 | mu_assert_str_equals(buf, s2); 42 | 43 | size_t sz = modp_bjavascript_encode_strlen(s1, len1); 44 | mu_assert_int_equals(sz, len2); 45 | 46 | /* 47 | * Test the Raw escape '\' --> '\\' 48 | */ 49 | char ibuf[] = { '\\', '\0' }; 50 | memset(buf, 0, sizeof(buf)); 51 | d = modp_bjavascript_encode(buf, ibuf, (size_t)1); 52 | mu_assert_int_equals(d, 2); 53 | mu_assert_int_equals(buf[0], '\\'); 54 | mu_assert_int_equals(buf[1], '\\'); 55 | mu_assert_int_equals(buf[2], 0); 56 | 57 | return 0; 58 | } 59 | 60 | static char* testSQuoteEscape(void) 61 | { 62 | char buf[100]; 63 | const char* s1 = "this is a 'string'\n"; 64 | const char* s2 = "this is a \\'string\\'\\n"; 65 | const size_t len1 = strlen(s1); 66 | const size_t len2 = strlen(s2); 67 | size_t d = modp_bjavascript_encode(buf, s1, len1); 68 | 69 | mu_assert_int_equals(len2, d); 70 | mu_assert_str_equals(buf, s2); 71 | 72 | size_t sz = modp_bjavascript_encode_strlen(s1, len1); 73 | mu_assert_int_equals(sz, len2); 74 | 75 | char ibuf[] = { '\'', '\0' }; 76 | memset(buf, 0, sizeof(buf)); 77 | d = modp_bjavascript_encode(buf, ibuf, (size_t)1); 78 | mu_assert_int_equals(d, 2); 79 | mu_assert_int_equals(buf[0], '\\'); 80 | mu_assert_int_equals(buf[1], '\''); 81 | mu_assert_int_equals(buf[2], '\0'); 82 | 83 | return 0; 84 | } 85 | 86 | static char* testDQuoteEscape(void) 87 | { 88 | char buf[100]; 89 | const char* s1 = "this is a \"string\"\n"; 90 | const char* s2 = "this is a \\\"string\\\"\\n"; 91 | const size_t len1 = strlen(s1); 92 | const size_t len2 = strlen(s2); 93 | size_t d = modp_bjavascript_encode(buf, s1, len1); 94 | 95 | mu_assert_int_equals(len2, d); 96 | mu_assert_str_equals(buf, s2); 97 | 98 | size_t sz = modp_bjavascript_encode_strlen(s1, len1); 99 | mu_assert_int_equals(sz, len2); 100 | char ibuf[] = { '\"', '\0' }; 101 | memset(buf, 0, sizeof(buf)); 102 | d = modp_bjavascript_encode(buf, ibuf, (size_t)1); 103 | mu_assert_int_equals(d, 2); 104 | mu_assert_int_equals(buf[0], '\\'); 105 | mu_assert_int_equals(buf[1], '\"'); 106 | mu_assert_int_equals(buf[2], '\0'); 107 | return 0; 108 | } 109 | 110 | static char* testBinaryEscape(void) 111 | { 112 | char buf[100]; 113 | const char s1[] = { 1, 2, 3, 4, 0 }; 114 | const char* s2 = "\\x01\\x02\\x03\\x04"; 115 | const size_t len1 = strlen(s1); 116 | const size_t len2 = strlen(s2); 117 | size_t d = modp_bjavascript_encode(buf, s1, len1); 118 | 119 | mu_assert_int_equals(len2, d); 120 | mu_assert_str_equals(buf, s2); 121 | 122 | size_t sz = modp_bjavascript_encode_strlen(s1, len1); 123 | mu_assert_int_equals(sz, len2); 124 | return 0; 125 | } 126 | 127 | static char* all_tests(void) 128 | { 129 | mu_run_test(testNoEscape); 130 | mu_run_test(testSimpleEscape); 131 | mu_run_test(testBinaryEscape); 132 | mu_run_test(testSQuoteEscape); 133 | mu_run_test(testDQuoteEscape); 134 | return 0; 135 | } 136 | 137 | UNITTESTS 138 | -------------------------------------------------------------------------------- /test/modp_utf8_test.c: -------------------------------------------------------------------------------- 1 | /* we compile as C90 but use snprintf */ 2 | #define _ISOC99_SOURCE 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "minunit.h" 9 | 10 | #include "modp_utf8.h" 11 | /** 12 | * Test empty input to decode 13 | */ 14 | static char* testUtf8ValidateEmpty(void) 15 | { 16 | int d = modp_utf8_validate("", (size_t)0); 17 | mu_assert_int_equals(d, 0); 18 | return 0; 19 | } 20 | 21 | static char* testUtf8ValidateAscii(void) 22 | { 23 | int d = modp_utf8_validate("abc", (size_t)3); 24 | mu_assert_int_equals(d, 0); 25 | 26 | /* with null and highest ASCII character 127 */ 27 | d = modp_utf8_validate("a\x00\x7Fz", (size_t)4); 28 | mu_assert_int_equals(d, 0); 29 | return 0; 30 | } 31 | 32 | static char* testUtf8Validate2(void) 33 | { 34 | /* 35 | * examples taken from Wikipedia 36 | * http://en.wikipedia.org/wiki/UTF-8 37 | */ 38 | int d; 39 | const char* s2 = "\xC2\xA2"; 40 | mu_assert_int_equals(strlen(s2), 2); 41 | d = modp_utf8_validate(s2, strlen(s2)); 42 | mu_assert_int_equals(d, 0); 43 | 44 | d = modp_utf8_validate(s2, strlen(s2) - 1); 45 | mu_assert_int_equals(d, MODP_UTF8_SHORT); 46 | 47 | /* overlong, decodes to 0 */ 48 | s2 = "\xC0\x80"; 49 | d = modp_utf8_validate(s2, strlen(s2)); 50 | mu_assert_int_equals(d, MODP_UTF8_OVERLONG); 51 | 52 | /* overlong, decodes to 127 */ 53 | s2 = "\xC1\xBF"; 54 | d = modp_utf8_validate(s2, strlen(s2)); 55 | mu_assert_int_equals(d, MODP_UTF8_OVERLONG); 56 | 57 | s2 = "\xC2\xC0"; 58 | d = modp_utf8_validate(s2, strlen(s2)); 59 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 60 | 61 | s2 = "\xC2\xFF"; 62 | d = modp_utf8_validate(s2, strlen(s2)); 63 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 64 | 65 | s2 = "\xC2\x01"; 66 | d = modp_utf8_validate(s2, strlen(s2)); 67 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 68 | 69 | return 0; 70 | } 71 | 72 | static char* testUtf8Validate3(void) 73 | { 74 | int d; 75 | const char* s3 = "\xE2\x82\xAC"; 76 | mu_assert_int_equals(strlen(s3), 3); 77 | d = modp_utf8_validate(s3, strlen(s3)); 78 | mu_assert_int_equals(d, 0); 79 | 80 | d = modp_utf8_validate(s3, strlen(s3) - 1); 81 | mu_assert_int_equals(d, MODP_UTF8_SHORT); 82 | 83 | s3 = "\xEF\xBF\xBF"; 84 | d = modp_utf8_validate(s3, strlen(s3)); 85 | mu_assert_int_equals(d, MODP_UTF8_OK); 86 | 87 | s3 = "\xE0\x80\x80"; 88 | d = modp_utf8_validate(s3, strlen(s3)); 89 | mu_assert_int_equals(d, MODP_UTF8_OVERLONG); 90 | 91 | s3 = "\xE2\x01\xAC"; 92 | d = modp_utf8_validate(s3, strlen(s3)); 93 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 94 | 95 | s3 = "\xE2\x82\x01"; 96 | d = modp_utf8_validate(s3, strlen(s3)); 97 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 98 | return 0; 99 | } 100 | 101 | static char* testUtf8Validate4(void) 102 | { 103 | int d; 104 | const char* s4 = "\xF0\xA4\xAD\xA2"; 105 | mu_assert_int_equals(strlen(s4), 4); 106 | d = modp_utf8_validate(s4, strlen(s4)); 107 | mu_assert_int_equals(d, 0); 108 | 109 | d = modp_utf8_validate(s4, strlen(s4) - 1); 110 | mu_assert_int_equals(d, MODP_UTF8_SHORT); 111 | 112 | /* maximum value */ 113 | s4 = "\xF7\xBF\xBF\xBF"; 114 | d = modp_utf8_validate(s4, strlen(s4)); 115 | mu_assert_int_equals(d, MODP_UTF8_OK); 116 | 117 | s4 = "\xF0\x01\xAD\xA2"; 118 | d = modp_utf8_validate(s4, strlen(s4)); 119 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 120 | 121 | s4 = "\xF0\xA4\x01\xA2"; 122 | d = modp_utf8_validate(s4, strlen(s4)); 123 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 124 | 125 | s4 = "\xF0\xA4\xAD\x01"; 126 | d = modp_utf8_validate(s4, strlen(s4)); 127 | mu_assert_int_equals(d, MODP_UTF8_INVALID); 128 | 129 | return 0; 130 | } 131 | static char* testUtf8Validate5(void) 132 | { 133 | int d; 134 | const char* s = "\xF8"; 135 | mu_assert_int_equals(strlen(s), 1); 136 | d = modp_utf8_validate(s, strlen(s)); 137 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 138 | 139 | s = "\xF9"; 140 | mu_assert_int_equals(strlen(s), 1); 141 | d = modp_utf8_validate(s, strlen(s)); 142 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 143 | 144 | s = "\xFA"; 145 | mu_assert_int_equals(strlen(s), 1); 146 | d = modp_utf8_validate(s, strlen(s)); 147 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 148 | 149 | s = "\xFB"; 150 | mu_assert_int_equals(strlen(s), 1); 151 | d = modp_utf8_validate(s, strlen(s)); 152 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 153 | 154 | s = "\xFC"; 155 | mu_assert_int_equals(strlen(s), 1); 156 | d = modp_utf8_validate(s, strlen(s)); 157 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 158 | 159 | s = "\xFD"; 160 | mu_assert_int_equals(strlen(s), 1); 161 | d = modp_utf8_validate(s, strlen(s)); 162 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 163 | 164 | s = "\xFE"; 165 | mu_assert_int_equals(strlen(s), 1); 166 | d = modp_utf8_validate(s, strlen(s)); 167 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 168 | 169 | s = "\xFF"; 170 | mu_assert_int_equals(strlen(s), 1); 171 | d = modp_utf8_validate(s, strlen(s)); 172 | mu_assert_int_equals(d, MODP_UTF8_CODEPOINT); 173 | 174 | return 0; 175 | } 176 | 177 | static char* all_tests(void) 178 | { 179 | mu_run_test(testUtf8ValidateEmpty); 180 | mu_run_test(testUtf8ValidateAscii); 181 | mu_run_test(testUtf8Validate2); 182 | mu_run_test(testUtf8Validate3); 183 | mu_run_test(testUtf8Validate4); 184 | mu_run_test(testUtf8Validate5); 185 | return 0; 186 | } 187 | 188 | UNITTESTS 189 | -------------------------------------------------------------------------------- /test/speedtest.c: -------------------------------------------------------------------------------- 1 | /** \file speedtest.c 2 | * 3 | * Copyright 2005-2016 Nick Galbreath -- nickg [at] client9 [dot] com 4 | * All rights reserved. 5 | * 6 | * https://github.com/client9/stringencoders/ 7 | * 8 | * Released under MIT license. See LICENSE for details. 9 | * 10 | * Quickie performance tester. This does NOT test correctness. 11 | * 12 | */ 13 | 14 | #include "apr_base64.h" 15 | #include "modp_b16.h" 16 | #include "modp_b2.h" 17 | #include "modp_b64.h" 18 | #include "modp_b85.h" 19 | #include "modp_bjavascript.h" 20 | #include "modp_burl.h" 21 | 22 | #include 23 | #ifndef CLOCKS_PER_SEC 24 | #ifdef CLK_TCK 25 | #define CLOCKS_PER_SEC (CLK_TCK) 26 | #endif 27 | #endif 28 | #include 29 | #include 30 | 31 | #define SZ 4096 32 | int main(void) 33 | { 34 | double s1, s2; 35 | int i, j; 36 | clock_t c0, c1; 37 | char teststr1[SZ]; 38 | 39 | /* 40 | this contains the message sizes we'll test on 41 | add, subtract, change as desired. 42 | */ 43 | size_t sizes[] = { 20, 200, 2000 }; 44 | 45 | for (i = 0; i < (int)sizeof(teststr1); ++i) { 46 | teststr1[i] = (char)('A' + i % 26); 47 | } 48 | 49 | /* over allocate result buffers */ 50 | char result[SZ * 8]; 51 | char result2[SZ * 8]; 52 | 53 | const int MAX = 1000000; 54 | 55 | for (j = 0; j < (int)(sizeof(sizes) / sizeof(size_t)); ++j) { 56 | printf("\nMessage size = %d\n", (int)sizes[j]); 57 | 58 | printf("\tmodpb64\tapache\timprovement\tmodpb85\tmodpurl\tmodpb16\tmodpb2\tmodpjs\n"); 59 | printf("Encode\t"); 60 | fflush(stdout); 61 | 62 | /* MODP_B64 ENCODE */ 63 | c0 = clock(); 64 | for (i = 0; i < MAX; ++i) { 65 | modp_b64_encode(result, teststr1, sizes[j]); 66 | } 67 | c1 = clock(); 68 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 69 | printf("%6.2f\t", s1); 70 | fflush(stdout); 71 | 72 | /* APACHE ENCODE */ 73 | c0 = clock(); 74 | for (i = 0; i < MAX; ++i) { 75 | apr_base64_encode_binary(result, 76 | (const unsigned char*)teststr1, 77 | (int)sizes[j]); 78 | } 79 | c1 = clock(); 80 | s2 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 81 | printf("%6.2f\t", s2); 82 | printf("%6.2fx\t\t", s2 / s1); 83 | fflush(stdout); 84 | 85 | /* 86 | * base85 encode, let's see what is faster 87 | */ 88 | c0 = clock(); 89 | for (i = 0; i < MAX; ++i) { 90 | modp_b85_encode(result, teststr1, sizes[j]); 91 | } 92 | c1 = clock(); 93 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 94 | printf("%6.2f\t", s1); 95 | fflush(stdout); 96 | 97 | /* 98 | * url encode 99 | */ 100 | c0 = clock(); 101 | for (i = 0; i < MAX; ++i) { 102 | modp_burl_encode(result, teststr1, sizes[j]); 103 | } 104 | c1 = clock(); 105 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 106 | printf("%6.2f\t", s1); 107 | fflush(stdout); 108 | 109 | /** 110 | * B16 111 | */ 112 | c0 = clock(); 113 | for (i = 0; i < MAX; ++i) { 114 | modp_b16_encode(result, teststr1, sizes[j]); 115 | } 116 | c1 = clock(); 117 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 118 | printf("%6.2f\t", s1); 119 | fflush(stdout); 120 | 121 | /** 122 | * B2 BINARY 123 | */ 124 | c0 = clock(); 125 | for (i = 0; i < MAX; ++i) { 126 | modp_b2_encode(result, teststr1, sizes[j]); 127 | } 128 | c1 = clock(); 129 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 130 | printf("%6.2f\t", s1); 131 | fflush(stdout); 132 | 133 | /** 134 | * javascript 135 | */ 136 | c0 = clock(); 137 | for (i = 0; i < MAX; ++i) { 138 | modp_bjavascript_encode(result, teststr1, sizes[j]); 139 | } 140 | c1 = clock(); 141 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 142 | printf("%6.2f\t", s1); 143 | fflush(stdout); 144 | 145 | printf("\n"); 146 | fflush(stdout); 147 | 148 | /*** 149 | * DECODE 150 | */ 151 | /* reset result to have b64 chars */ 152 | modp_b64_encode(result, teststr1, sizes[j]); 153 | size_t len = strlen(result); 154 | 155 | printf("Decode\t"); 156 | fflush(stdout); 157 | 158 | /* MODP_B64 */ 159 | c0 = clock(); 160 | for (i = 0; i < MAX; ++i) { 161 | modp_b64_decode(result2, result, len); 162 | } 163 | c1 = clock(); 164 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 165 | printf("%6.2f\t", s1); 166 | fflush(stdout); 167 | 168 | /* APACHE */ 169 | c0 = clock(); 170 | for (i = 0; i < MAX; ++i) { 171 | apr_base64_decode_binary((unsigned char*)result2, result); 172 | } 173 | c1 = clock(); 174 | s2 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 175 | printf("%6.2f\t", s2); 176 | printf("%6.2fx\t\t", s2 / s1); 177 | fflush(stdout); 178 | 179 | /* 180 | * modp_b85 decode 181 | */ 182 | /* re-encode to get b85 chars, not b64 */ 183 | len = modp_b85_encode(result, teststr1, sizes[j]); 184 | 185 | c0 = clock(); 186 | for (i = 0; i < MAX; ++i) { 187 | modp_b85_decode(result2, result, len); 188 | } 189 | c1 = clock(); 190 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 191 | printf("%6.2f\t", s1); 192 | fflush(stdout); 193 | 194 | /* re-encode to get urlencoded chars, not b64 */ 195 | len = modp_burl_encode(result, teststr1, sizes[j]); 196 | 197 | c0 = clock(); 198 | for (i = 0; i < MAX; ++i) { 199 | modp_burl_decode(result2, result, len); 200 | } 201 | c1 = clock(); 202 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 203 | printf("%6.2f\t", s1); 204 | fflush(stdout); 205 | 206 | /** 207 | ** B16 DECODE 208 | **/ 209 | /* re-encode to get urlencoded chars, not b64 */ 210 | len = modp_b16_encode(result, teststr1, sizes[j]); 211 | 212 | c0 = clock(); 213 | for (i = 0; i < MAX; ++i) { 214 | modp_b16_decode(result2, result, len); 215 | } 216 | c1 = clock(); 217 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 218 | printf("%6.2f\t", s1); 219 | fflush(stdout); 220 | 221 | /** 222 | ** B16 DECODE 223 | **/ 224 | /* re-encode to get urlencoded chars, not b64 */ 225 | len = modp_b2_encode(result, teststr1, sizes[j]); 226 | 227 | c0 = clock(); 228 | for (i = 0; i < MAX; ++i) { 229 | modp_b2_decode(result2, result, len); 230 | } 231 | c1 = clock(); 232 | s1 = (double)(c1 - c0) * (1.0 / (double)CLOCKS_PER_SEC); 233 | printf("%6.2f\t", s1); 234 | fflush(stdout); 235 | 236 | printf("\n"); 237 | fflush(stdout); 238 | } 239 | 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /test/speedtest_msg.c: -------------------------------------------------------------------------------- 1 | #include "modp_json.h" 2 | 3 | #include 4 | #ifndef CLOCKS_PER_SEC 5 | #ifdef CLK_TCK 6 | #define CLOCKS_PER_SEC (CLK_TCK) 7 | #endif 8 | #endif 9 | #include 10 | #include 11 | #include 12 | 13 | size_t test_json_encode(char* dest) 14 | { 15 | modp_json_ctx ctx; 16 | modp_json_init(&ctx, dest); 17 | modp_json_map_open(&ctx); 18 | 19 | modp_json_add_cstring(&ctx, "start_ms"); 20 | modp_json_add_uint32(&ctx, 123456789); 21 | 22 | modp_json_add_cstring(&ctx, "remote_ip"); 23 | modp_json_add_cstring(&ctx, "123.123.123.13"); 24 | 25 | modp_json_add_cstring(&ctx, "request"); 26 | modp_json_add_cstring(&ctx, "GET /foobar HTTP/1.1"); 27 | 28 | modp_json_add_cstring(&ctx, "headers_in"); 29 | modp_json_ary_open(&ctx); 30 | 31 | modp_json_ary_open(&ctx); 32 | modp_json_add_cstring(&ctx, "Accept"); 33 | modp_json_add_cstring(&ctx, "*/*"); 34 | modp_json_ary_close(&ctx); 35 | 36 | modp_json_ary_open(&ctx); 37 | modp_json_add_cstring(&ctx, "Content-type"); 38 | modp_json_add_cstring(&ctx, "text/plain"); 39 | modp_json_ary_close(&ctx); 40 | 41 | modp_json_ary_open(&ctx); 42 | modp_json_add_cstring(&ctx, "Connection"); 43 | modp_json_add_cstring(&ctx, "close"); 44 | modp_json_ary_close(&ctx); 45 | 46 | modp_json_ary_open(&ctx); 47 | modp_json_add_cstring(&ctx, "User-agent"); 48 | modp_json_add_cstring(&ctx, "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405"); 49 | modp_json_ary_close(&ctx); 50 | 51 | modp_json_ary_close(&ctx); 52 | modp_json_map_close(&ctx); 53 | return modp_json_end(&ctx); 54 | } 55 | 56 | int main(void) 57 | { 58 | 59 | const int imax = 1000000; 60 | clock_t t0, t1; 61 | int i; 62 | double s1; 63 | size_t len; 64 | char buf2[512]; 65 | 66 | printf("ALG\tEncodes/Sec\tBYTES\n"); 67 | fflush(stdout); 68 | t0 = clock(); 69 | for (i = 0; i < imax; ++i) { 70 | len = test_json_encode(NULL); 71 | len = test_json_encode(buf2); 72 | } 73 | t1 = clock(); 74 | s1 = (double)(t1 - t0) * (1.0 / (double)CLOCKS_PER_SEC); 75 | printf("%s\t%8.0f\t%u\n", "JSON", imax / s1, (unsigned)len); 76 | fflush(stdout); 77 | return 0; 78 | } 79 | --------------------------------------------------------------------------------