diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ext-key-format.cpp | 308 | ||||
-rw-r--r-- | src/sexp-char-defs.cpp | 345 | ||||
-rw-r--r-- | src/sexp-depth-manager.cpp | 50 | ||||
-rw-r--r-- | src/sexp-error.cpp | 56 | ||||
-rw-r--r-- | src/sexp-input.cpp | 514 | ||||
-rw-r--r-- | src/sexp-main.cpp | 231 | ||||
-rw-r--r-- | src/sexp-object.cpp | 188 | ||||
-rw-r--r-- | src/sexp-output.cpp | 197 | ||||
-rw-r--r-- | src/sexp-simple-string.cpp | 191 |
9 files changed, 2080 insertions, 0 deletions
diff --git a/src/ext-key-format.cpp b/src/ext-key-format.cpp new file mode 100644 index 0000000..7a402cb --- /dev/null +++ b/src/ext-key-format.cpp @@ -0,0 +1,308 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "sexpp/ext-key-format.h" + +using namespace sexp; + +namespace ext_key_format { + +void ext_key_error( + sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos) +{ + char tmp[256]; + sexp_exception_t::severity l = (sexp_exception_t::severity) level; + snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]), msg, c1, c2); + if (sexp_exception_t::shall_throw(l)) + throw sexp_exception_t(tmp, l, pos, "EXTENDED KEY FORMAT"); + if (sexp_exception_t::is_interactive()) { + std::cout.flush() << std::endl + << "*** " + << sexp_exception_t::format("EXTENDED KEY FORMAT", tmp, l, pos) + << " ***" << std::endl; + } +} + +// Valid characters are all ASCII letters, numbers and the hyphen. +// true if allowed in the name field +const bool ext_key_input_stream_t::namechar[256] = { + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ false, /* 0x2b + */ false, /* 0x2c , */ false, + /* 0x2d - */ true, /* 0x2e . */ false, /* 0x2f / */ false, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ false, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ false, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +/* + * ext_key_input_stream_t::skip_line + */ +int ext_key_input_stream_t::skip_line(void) +{ + int c; + do { + c = input_file->get(); + } while (!is_newline_char(c) && c != EOF); + return c; +} + +/* + * ext_key_input_stream_t::read_char + */ +int ext_key_input_stream_t::read_char(void) +{ + int lookahead_1 = input_file->get(); + count++; + if (is_scanning_value && is_newline_char(lookahead_1)) { + while (true) { + int lookahead_2 = input_file->peek(); + if (lookahead_1 == '\r' && lookahead_2 == '\n') { + lookahead_1 = input_file->get(); + count++; + lookahead_2 = input_file->peek(); + } + if (lookahead_2 == ' ') { + input_file->get(); + count++; + lookahead_2 = input_file->peek(); + if (lookahead_2 == '#') { + lookahead_1 = skip_line(); + continue; + } + if (is_newline_char(lookahead_2)) { + lookahead_1 = lookahead_2; + continue; + } + lookahead_1 = input_file->get(); + count++; + } + return lookahead_1; + } + } + return lookahead_1; +} + +/* + * ext_key_input_stream_t::scan_name + * A name must start with a letter and end with a colon. Valid characters are all ASCII + * letters, numbers and the hyphen. Comparison of names is done case insensitively. Names may + * be used several times to represent an array of values. Note that the name “Key” is special + * in that it is madandory must occur only once. + */ + +std::string ext_key_input_stream_t::scan_name(int c) +{ + std::string name; + if (!is_alpha(c)) { + ext_key_error(sexp_exception_t::error, + isprint(next_char) ? + "unexpected character '%c' (0x%x) found starting a name field" : + "unexpected character '0x%x' found starting a name field", + c, + c, + count); + } else { + name += (char) c; + c = read_char(); + while (c != ':') { + if (c == EOF) { + ext_key_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); + } + if (is_newline_char(c)) { + ext_key_error(sexp_exception_t::error, "unexpected end of line", 0, 0, count); + } + if (!is_namechar(c)) { + ext_key_error(sexp_exception_t::error, + isprint(next_char) ? + "unexpected character '%c' (0x%x) found in a name field" : + "unexpected character '0x%x' found in a name field", + c, + c, + count); + } + name += (int) c; + c = read_char(); + } + } + return name; +} + +/* + * ext_key_input_stream_t::scan_value + * Values are UTF-8 encoded strings. Values can be wrapped at any point, and continued in + * the next line indicated by leading whitespace. A continuation line with one leading space + * does not introduce a blank so that the lines can be effectively concatenated. A blank + * line as part of a continuation line encodes a newline. + */ +std::string ext_key_input_stream_t::scan_value(void) +{ + std::string value; + int c; + do { + c = read_char(); + } while (is_white_space(c)); + while (c != EOF && !is_newline_char(c)) { + value += c; + c = read_char(); + } + return value; +} + +/* + * ext_key_input_stream_t::scan + * GnuPG 2.3+ uses a new format to store private keys that is both more flexible and easier to + * read and edit by human beings. The new format stores name, value-pairs using the common mail + * and http header convention. + */ +void ext_key_input_stream_t::scan(extended_private_key_t &res) +{ + set_byte_size(8); + int c = read_char(); + if (c == '(') { + set_next_char(c); + res.key.parse(this); + has_key = true; + } else { + while (c != EOF) { + // Comparison of names is done case insensitively + std::string name = scan_name(c); + // The name “Key” is special in that it is mandatory and must occur only once. + // The associated value holds the actual S-expression with the cryptographic key. + // The S-expression is formatted using the ‘Advanced Format’ + // (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that the file + // can be easily inspected and edited. + is_scanning_value = true; + if (extended_private_key_t::iequals(name, "key")) { + if (has_key) { + ext_key_error(sexp_exception_t::error, + "'key' field must occur only once", + 0, + 0, + count); + } + do { + c = read_char(); + } while (is_white_space(c)); + set_next_char(c); + res.key.parse(this); + has_key = true; + } else { + std::string value = scan_value(); + res.fields.insert(std::pair<std::string, std::string>{name, value}); + } + c = read_char(); + is_scanning_value = false; + } + } + if (!has_key) { + ext_key_error(sexp_exception_t::error, "missing mandatory 'key' field", 0, 0, count); + } +} + +/* + * extended_private_key_t::parse + */ +void extended_private_key_t::parse(ext_key_input_stream_t &is) +{ + is.scan(*this); +} + +} // namespace ext_key_format
\ No newline at end of file diff --git a/src/sexp-char-defs.cpp b/src/sexp-char-defs.cpp new file mode 100644 index 0000000..f31b62d --- /dev/null +++ b/src/sexp-char-defs.cpp @@ -0,0 +1,345 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Original copyright + * + * SEXP implementation code sexp-input.c + * Ron Rivest + * 7/21/1997 + */ + +#include "sexpp/sexp.h" + +namespace sexp { + +/**************************************/ +/* CHARACTER ROUTINES AND DEFINITIONS */ +/**************************************/ +std::locale sexp_char_defs_t::c_locale{"C"}; + +const unsigned char sexp_char_defs_t::values[256][3] = + {/* values of c as { dec. hex, base64 } digit */ + {/* 0x00 */ 0x00, 0x00, 0x00}, {/* 0x01 */ 0x00, 0x00, 0x00}, + {/* 0x02 */ 0x00, 0x00, 0x00}, {/* 0x03 */ 0x00, 0x00, 0x00}, + {/* 0x04 */ 0x00, 0x00, 0x00}, {/* 0x05 */ 0x00, 0x00, 0x00}, + {/* 0x06 */ 0x00, 0x00, 0x00}, {/* 0x07 */ 0x00, 0x00, 0x00}, + {/* 0x08 */ 0x00, 0x00, 0x00}, {/* 0x09 */ 0x00, 0x00, 0x00}, + {/* 0x0a */ 0x00, 0x00, 0x00}, {/* 0x0b */ 0x00, 0x00, 0x00}, + {/* 0x0c */ 0x00, 0x00, 0x00}, {/* 0x0d */ 0x00, 0x00, 0x00}, + {/* 0x0e */ 0x00, 0x00, 0x00}, {/* 0x0f */ 0x00, 0x00, 0x00}, + {/* 0x10 */ 0x00, 0x00, 0x00}, {/* 0x11 */ 0x00, 0x00, 0x00}, + {/* 0x12 */ 0x00, 0x00, 0x00}, {/* 0x13 */ 0x00, 0x00, 0x00}, + {/* 0x14 */ 0x00, 0x00, 0x00}, {/* 0x15 */ 0x00, 0x00, 0x00}, + {/* 0x16 */ 0x00, 0x00, 0x00}, {/* 0x17 */ 0x00, 0x00, 0x00}, + {/* 0x18 */ 0x00, 0x00, 0x00}, {/* 0x19 */ 0x00, 0x00, 0x00}, + {/* 0x1a */ 0x00, 0x00, 0x00}, {/* 0x1b */ 0x00, 0x00, 0x00}, + {/* 0x1c */ 0x00, 0x00, 0x00}, {/* 0x1d */ 0x00, 0x00, 0x00}, + {/* 0x1e */ 0x00, 0x00, 0x00}, {/* 0x1f */ 0x00, 0x00, 0x00}, + {/* 0x20 */ 0x00, 0x00, 0x00}, {/* 0x21 ! */ 0x00, 0x00, 0x00}, + {/* 0x22 " */ 0x00, 0x00, 0x00}, {/* 0x23 # */ 0x00, 0x00, 0x00}, + {/* 0x24 $ */ 0x00, 0x00, 0x00}, {/* 0x25 % */ 0x00, 0x00, 0x00}, + {/* 0x26 & */ 0x00, 0x00, 0x00}, {/* 0x27 ' */ 0x00, 0x00, 0x00}, + {/* 0x28 ( */ 0x00, 0x00, 0x00}, {/* 0x29 ) */ 0x00, 0x00, 0x00}, + {/* 0x2a * */ 0x00, 0x00, 0x00}, {/* 0x2b + */ 0x00, 0x00, 0x3e}, + {/* 0x2c , */ 0x00, 0x00, 0x00}, {/* 0x2d - */ 0x00, 0x00, 0x00}, + {/* 0x2e . */ 0x00, 0x00, 0x00}, {/* 0x2f / */ 0x00, 0x00, 0x3f}, + {/* 0x30 0 */ 0x00, 0x00, 0x34}, {/* 0x31 1 */ 0x01, 0x01, 0x35}, + {/* 0x32 2 */ 0x02, 0x02, 0x36}, {/* 0x33 3 */ 0x03, 0x03, 0x37}, + {/* 0x34 4 */ 0x04, 0x04, 0x38}, {/* 0x35 5 */ 0x05, 0x05, 0x39}, + {/* 0x36 6 */ 0x06, 0x06, 0x3a}, {/* 0x37 7 */ 0x07, 0x07, 0x3b}, + {/* 0x38 8 */ 0x08, 0x08, 0x3c}, {/* 0x39 9 */ 0x09, 0x09, 0x3d}, + {/* 0x3a : */ 0x00, 0x00, 0x00}, {/* 0x3b ; */ 0x00, 0x00, 0x00}, + {/* 0x3c < */ 0x00, 0x00, 0x00}, {/* 0x3d = */ 0x00, 0x00, 0x00}, + {/* 0x3e > */ 0x00, 0x00, 0x00}, {/* 0x3f ? */ 0x00, 0x00, 0x00}, + {/* 0x40 @ */ 0x00, 0x00, 0x00}, {/* 0x41 A */ 0x00, 0x0a, 0x00}, + {/* 0x42 B */ 0x00, 0x0b, 0x01}, {/* 0x43 C */ 0x00, 0x0c, 0x02}, + {/* 0x44 D */ 0x00, 0x0d, 0x03}, {/* 0x45 E */ 0x00, 0x0e, 0x04}, + {/* 0x46 F */ 0x00, 0x0f, 0x05}, {/* 0x47 G */ 0x00, 0x00, 0x06}, + {/* 0x48 H */ 0x00, 0x00, 0x07}, {/* 0x49 I */ 0x00, 0x00, 0x08}, + {/* 0x4a J */ 0x00, 0x00, 0x09}, {/* 0x4b K */ 0x00, 0x00, 0x0a}, + {/* 0x4c L */ 0x00, 0x00, 0x0b}, {/* 0x4d M */ 0x00, 0x00, 0x0c}, + {/* 0x4e N */ 0x00, 0x00, 0x0d}, {/* 0x4f O */ 0x00, 0x00, 0x0e}, + {/* 0x50 P */ 0x00, 0x00, 0x0f}, {/* 0x51 Q */ 0x00, 0x00, 0x10}, + {/* 0x52 R */ 0x00, 0x00, 0x11}, {/* 0x53 S */ 0x00, 0x00, 0x12}, + {/* 0x54 T */ 0x00, 0x00, 0x13}, {/* 0x55 U */ 0x00, 0x00, 0x14}, + {/* 0x56 V */ 0x00, 0x00, 0x15}, {/* 0x57 W */ 0x00, 0x00, 0x16}, + {/* 0x58 X */ 0x00, 0x00, 0x17}, {/* 0x59 Y */ 0x00, 0x00, 0x18}, + {/* 0x5a Z */ 0x00, 0x00, 0x19}, {/* 0x5b [ */ 0x00, 0x00, 0x00}, + {/* 0x5c \ */ 0x00, 0x00, 0x00}, {/* 0x5d ] */ 0x00, 0x00, 0x00}, + {/* 0x5e ^ */ 0x00, 0x00, 0x00}, {/* 0x5f _ */ 0x00, 0x00, 0x00}, + {/* 0x60 ` */ 0x00, 0x00, 0x00}, {/* 0x61 a */ 0x00, 0x0a, 0x1a}, + {/* 0x62 b */ 0x00, 0x0b, 0x1b}, {/* 0x63 c */ 0x00, 0x0c, 0x1c}, + {/* 0x64 d */ 0x00, 0x0d, 0x1d}, {/* 0x65 e */ 0x00, 0x0e, 0x1e}, + {/* 0x66 f */ 0x00, 0x0f, 0x1f}, {/* 0x67 g */ 0x00, 0x00, 0x20}, + {/* 0x68 h */ 0x00, 0x00, 0x21}, {/* 0x69 i */ 0x00, 0x00, 0x22}, + {/* 0x6a j */ 0x00, 0x00, 0x23}, {/* 0x6b k */ 0x00, 0x00, 0x24}, + {/* 0x6c l */ 0x00, 0x00, 0x25}, {/* 0x6d m */ 0x00, 0x00, 0x26}, + {/* 0x6e n */ 0x00, 0x00, 0x27}, {/* 0x6f o */ 0x00, 0x00, 0x28}, + {/* 0x70 p */ 0x00, 0x00, 0x29}, {/* 0x71 q */ 0x00, 0x00, 0x2a}, + {/* 0x72 r */ 0x00, 0x00, 0x2b}, {/* 0x73 s */ 0x00, 0x00, 0x2c}, + {/* 0x74 t */ 0x00, 0x00, 0x2d}, {/* 0x75 u */ 0x00, 0x00, 0x2e}, + {/* 0x76 v */ 0x00, 0x00, 0x2f}, {/* 0x77 w */ 0x00, 0x00, 0x30}, + {/* 0x78 x */ 0x00, 0x00, 0x31}, {/* 0x79 y */ 0x00, 0x00, 0x32}, + {/* 0x7a z */ 0x00, 0x00, 0x33}, {/* 0x7b { */ 0x00, 0x00, 0x00}, + {/* 0x7c | */ 0x00, 0x00, 0x00}, {/* 0x7d } */ 0x00, 0x00, 0x00}, + {/* 0x7e ~ */ 0x00, 0x00, 0x00}, {/* 0x7f */ 0x00, 0x00, 0x00}, + {/* 0x80 */ 0x00, 0x00, 0x00}, {/* 0x81 */ 0x00, 0x00, 0x00}, + {/* 0x82 */ 0x00, 0x00, 0x00}, {/* 0x83 */ 0x00, 0x00, 0x00}, + {/* 0x84 */ 0x00, 0x00, 0x00}, {/* 0x85 */ 0x00, 0x00, 0x00}, + {/* 0x86 */ 0x00, 0x00, 0x00}, {/* 0x87 */ 0x00, 0x00, 0x00}, + {/* 0x88 */ 0x00, 0x00, 0x00}, {/* 0x89 */ 0x00, 0x00, 0x00}, + {/* 0x8a */ 0x00, 0x00, 0x00}, {/* 0x8b */ 0x00, 0x00, 0x00}, + {/* 0x8c */ 0x00, 0x00, 0x00}, {/* 0x8d */ 0x00, 0x00, 0x00}, + {/* 0x8e */ 0x00, 0x00, 0x00}, {/* 0x8f */ 0x00, 0x00, 0x00}, + {/* 0x90 */ 0x00, 0x00, 0x00}, {/* 0x91 */ 0x00, 0x00, 0x00}, + {/* 0x92 */ 0x00, 0x00, 0x00}, {/* 0x93 */ 0x00, 0x00, 0x00}, + {/* 0x94 */ 0x00, 0x00, 0x00}, {/* 0x95 */ 0x00, 0x00, 0x00}, + {/* 0x96 */ 0x00, 0x00, 0x00}, {/* 0x97 */ 0x00, 0x00, 0x00}, + {/* 0x98 */ 0x00, 0x00, 0x00}, {/* 0x99 */ 0x00, 0x00, 0x00}, + {/* 0x9a */ 0x00, 0x00, 0x00}, {/* 0x9b */ 0x00, 0x00, 0x00}, + {/* 0x9c */ 0x00, 0x00, 0x00}, {/* 0x9d */ 0x00, 0x00, 0x00}, + {/* 0x9e */ 0x00, 0x00, 0x00}, {/* 0x9f */ 0x00, 0x00, 0x00}, + {/* 0xa0 */ 0x00, 0x00, 0x00}, {/* 0xa1 */ 0x00, 0x00, 0x00}, + {/* 0xa2 */ 0x00, 0x00, 0x00}, {/* 0xa3 */ 0x00, 0x00, 0x00}, + {/* 0xa4 */ 0x00, 0x00, 0x00}, {/* 0xa5 */ 0x00, 0x00, 0x00}, + {/* 0xa6 */ 0x00, 0x00, 0x00}, {/* 0xa7 */ 0x00, 0x00, 0x00}, + {/* 0xa8 */ 0x00, 0x00, 0x00}, {/* 0xa9 */ 0x00, 0x00, 0x00}, + {/* 0xaa */ 0x00, 0x00, 0x00}, {/* 0xab */ 0x00, 0x00, 0x00}, + {/* 0xac */ 0x00, 0x00, 0x00}, {/* 0xad */ 0x00, 0x00, 0x00}, + {/* 0xae */ 0x00, 0x00, 0x00}, {/* 0xaf */ 0x00, 0x00, 0x00}, + {/* 0xb0 */ 0x00, 0x00, 0x00}, {/* 0xb1 */ 0x00, 0x00, 0x00}, + {/* 0xb2 */ 0x00, 0x00, 0x00}, {/* 0xb3 */ 0x00, 0x00, 0x00}, + {/* 0xb4 */ 0x00, 0x00, 0x00}, {/* 0xb5 */ 0x00, 0x00, 0x00}, + {/* 0xb6 */ 0x00, 0x00, 0x00}, {/* 0xb7 */ 0x00, 0x00, 0x00}, + {/* 0xb8 */ 0x00, 0x00, 0x00}, {/* 0xb9 */ 0x00, 0x00, 0x00}, + {/* 0xba */ 0x00, 0x00, 0x00}, {/* 0xbb */ 0x00, 0x00, 0x00}, + {/* 0xbc */ 0x00, 0x00, 0x00}, {/* 0xbd */ 0x00, 0x00, 0x00}, + {/* 0xbe */ 0x00, 0x00, 0x00}, {/* 0xbf */ 0x00, 0x00, 0x00}, + {/* 0xc0 */ 0x00, 0x00, 0x00}, {/* 0xc1 */ 0x00, 0x00, 0x00}, + {/* 0xc2 */ 0x00, 0x00, 0x00}, {/* 0xc3 */ 0x00, 0x00, 0x00}, + {/* 0xc4 */ 0x00, 0x00, 0x00}, {/* 0xc5 */ 0x00, 0x00, 0x00}, + {/* 0xc6 */ 0x00, 0x00, 0x00}, {/* 0xc7 */ 0x00, 0x00, 0x00}, + {/* 0xc8 */ 0x00, 0x00, 0x00}, {/* 0xc9 */ 0x00, 0x00, 0x00}, + {/* 0xca */ 0x00, 0x00, 0x00}, {/* 0xcb */ 0x00, 0x00, 0x00}, + {/* 0xcc */ 0x00, 0x00, 0x00}, {/* 0xcd */ 0x00, 0x00, 0x00}, + {/* 0xce */ 0x00, 0x00, 0x00}, {/* 0xcf */ 0x00, 0x00, 0x00}, + {/* 0xd0 */ 0x00, 0x00, 0x00}, {/* 0xd1 */ 0x00, 0x00, 0x00}, + {/* 0xd2 */ 0x00, 0x00, 0x00}, {/* 0xd3 */ 0x00, 0x00, 0x00}, + {/* 0xd4 */ 0x00, 0x00, 0x00}, {/* 0xd5 */ 0x00, 0x00, 0x00}, + {/* 0xd6 */ 0x00, 0x00, 0x00}, {/* 0xd7 */ 0x00, 0x00, 0x00}, + {/* 0xd8 */ 0x00, 0x00, 0x00}, {/* 0xd9 */ 0x00, 0x00, 0x00}, + {/* 0xda */ 0x00, 0x00, 0x00}, {/* 0xdb */ 0x00, 0x00, 0x00}, + {/* 0xdc */ 0x00, 0x00, 0x00}, {/* 0xdd */ 0x00, 0x00, 0x00}, + {/* 0xde */ 0x00, 0x00, 0x00}, {/* 0xdf */ 0x00, 0x00, 0x00}, + {/* 0xe0 */ 0x00, 0x00, 0x00}, {/* 0xe1 */ 0x00, 0x00, 0x00}, + {/* 0xe2 */ 0x00, 0x00, 0x00}, {/* 0xe3 */ 0x00, 0x00, 0x00}, + {/* 0xe4 */ 0x00, 0x00, 0x00}, {/* 0xe5 */ 0x00, 0x00, 0x00}, + {/* 0xe6 */ 0x00, 0x00, 0x00}, {/* 0xe7 */ 0x00, 0x00, 0x00}, + {/* 0xe8 */ 0x00, 0x00, 0x00}, {/* 0xe9 */ 0x00, 0x00, 0x00}, + {/* 0xea */ 0x00, 0x00, 0x00}, {/* 0xeb */ 0x00, 0x00, 0x00}, + {/* 0xec */ 0x00, 0x00, 0x00}, {/* 0xed */ 0x00, 0x00, 0x00}, + {/* 0xee */ 0x00, 0x00, 0x00}, {/* 0xef */ 0x00, 0x00, 0x00}, + {/* 0xf0 */ 0x00, 0x00, 0x00}, {/* 0xf1 */ 0x00, 0x00, 0x00}, + {/* 0xf2 */ 0x00, 0x00, 0x00}, {/* 0xf3 */ 0x00, 0x00, 0x00}, + {/* 0xf4 */ 0x00, 0x00, 0x00}, {/* 0xf5 */ 0x00, 0x00, 0x00}, + {/* 0xf6 */ 0x00, 0x00, 0x00}, {/* 0xf7 */ 0x00, 0x00, 0x00}, + {/* 0xf8 */ 0x00, 0x00, 0x00}, {/* 0xf9 */ 0x00, 0x00, 0x00}, + {/* 0xfa */ 0x00, 0x00, 0x00}, {/* 0xfb */ 0x00, 0x00, 0x00}, + {/* 0xfc */ 0x00, 0x00, 0x00}, {/* 0xfd */ 0x00, 0x00, 0x00}, + {/* 0xfe */ 0x00, 0x00, 0x00}, {/* 0xff */ 0x00, 0x00, 0x00}}; + +const bool sexp_char_defs_t::base64digit[256] = + {/* c is base64 digit */ + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ false, /* 0x2b + */ true, /* 0x2c , */ false, + /* 0x2d - */ false, /* 0x2e . */ false, /* 0x2f / */ true, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ false, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ false, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +const bool sexp_char_defs_t::tokenchar[256] = + {/* c can be in a token */ + /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, + /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, + /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, + /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, + /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, + /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, + /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, + /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, + /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, + /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, + /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, + /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, + /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, + /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, + /* 0x2a * */ true, /* 0x2b + */ true, /* 0x2c , */ false, + /* 0x2d - */ true, /* 0x2e . */ true, /* 0x2f / */ true, + /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, + /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, + /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, + /* 0x39 9 */ true, /* 0x3a : */ true, /* 0x3b ; */ false, + /* 0x3c < */ false, /* 0x3d = */ true, /* 0x3e > */ false, + /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, + /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, + /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, + /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, + /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, + /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, + /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, + /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, + /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, + /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, + /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ true, + /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, + /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, + /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, + /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, + /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, + /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, + /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, + /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, + /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, + /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, + /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, + /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, + /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, + /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, + /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, + /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, + /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, + /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, + /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, + /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, + /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, + /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, + /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, + /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, + /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, + /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, + /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, + /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, + /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, + /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, + /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, + /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, + /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, + /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, + /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, + /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, + /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, + /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, + /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, + /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, + /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, + /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, + /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, + /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, + /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, + /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, + /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, + /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, + /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, + /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, + /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, + /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, + /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; + +} // namespace sexp diff --git a/src/sexp-depth-manager.cpp b/src/sexp-depth-manager.cpp new file mode 100644 index 0000000..2f26e27 --- /dev/null +++ b/src/sexp-depth-manager.cpp @@ -0,0 +1,50 @@ +/** + * + * Copyright 2023 Ribose Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **/ + +#include "sexpp/sexp.h" + +namespace sexp { + +sexp_depth_manager::sexp_depth_manager(size_t m_depth) +{ + reset_depth(m_depth); +} +void sexp_depth_manager::reset_depth(size_t m_depth) +{ + depth = 0; + max_depth = m_depth; +} +void sexp_depth_manager::increase_depth(int count) +{ + if (max_depth != 0 && ++depth > max_depth) + sexp_error(sexp_exception_t::error, + "Maximum allowed SEXP list depth (%u) is exceeded", + max_depth, + 0, + count); +} +void sexp_depth_manager::decrease_depth(void) +{ + depth--; +} +} // namespace sexp diff --git a/src/sexp-error.cpp b/src/sexp-error.cpp new file mode 100644 index 0000000..3558f02 --- /dev/null +++ b/src/sexp-error.cpp @@ -0,0 +1,56 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "sexpp/sexp-error.h" + +namespace sexp { + +sexp_exception_t::severity sexp_exception_t::verbosity = sexp_exception_t::error; +bool sexp_exception_t::interactive = false; + +std::string sexp_exception_t::format(std::string prf, + std::string message, + severity level, + int position) +{ + std::string r = prf + (level == error ? " ERROR: " : " WARNING: ") + message; + if (position >= 0) + r += " at position " + std::to_string(position); + return r; +}; + +void sexp_error( + sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos) +{ + char tmp[256]; + sexp_exception_t::severity l = (sexp_exception_t::severity) level; + snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]), msg, c1, c2); + if (sexp_exception_t::shall_throw(l)) + throw sexp_exception_t(tmp, l, pos); + if (sexp_exception_t::is_interactive()) { + std::cout.flush() << std::endl + << "*** " << sexp_exception_t::format("SEXP", tmp, l, pos) << " ***" + << std::endl; + } +} +} // namespace sexp
\ No newline at end of file diff --git a/src/sexp-input.cpp b/src/sexp-input.cpp new file mode 100644 index 0000000..cb21686 --- /dev/null +++ b/src/sexp-input.cpp @@ -0,0 +1,514 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Original copyright + * + * SEXP implementation code sexp-input.c + * Ron Rivest + * 7/21/1997 + */ + +#include "sexpp/sexp.h" + +namespace sexp { + +/* + * sexp_input_stream_t::sexp_input_stream_t + * Creates and initializes new sexp_input_stream_t object. + */ + +sexp_input_stream_t::sexp_input_stream_t(std::istream *i, size_t m_depth) +{ + set_input(i, m_depth); +} + +/* + * sexp_input_stream_t::set_input(std::istream *i, size_t m_depth) + */ + +sexp_input_stream_t *sexp_input_stream_t::set_input(std::istream *i, size_t m_depth) +{ + input_file = i; + byte_size = 8; + next_char = ' '; + bits = 0; + n_bits = 0; + count = -1; + reset_depth(m_depth); + return this; +} + +/* + * sexp_input_stream_t::set_byte_size(newByteSize) + */ +sexp_input_stream_t *sexp_input_stream_t::set_byte_size(uint32_t newByteSize) +{ + byte_size = newByteSize; + n_bits = 0; + bits = 0; + return this; +} + +int sexp_input_stream_t::read_char(void) +{ + count++; + return input_file->get(); +} + +/* + * sexp_input_stream_t::get_char() + * This is one possible character input routine for an input stream. + * (This version uses the standard input stream.) + * get_char places next 8-bit character into is->next_char. + * It also updates the count of number of 8-bit characters read. + * The value EOF is obtained when no more input is available. + * This code handles 4-bit/6-bit/8-bit channels. + */ +sexp_input_stream_t *sexp_input_stream_t::get_char(void) +{ + int c; + if (next_char == EOF) { + byte_size = 8; + return this; + } + + while (true) { + c = next_char = read_char(); + if (c == EOF) + return this; + if ((byte_size == 6 && (c == '|' || c == '}')) || (byte_size == 4 && (c == '#'))) { + // end of region reached; return terminating character, after checking for + // unused bits + if (n_bits > 0 && (((1 << n_bits) - 1) & bits) != 0) { + sexp_error(sexp_exception_t::warning, + "%d-bit region ended with %d unused bits left-over", + byte_size, + n_bits, + count); + } + return set_byte_size(8); + } else if (byte_size != 8 && is_white_space(c)) + ; /* ignore white space in hex and base64 regions */ + else if (byte_size == 6 && c == '=') + ; /* ignore equals signs in base64 regions */ + else if (byte_size == 8) { + return this; + } else if (byte_size < 8) { + bits = bits << byte_size; + n_bits += byte_size; + if (byte_size == 6 && is_base64_digit(c)) + bits = bits | base64value(c); + else if (byte_size == 4 && is_hex_digit(c)) + bits = bits | hexvalue(c); + else { + sexp_error(sexp_exception_t::error, + "character '%c' found in %u-bit coding region", + next_char, + byte_size, + count); + } + if (n_bits >= 8) { + next_char = (bits >> (n_bits - 8)) & 0xFF; + n_bits -= 8; + return this; + } + } + } +} + +/* + * sexp_input_stream_t::skip_white_space + * Skip over any white space on the given sexp_input_stream_t. + */ +sexp_input_stream_t *sexp_input_stream_t::skip_white_space(void) +{ + while (is_white_space(next_char)) + get_char(); + return this; +} + +/* + * sexp_input_stream_t::skip_char(c) + * Skip the following input character on input stream is, if it is + * equal to the character c. If it is not equal, then an error occurs. + */ +sexp_input_stream_t *sexp_input_stream_t::skip_char(int c) +{ + if (next_char != c) + sexp_error(sexp_exception_t::error, + "character '%c' found where '%c' was expected", + next_char, + c, + count); + return get_char(); +} + +/* + * sexp_input_stream_t::scan_token(ss) + * scan one or more characters into simple string ss as a token. + */ +void sexp_input_stream_t::scan_token(sexp_simple_string_t &ss) +{ + skip_white_space(); + while (is_token_char(next_char)) { + ss.append(next_char); + get_char(); + } +} + +/* + * sexp_input_stream_t::scan_to_eof(void) + * scan one or more characters (until EOF reached) + * return an object that is just that string + */ +std::shared_ptr<sexp_object_t> sexp_input_stream_t::scan_to_eof(void) +{ + sexp_simple_string_t ss; + skip_white_space(); + while (next_char != EOF) { + ss.append(next_char); + get_char(); + } + auto s = std::make_shared<sexp_string_t>(); + s->set_string(ss); + return s; +} + +/* + * scan_decimal_string(is) + * returns long integer that is value of decimal number + */ +uint32_t sexp_input_stream_t::scan_decimal_string(void) +{ + uint32_t value = 0; + uint32_t i = 0; + while (is_dec_digit(next_char)) { + value = value * 10 + decvalue(next_char); + get_char(); + if (i++ > 8) + sexp_error(sexp_exception_t::error, "Decimal number is too long", 0, 0, count); + } + return value; +} + +/* + * sexp_input_stream_t::scan_verbatim_string(is,ss,length) + * Reads verbatim string of given length into simple string ss. + */ +void sexp_input_stream_t::scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length) +{ + skip_white_space()->skip_char(':'); + + // Some length is specified always, this is ensured by the caller's logic + assert(length != std::numeric_limits<uint32_t>::max()); + for (uint32_t i = 0; i < length; i++) { + ss.append(next_char); + get_char(); + } +} + +/* + * sexp_input_stream_t::scan_quoted_string(ss,length) + * Reads quoted string of given length into simple string ss. + * Handles ordinary C escapes. + * If of indefinite length, length is std::numeric_limits<uint32_t>::max(). + */ +void sexp_input_stream_t::scan_quoted_string(sexp_simple_string_t &ss, uint32_t length) +{ + skip_char('"'); + while (ss.length() <= length) { + if (next_char == '\"') { + if (length == std::numeric_limits<uint32_t>::max() || (ss.length() == length)) { + skip_char('\"'); + return; + } else + sexp_error(sexp_exception_t::error, + "Declared length was %d, but quoted string ended too early", + (int) length, + 0, + count); + } else if (next_char == '\\') /* handle escape sequence */ + { + get_char(); + switch (next_char) { + case 'b': + ss.append('\b'); + break; + case 't': + ss.append('\t'); + break; + case 'v': + ss.append('\v'); + break; + case 'n': + ss.append('\n'); + break; + case 'f': + ss.append('\f'); + break; + case 'r': + ss.append('\r'); + break; + case '\"': + ss.append('\"'); + break; + case '\'': + ss.append('\''); + break; + case '\\': + ss.append('\\'); + break; + case 'x': /* hexadecimal number */ + { + int j, val; + val = 0; + get_char(); + for (j = 0; j < 2; j++) { + if (is_hex_digit(next_char)) { + val = ((val << 4) | hexvalue(next_char)); + if (j < 1) { + get_char(); + } + } else + sexp_error(sexp_exception_t::error, + "Hex character \x5cx%x... too short", + val, + 0, + count); + } + ss.append(val); + } break; + case '\n': /* ignore backslash line feed */ + get_char(); /* also ignore following carriage-return if present */ + if (next_char != '\r') + continue; + break; + case '\r': /* ignore backslash carriage-return */ + get_char(); /* also ignore following linefeed if present */ + if (next_char != '\n') + continue; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { /* octal number */ + int j, val; + val = 0; + for (j = 0; j < 3; j++) { + if (next_char >= '0' && next_char <= '7') { + val = ((val << 3) | (next_char - '0')); + if (j < 2) + get_char(); + } else + sexp_error(sexp_exception_t::error, + "Octal character \\%o... too short", + val, + 0, + count); + } + if (val > 255) + sexp_error(sexp_exception_t::error, + "Octal character \\%o... too big", + val, + 0, + count); + ss.append(val); + } break; + default: + sexp_error(sexp_exception_t::error, + "Unknown escape sequence \\%c", + next_char, + 0, + count); + } + } /* end of handling escape sequence */ + else if (next_char == EOF) { + sexp_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); + } else { + ss.append(next_char); + } + get_char(); + } /* end of main while loop */ +} + +/* + * scan_hexadecimal_string(ss,length) + * Reads hexadecimal string into simple string ss. + * String is of given length result, or length = std::numeric_limits<uint32_t>::max() + * if indefinite length. + */ +void sexp_input_stream_t::scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length) +{ + set_byte_size(4)->skip_char('#'); + while (next_char != EOF && (next_char != '#' || get_byte_size() == 4)) { + ss.append(next_char); + get_char(); + } + skip_char('#'); + if (ss.length() != length && length != std::numeric_limits<uint32_t>::max()) + sexp_error(sexp_exception_t::warning, + "Hex string has length %d different than declared length %d", + ss.length(), + length, + count); +} + +/* + * sexp_input_stream_t::scan_base64_string(ss,length) + * Reads base64 string into simple string ss. + * String is of given length result, or length = std::numeric_limits<uint32_t>::max() + * if indefinite length. + */ +void sexp_input_stream_t::scan_base64_string(sexp_simple_string_t &ss, uint32_t length) +{ + set_byte_size(6)->skip_char('|'); + while (next_char != EOF && (next_char != '|' || get_byte_size() == 6)) { + ss.append(next_char); + get_char(); + } + skip_char('|'); + if (ss.length() != length && length != std::numeric_limits<uint32_t>::max()) + sexp_error(sexp_exception_t::warning, + "Base64 string has length %d different than declared length %d", + ss.length(), + length, + count); +} + +/* + * sexp_input_stream_t::scan_simple_string(void) + * Reads and returns a simple string from the input stream. + * Determines type of simple string from the initial character, and + * dispatches to appropriate routine based on that. + */ +sexp_simple_string_t sexp_input_stream_t::scan_simple_string(void) +{ + int length; + sexp_simple_string_t ss; + skip_white_space(); + /* Note that it is important in the following code to test for token-ness + * before checking the other cases, so that a token may begin with ":", + * which would otherwise be treated as a verbatim string missing a length. + */ + if (is_token_char(next_char) && !is_dec_digit(next_char)) { + scan_token(ss); + } else { + length = is_dec_digit(next_char) ? scan_decimal_string() : + std::numeric_limits<uint32_t>::max(); + + switch (next_char) { + case '\"': + scan_quoted_string(ss, length); + break; + case '#': + scan_hexadecimal_string(ss, length); + break; + case '|': + scan_base64_string(ss, length); + break; + case ':': + // ':' is 'tokenchar', so some length shall be defined + scan_verbatim_string(ss, length); + break; + default: { + const char *const msg = (next_char == EOF) ? "unexpected end of file" : + isprint(next_char) ? "illegal character '%c' (0x%x)" : + "illegal character 0x%x"; + sexp_error(sexp_exception_t::error, msg, next_char, next_char, count); + } + } + } + + if (ss.length() == 0) + sexp_error(sexp_exception_t::warning, "Simple string has zero length", 0, 0, count); + return ss; +} + +/* + * sexp_input_stream_t::scan_string(void) + * Reads and returns a string [presentationhint]string from input stream. + */ +std::shared_ptr<sexp_string_t> sexp_input_stream_t::scan_string(void) +{ + auto s = std::make_shared<sexp_string_t>(); + ; + s->parse(this); + return s; +} + +/* + * sexp_input_stream_t::scan_list(void) + * Read and return a sexp_list_t from the input stream. + */ +std::shared_ptr<sexp_list_t> sexp_input_stream_t::scan_list(void) +{ + auto list = std::make_shared<sexp_list_t>(); + list->parse(this); + return list; +} + +/* + * sexp_input_stream_t::scan_object(void) + * Reads and returns a sexp_object_t from the given input stream. + */ +std::shared_ptr<sexp_object_t> sexp_input_stream_t::scan_object(void) +{ + std::shared_ptr<sexp_object_t> object; + skip_white_space(); + if (next_char == '{' && byte_size != 6) { + set_byte_size(6)->skip_char('{'); + object = scan_object(); + skip_char('}'); + } else { + if (next_char == '(') + object = scan_list(); + else + object = scan_string(); + } + return object; +} + +/* + * sexp_input_stream_t::open_list(void) + */ +sexp_input_stream_t *sexp_input_stream_t::open_list(void) +{ + skip_char('('); + // gcc 4.8.5 generates wrong code in case of chaining like + // skip_char('(')->increase_depth(count) + increase_depth(count); + return this; +} +/* + * sexp_input_stream_t::close_list(void) + */ +sexp_input_stream_t *sexp_input_stream_t::close_list(void) +{ + skip_char(')'); + decrease_depth(); + return this; +} + +} // namespace sexp diff --git a/src/sexp-main.cpp b/src/sexp-main.cpp new file mode 100644 index 0000000..46fae63 --- /dev/null +++ b/src/sexp-main.cpp @@ -0,0 +1,231 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Original copyright + * + * SEXP implementation code sexp-main.c + * Ron Rivest + * 6/29/1997 + **/ + +#include <fstream> + +#include "sexpp/sexp.h" + +using namespace sexp; + +const char *help = "The program 'sexp' reads, parses, and prints out S-expressions.\n" + " INPUT:\n" + " Input is normally taken from stdin, but this can be changed:\n" + " -i filename -- takes input from file instead.\n" + " -p -- prompts user for console input\n" + " Input is normally parsed, but this can be changed:\n" + " -s -- treat input up to EOF as a single string\n" + " CONTROL LOOP:\n" + " The main routine typically reads one S-expression, prints it out " + "again, \n" + " and stops. This may be modified:\n" + " -x -- execute main loop repeatedly until EOF\n" + " OUTPUT:\n" + " Output is normally written to stdout, but this can be changed:\n" + " -o filename -- write output to file instead\n" + " The output format is normally canonical, but this can be changed:\n" + " -a -- write output in advanced transport format\n" + " -b -- write output in base-64 output format\n" + " -c -- write output in canonical format\n" + " -l -- suppress linefeeds after output\n" + " More than one output format can be requested at once.\n" + " There is normally a line-width of 75 on output, but:\n" + " -w width -- changes line width to specified width.\n" + " (0 implies no line-width constraint)\n" + " Running without switches implies: -p -a -b -c -x\n" + " Typical usage: cat certificate-file | sexp -a -x \n"; + +/*************************************************************************/ +/* main(argc,argv) + */ +int main(int argc, char **argv) +{ + char *c; + bool swa = true, swb = true, swc = true, swp = true, sws = false, swx = true, swl = false; + int i; + int ret = -1; + sexp_exception_t::set_interactive(true); + std::ifstream * ifs = nullptr; + sexp_input_stream_t * is = nullptr; + std::ofstream * ofs = nullptr; + sexp_output_stream_t *os = nullptr; + std::string ofname; + std::string ifname; + try { + std::shared_ptr<sexp_object_t> object; + + is = new sexp_input_stream_t(&std::cin); + os = new sexp_output_stream_t(&std::cout); + + if (argc > 1) + swa = swb = swc = swp = sws = swx = swl = false; + for (i = 1; i < argc; i++) { + c = argv[i]; + if (*c != '-') + throw sexp_exception_t( + std::string("Unrecognized switch ") + c, sexp_exception_t::error, EOF); + c++; + if (*c == 'a') + swa = true; /* advanced output */ + else if (*c == 'b') + swb = true; /* base-64 output */ + else if (*c == 'c') + swc = true; /* canonical output */ + else if (*c == 'h') { /* help */ + std::cout << help; + exit(0); + } else if (*c == 'i') { /* input file */ + if (i + 1 < argc) + i++; + ifs = new std::ifstream(argv[i], std::ifstream::binary); + if (ifs->fail()) + sexp_error(sexp_exception_t::error, "Can't open input file.", 0, 0, EOF); + is->set_input(ifs); + ifname = argv[i]; + } else if (*c == 'l') + swl = true; /* suppress linefeeds after output */ + else if (*c == 'o') { /* output file */ + if (i + 1 < argc) + i++; + ofs = new std::ofstream(argv[i], std::ifstream::binary); + if (ofs->fail()) + sexp_error(sexp_exception_t::error, "Can't open output file.", 0, 0, EOF); + os->set_output(ofs); + ofname = argv[i]; + } else if (*c == 'p') + swp = true; /* prompt for input */ + else if (*c == 's') + sws = true; /* treat input as one big string */ + else if (*c == 'w') { /* set output width */ + if (i + 1 < argc) + i++; + os->set_max_column(atoi(argv[i])); + } else if (*c == 'x') + swx = true; /* execute repeatedly */ + else + throw sexp_exception_t( + std::string("Unrecognized switch ") + argv[i], sexp_exception_t::error, EOF); + } + + if (swa == false && swb == false && swc == false) + swc = true; /* must have some output format! */ + + /* main loop */ + if (swp == 0) + is->get_char(); + else + is->set_next_char(-2); /* this is not EOF */ + while (is->get_next_char() != EOF) { + if (swp) { + if (ifname.empty()) + std::cout << "Input:"; + else + std::cout << "Reading input from " << ifname; + std::cout << std::endl; + std::cout.flush(); + } + + is->set_byte_size(8); + if (is->get_next_char() == -2) + is->get_char(); + + is->skip_white_space(); + if (is->get_next_char() == EOF) + break; + + object = sws ? is->scan_to_eof() : is->scan_object(); + + if (swp) + std::cout << std::endl; + + if (swc) { + if (swp) { + if (ofname.empty()) + std::cout << "Canonical output:" << std::endl; + else + std::cout << "Writing canonical output to '" << ofname << "'"; + } + object->print_canonical(os); + if (!swl) { + std::cout << std::endl; + } + } + + if (swb) { + if (swp) { + if (ofname.empty()) + std::cout << "Base64 (of canonical) output:" << std::endl; + else + std::cout << "Writing base64 (of canonical) output to '" << ofname + << "'"; + } + os->set_output(ofs ? ofs : &std::cout)->print_base64(object); + if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + + if (swa) { + if (swp) { + if (ofname.empty()) + std::cout << "Advanced transport output:" << std::endl; + else + std::cout << "Writing advanced transport output to '" << ofname << "'"; + } + os->set_output(ofs ? ofs : &std::cout)->print_advanced(object); + if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + + if (!swx) + break; + if (!swp) + is->skip_white_space(); + else if (!swl) { + std::cout << std::endl; + std::cout.flush(); + } + } + ret = 0; + } catch (sexp_exception_t &e) { + std::cout << e.what() << std::endl; + } catch (...) { + std::cout << "UNEXPECTED ERROR" << std::endl; + } + if (is) + delete is; + if (ifs) + delete ifs; + if (os) + delete os; + if (ofs) + delete ofs; + return ret; +}
\ No newline at end of file diff --git a/src/sexp-object.cpp b/src/sexp-object.cpp new file mode 100644 index 0000000..d01ae11 --- /dev/null +++ b/src/sexp-object.cpp @@ -0,0 +1,188 @@ +/**
+ *
+ * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Original copyright
+ *
+ * SEXP implementation code sexp-output.c
+ * Ron Rivest
+ * 5/5/1997
+ */
+
+#include "sexpp/sexp.h"
+
+namespace sexp {
+
+/*
+ * sexp_string_t::parse(sis)
+ * Parses the strin from input stream
+ */
+
+void sexp_string_t::parse(sexp_input_stream_t *sis)
+{
+ if (sis->get_next_char() == '[') { /* scan presentation hint */
+ sis->skip_char('[');
+ set_presentation_hint(sis->scan_simple_string());
+ sis->skip_white_space()->skip_char(']')->skip_white_space();
+ }
+ set_string(sis->scan_simple_string());
+}
+
+/*
+ * sexp_string_t::print_canonical(os)
+ * Prints out sexp string onto output stream os
+ */
+sexp_output_stream_t *sexp_string_t::print_canonical(sexp_output_stream_t *os) const
+{
+ if (with_presentation_hint) {
+ os->var_put_char('[');
+ presentation_hint.print_canonical_verbatim(os);
+ os->var_put_char(']');
+ }
+ data_string.print_canonical_verbatim(os);
+ return os;
+}
+
+/*
+ * sexp_string_t::print_advanced(os)
+ * Prints out sexp string onto output stream os
+ */
+sexp_output_stream_t *sexp_string_t::print_advanced(sexp_output_stream_t *os) const
+{
+ sexp_object_t::print_advanced(os);
+ if (with_presentation_hint) {
+ os->put_char('[');
+ presentation_hint.print_advanced(os);
+ os->put_char(']');
+ }
+ data_string.print_advanced(os);
+ return os;
+}
+
+/*
+ * sexp_string_t::advanced_length(os)
+ * Returns length of printed image of string
+ */
+size_t sexp_string_t::advanced_length(sexp_output_stream_t *os) const
+{
+ size_t len = 0;
+ if (with_presentation_hint)
+ len += 2 + presentation_hint.advanced_length(os);
+ len += data_string.advanced_length(os);
+ return len;
+}
+
+/*
+ * sexp_list_t::parse(sis)
+ * Parses the list from input stream
+ */
+
+void sexp_list_t::parse(sexp_input_stream_t *sis)
+{
+ sis->open_list()->skip_white_space();
+ if (sis->get_next_char() == ')') {
+ ;
+ } else {
+ push_back(sis->scan_object());
+ }
+
+ while (true) {
+ sis->skip_white_space();
+ if (sis->get_next_char() == ')') { /* we just grabbed last element of list */
+ sis->close_list();
+ return;
+
+ } else {
+ push_back(sis->scan_object());
+ }
+ }
+}
+
+/*
+ * sexp_list_t::print_canonical(os)
+ * Prints out the list "list" onto output stream os
+ */
+sexp_output_stream_t *sexp_list_t::print_canonical(sexp_output_stream_t *os) const
+{
+ os->var_open_list();
+ std::for_each(begin(), end(), [os](const std::shared_ptr<sexp_object_t> &obj) {
+ obj->print_canonical(os);
+ });
+ os->var_close_list();
+ return os;
+}
+
+/*
+ * sexp_list_t::print_advanced(os)
+ * Prints out the list onto output stream os.
+ * Uses print-length to determine length of the image. If it all fits
+ * on the current line, then it is printed that way. Otherwise, it is
+ * written out in "vertical" mode, with items of the list starting in
+ * the same column on successive lines.
+ */
+sexp_output_stream_t *sexp_list_t::print_advanced(sexp_output_stream_t *os) const
+{
+ sexp_object_t::print_advanced(os);
+ int vertical = false;
+ int firstelement = true;
+ os->open_list()->inc_indent();
+ vertical = (advanced_length(os) > os->get_max_column() - os->get_column());
+
+ std::for_each(begin(), end(), [&](const std::shared_ptr<sexp_object_t> &obj) {
+ if (!firstelement) {
+ if (vertical)
+ os->new_line(sexp_output_stream_t::advanced);
+ else
+ os->put_char(' ');
+ }
+ obj->print_advanced(os);
+ firstelement = false;
+ });
+
+ if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 2)
+ os->new_line(sexp_output_stream_t::advanced);
+ return os->dec_indent()->put_char(')');
+}
+
+/*
+ * sexp_list_t::advanced_length(os)
+ * Returns length of printed image of list given as iterator
+ */
+size_t sexp_list_t::advanced_length(sexp_output_stream_t *os) const
+{
+ size_t len = 1; /* for left paren */
+ std::for_each(begin(), end(), [&](const std::shared_ptr<sexp_object_t> &obj) {
+ len += obj->advanced_length(os);
+ });
+ return (len + 1); /* for final paren */
+}
+
+/*
+ * sexp_object_t::print_advanced(os)
+ * Prints out object on output stream os
+ */
+sexp_output_stream_t *sexp_object_t::print_advanced(sexp_output_stream_t *os) const
+{
+ if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 4)
+ os->new_line(sexp_output_stream_t::advanced);
+ return os;
+}
+
+} // namespace sexp
\ No newline at end of file diff --git a/src/sexp-output.cpp b/src/sexp-output.cpp new file mode 100644 index 0000000..07b476c --- /dev/null +++ b/src/sexp-output.cpp @@ -0,0 +1,197 @@ +/** + * + * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Original copyright + * + * SEXP implementation code sexp-output.c + * Ron Rivest + * 5/5/1997 + */ + +#include "sexpp/sexp.h" + +namespace sexp { + +static const char *hexDigits = "0123456789ABCDEF"; +static const char *base64Digits = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * sexp_output_stream_t::sexp_output_stream_t + * Creates and initializes new sexp_output_stream_t object. + */ +sexp_output_stream_t::sexp_output_stream_t(std::ostream *o, size_t m_depth) +{ + set_output(o, m_depth); +} + +/* + * sexp_output_stream_t::set_output + * Re-initializes new sexp_output_stream_t object. + */ +sexp_output_stream_t *sexp_output_stream_t::set_output(std::ostream *o, size_t m_depth) +{ + output_file = o; + byte_size = 8; + bits = 0; + n_bits = 0; + mode = canonical; + column = 0; + max_column = default_line_length; + indent = 0; + base64_count = 0; + reset_depth(m_depth); + return this; +} + +/* + * sexp_output_stream_t::put_char(c) + * Puts the character c out on the output stream os. + * Keeps track of the "column" the next output char will go to. + */ +sexp_output_stream_t *sexp_output_stream_t::put_char(int c) +{ + output_file->put(c); + column++; + return this; +} + +/* + * sexp_output_stream_t::var_put_char(c) + * put_char with variable sized output bytes considered. + * int c; -- this is always an eight-bit byte being output + */ +sexp_output_stream_t *sexp_output_stream_t::var_put_char(int c) +{ + c &= 0xFF; + bits = (bits << 8) | c; + n_bits += 8; + while (n_bits >= byte_size) { + if ((byte_size == 6 || byte_size == 4 || c == '}' || c == '{' || c == '#' || + c == '|') && + max_column > 0 && column >= max_column) + new_line(mode); + if (byte_size == 4) + put_char(hexDigits[(bits >> (n_bits - 4)) & 0x0F]); + else if (byte_size == 6) + put_char(base64Digits[(bits >> (n_bits - 6)) & 0x3F]); + else if (byte_size == 8) + put_char(bits & 0xFF); + n_bits -= byte_size; + base64_count++; + } + return this; +} + +/* + * sexp_output_stream_t::change_output_byte_size(newByteSize,newMode) + * Change os->byte_size to newByteSize + * record mode in output stream for automatic line breaks + */ +sexp_output_stream_t *sexp_output_stream_t::change_output_byte_size(int newByteSize, + sexp_print_mode newMode) +{ + if (newByteSize != 4 && newByteSize != 6 && newByteSize != 8) + sexp_error(sexp_exception_t::error, "Illegal output base %d", newByteSize, 0, EOF); + if (newByteSize != 8 && byte_size != 8) + sexp_error(sexp_exception_t::error, + "Illegal change of output byte size from %d to %d", + byte_size, + newByteSize, + EOF); + byte_size = newByteSize; + n_bits = 0; + bits = 0; + base64_count = 0; + mode = newMode; + return this; +} + +/* + * sexp_output_stream_t::flush() + * flush out any remaining bits + */ +sexp_output_stream_t *sexp_output_stream_t::flush(void) +{ + if (n_bits > 0) { + assert(byte_size == 6); + put_char(base64Digits[(bits << (6 - n_bits)) & 0x3F]); + n_bits = 0; + base64_count++; + } + if (byte_size == 6) { /* and add switch here */ + while ((base64_count & 3) != 0) { + if (max_column > 0 && column >= max_column) + new_line(mode); + put_char('='); + base64_count++; + } + } + return this; +} + +/* + * sexp_output_stream_t::new_line(mode) + * Outputs a newline symbol to the output stream os. + * For advanced mode, also outputs indentation as one blank per + * indentation level (but never indents more than half of max_column). + * Resets column for next output character. + */ +sexp_output_stream_t *sexp_output_stream_t::new_line(sexp_print_mode mode) +{ + if (mode == advanced || mode == base64) { + put_char('\n'); + column = 0; + } + if (mode == advanced) { + for (uint32_t i = 0; i < indent && (4 * i) < max_column; i++) + put_char(' '); + } + return this; +} + +/* + * sexp_output_stream_t::print_decimal(n) + * print out n in decimal to output stream os + */ +sexp_output_stream_t *sexp_output_stream_t::print_decimal(uint64_t n) +{ + char buffer[20]; // 64*ln(2)/ln(10) + // since itoa is not a part of any standard + snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%" PRIu64, n); + for (uint32_t i = 0; buffer[i] != 0; i++) + var_put_char(buffer[i]); + return this; +} + +/* + * base64 MODE + * Same as canonical, except all characters get put out as base 64 ones + */ + +sexp_output_stream_t *sexp_output_stream_t::print_base64( + const std::shared_ptr<sexp_object_t> &object) +{ + change_output_byte_size(8, base64)->var_put_char('{')->change_output_byte_size(6, base64); + print_canonical(object); + return flush()->change_output_byte_size(8, base64)->var_put_char('}'); +} +} // namespace sexp diff --git a/src/sexp-simple-string.cpp b/src/sexp-simple-string.cpp new file mode 100644 index 0000000..0e4c869 --- /dev/null +++ b/src/sexp-simple-string.cpp @@ -0,0 +1,191 @@ +/**
+ *
+ * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Original copyright
+ *
+ * SEXP implementation code sexp-output.c
+ * Ron Rivest
+ * 5/5/1997
+ */
+
+#include "sexpp/sexp.h"
+
+namespace sexp {
+/*
+ * sexp_simple_string_t::print_canonical_verbatim(os)
+ * Print out simple string on output stream os as verbatim string.
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_canonical_verbatim(
+ sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ /* print out len: */
+ os->print_decimal(length())->var_put_char(':');
+ /* print characters in fragment */
+ for (uint32_t i = 0; i < length(); i++)
+ os->var_put_char((int) *c++);
+ return os;
+}
+
+/*
+ * sexp_simple_string_t::advanced_length(os)
+ * Returns length of printed image of s
+ */
+size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const
+{
+ if (can_print_as_token(os))
+ return advanced_length_token();
+ else if (can_print_as_quoted_string())
+ return advanced_length_quoted();
+ else if (length() <= 4 && os->get_byte_size() == 8)
+ return advanced_length_hexadecimal();
+ else if (os->get_byte_size() == 8)
+ return advanced_length_base64();
+ else
+ return 0; /* an error condition */
+}
+
+/*
+ * sexp_simple_string_t::print_token(os)
+ * Prints out simple string ss as a token (assumes that this is OK).
+ * May run over max-column, but there is no fragmentation allowed...
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_token(sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ if (os->get_max_column() > 0 && os->get_column() > (os->get_max_column() - length()))
+ os->new_line(sexp_output_stream_t::advanced);
+ for (uint32_t i = 0; i < length(); i++)
+ os->put_char((int) (*c++));
+ return os;
+}
+
+/*
+ * sexp_simple_string_t::print_base64(os)
+ * Prints out simple string ss as a base64 value.
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_base64(sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ os->var_put_char('|')->change_output_byte_size(6, sexp_output_stream_t::advanced);
+ for (uint32_t i = 0; i < length(); i++)
+ os->var_put_char((int) (*c++));
+ return os->flush()
+ ->change_output_byte_size(8, sexp_output_stream_t::advanced)
+ ->var_put_char('|');
+}
+
+/*
+ * sexp_simple_string_t::print_hexadecimal(os)
+ * Prints out simple string as a hexadecimal value.
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_hexadecimal(sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ os->put_char('#')->change_output_byte_size(4, sexp_output_stream_t::advanced);
+ for (uint32_t i = 0; i < length(); i++)
+ os->var_put_char((int) (*c++));
+ return os->flush()
+ ->change_output_byte_size(8, sexp_output_stream_t::advanced)
+ ->put_char('#');
+}
+
+/*
+ * sexp_simple_string_t::print_quoted(os)
+ * Prints out simple string ss as a quoted string
+ * This code assumes that all characters are tokenchars and blanks,
+ * so no escape sequences need to be generated.
+ * May run over max-column, but there is no fragmentation allowed...
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_quoted(sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ os->put_char('\"');
+ for (uint32_t i = 0; i < length(); i++) {
+ if (os->get_max_column() > 0 && os->get_column() >= os->get_max_column() - 2) {
+ os->put_char('\\')->put_char('\n');
+ os->reset_column();
+ }
+ os->put_char(*c++);
+ }
+ return os->put_char('\"');
+}
+
+/*
+ * sexp_simple_string_t::print_advanced(os)
+ * Prints out simple string onto output stream ss
+ */
+sexp_output_stream_t *sexp_simple_string_t::print_advanced(sexp_output_stream_t *os) const
+{
+ if (can_print_as_token(os))
+ print_token(os);
+ else if (can_print_as_quoted_string())
+ print_quoted(os);
+ else if (length() <= 4 && os->get_byte_size() == 8)
+ print_hexadecimal(os);
+ else if (os->get_byte_size() == 8)
+ print_base64(os);
+ else
+ sexp_error(sexp_exception_t::error,
+ "Can't print in advanced mode with restricted output character set",
+ 0,
+ 0,
+ EOF);
+ return os;
+}
+
+/*
+ * sexp_simple_string_t::can_print_as_quoted_string(void)
+ * Returns true if simple string can be printed as a quoted string.
+ * Must have only tokenchars and blanks.
+ */
+bool sexp_simple_string_t::can_print_as_quoted_string(void) const
+{
+ const octet_t *c = c_str();
+ for (uint32_t i = 0; i < length(); i++, c++) {
+ if (!is_token_char((int) (*c)) && *c != ' ')
+ return false;
+ }
+ return true;
+}
+
+/*
+ * sexp_simple_string_t::can_print_as_token(os)
+ * Returns true if simple string can be printed as a token.
+ * Doesn't begin with a digit, and all characters are tokenchars.
+ */
+bool sexp_simple_string_t::can_print_as_token(const sexp_output_stream_t *os) const
+{
+ const octet_t *c = c_str();
+ if (length() <= 0)
+ return false;
+ if (is_dec_digit((int) *c))
+ return false;
+ if (os->get_max_column() > 0 && os->get_column() + length() >= os->get_max_column())
+ return false;
+ for (uint32_t i = 0; i < length(); i++) {
+ if (!is_token_char((int) (*c++)))
+ return false;
+ }
+ return true;
+}
+
+} // namespace sexp
|