summaryrefslogtreecommitdiffstats
path: root/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/third_party/rnp/src/libsexp/include/sexp/sexp.h435
1 files changed, 435 insertions, 0 deletions
diff --git a/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h b/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h
new file mode 100644
index 0000000000..52cad55751
--- /dev/null
+++ b/comm/third_party/rnp/src/libsexp/include/sexp/sexp.h
@@ -0,0 +1,435 @@
+/**
+ *
+ * Copyright (c) 2022-2023, [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ * This file is a part of RNP sexp library
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Original copyright
+ *
+ * SEXP standard header file: sexp.h
+ * Ronald L. Rivest
+ * 6/29/1997
+ */
+
+#pragma once
+
+#include <climits>
+#include <limits>
+#include <cctype>
+#include <locale>
+#include <cstring>
+#include <memory>
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cassert>
+
+#include "sexp-error.h"
+
+namespace sexp {
+/*
+ * SEXP octet_t definitions
+ * We maintain some presumable redundancy with ctype
+ * However, we do enforce 'C' locale this way
+ */
+
+class sexp_char_defs_t {
+ protected:
+ static const bool base64digit[256]; /* true if c is base64 digit */
+ static const bool tokenchar[256]; /* true if c can be in a token */
+ static const unsigned char values[256][3]; /* values of c as { dec. hex, base64 } digit */
+ static std::locale c_locale;
+
+ static bool is_white_space(int c)
+ {
+ return c >= 0 && c <= 255 && std::isspace((char) c, c_locale);
+ };
+ static bool is_dec_digit(int c)
+ {
+ return c >= 0 && c <= 255 && std::isdigit((char) c, c_locale);
+ };
+ static bool is_hex_digit(int c)
+ {
+ return c >= 0 && c <= 255 && std::isxdigit((char) c, c_locale);
+ };
+ static bool is_base64_digit(int c) { return c >= 0 && c <= 255 && base64digit[c]; };
+ static bool is_token_char(int c) { return c >= 0 && c <= 255 && tokenchar[c]; };
+ static bool is_alpha(int c)
+ {
+ return c >= 0 && c <= 255 && std::isalpha((char) c, c_locale);
+ };
+
+ /* decvalue(c) is value of c as dec digit */
+ static unsigned char decvalue(int c) { return (c >= 0 && c <= 255) ? values[c][0] : 0; };
+ /* hexvalue(c) is value of c as a hex digit */
+ static unsigned char hexvalue(int c) { return (c >= 0 && c <= 255) ? values[c][1] : 0; };
+ /* base64value(c) is value of c as base64 digit */
+ static unsigned char base64value(int c)
+ {
+ return (c >= 0 && c <= 255) ? values[c][2] : 0;
+ };
+};
+
+class sexp_string_t;
+class sexp_list_t;
+
+class sexp_output_stream_t;
+class sexp_input_stream_t;
+
+/*
+ * SEXP simple string
+ */
+
+typedef uint8_t octet_t;
+
+class sexp_simple_string_t : public std::basic_string<octet_t>, private sexp_char_defs_t {
+ public:
+ sexp_simple_string_t(void) = default;
+ sexp_simple_string_t(const octet_t *dt) : std::basic_string<octet_t>{dt} {}
+ sexp_simple_string_t(const octet_t *bt, size_t ln) : std::basic_string<octet_t>{bt, ln} {}
+ sexp_simple_string_t &append(int c)
+ {
+ (*this) += (octet_t)(c & 0xFF);
+ return *this;
+ }
+ // Returns length for printing simple string as a token
+ size_t advanced_length_token(void) const { return length(); }
+ // Returns length for printing simple string as a base64 string
+ size_t advanced_length_base64(void) const { return (2 + 4 * ((length() + 2) / 3)); }
+ // Returns length for printing simple string ss in quoted-string mode
+ size_t advanced_length_quoted(void) const { return (1 + length() + 1); }
+ // Returns length for printing simple string ss in hexadecimal mode
+ size_t advanced_length_hexadecimal(void) const { return (1 + 2 * length() + 1); }
+ size_t advanced_length(sexp_output_stream_t *os) const;
+
+ sexp_output_stream_t *print_canonical_verbatim(sexp_output_stream_t *os) const;
+ sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const;
+ sexp_output_stream_t *print_token(sexp_output_stream_t *os) const;
+ sexp_output_stream_t *print_quoted(sexp_output_stream_t *os) const;
+ sexp_output_stream_t *print_hexadecimal(sexp_output_stream_t *os) const;
+ sexp_output_stream_t *print_base64(sexp_output_stream_t *os) const;
+
+ bool can_print_as_quoted_string(void) const;
+ bool can_print_as_token(const sexp_output_stream_t *os) const;
+
+ bool operator==(const char *right) const noexcept
+ {
+ return length() == std::strlen(right) && std::memcmp(data(), right, length()) == 0;
+ }
+
+ bool operator!=(const char *right) const noexcept
+ {
+ return length() != std::strlen(right) || std::memcmp(data(), right, length()) != 0;
+ }
+
+ unsigned as_unsigned() const noexcept
+ {
+ return empty() ? std::numeric_limits<uint32_t>::max() :
+ (unsigned) atoi(reinterpret_cast<const char *>(c_str()));
+ }
+};
+
+inline bool operator==(const sexp_simple_string_t *left, const std::string &right) noexcept
+{
+ return *left == right.c_str();
+}
+
+inline bool operator!=(const sexp_simple_string_t *left, const std::string &right) noexcept
+{
+ return *left != right.c_str();
+}
+
+/*
+ * SEXP object
+ */
+
+class sexp_object_t {
+ public:
+ virtual ~sexp_object_t(){};
+
+ virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const = 0;
+ virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const;
+ virtual size_t advanced_length(sexp_output_stream_t *os) const = 0;
+
+ virtual sexp_list_t * sexp_list_view(void) noexcept { return nullptr; }
+ virtual sexp_string_t *sexp_string_view(void) noexcept { return nullptr; }
+ virtual bool is_sexp_list(void) const noexcept { return false; }
+ virtual bool is_sexp_string(void) const noexcept { return false; }
+
+ virtual const sexp_list_t *sexp_list_at(
+ std::vector<std::shared_ptr<sexp_object_t>>::size_type pos) const noexcept
+ {
+ return nullptr;
+ }
+ virtual const sexp_string_t *sexp_string_at(
+ std::vector<std::shared_ptr<sexp_object_t>>::size_type pos) const noexcept
+ {
+ return nullptr;
+ }
+ virtual const sexp_simple_string_t *sexp_simple_string_at(
+ std::vector<std::shared_ptr<sexp_object_t>>::size_type pos) const noexcept
+ {
+ return nullptr;
+ }
+ virtual bool operator==(const char *right) const noexcept { return false; }
+ virtual bool operator!=(const char *right) const noexcept { return true; }
+ virtual unsigned as_unsigned() const noexcept
+ {
+ return std::numeric_limits<uint32_t>::max();
+ }
+};
+
+/*
+ * SEXP string
+ */
+
+class sexp_string_t : public sexp_object_t {
+ protected:
+ bool with_presentation_hint;
+ sexp_simple_string_t presentation_hint;
+ sexp_simple_string_t data_string;
+
+ public:
+ sexp_string_t(const octet_t *dt) : with_presentation_hint(false), data_string(dt) {}
+ sexp_string_t(const octet_t *bt, size_t ln)
+ : with_presentation_hint(false), data_string(bt, ln)
+ {
+ }
+ sexp_string_t(const std::string &str)
+ : with_presentation_hint(false),
+ data_string(reinterpret_cast<const octet_t *>(str.data()))
+ {
+ }
+ sexp_string_t(void) : with_presentation_hint(false) {}
+ sexp_string_t(sexp_input_stream_t *sis) { parse(sis); };
+
+ const bool has_presentation_hint(void) const noexcept { return with_presentation_hint; }
+ const sexp_simple_string_t &get_string(void) const noexcept { return data_string; }
+ const sexp_simple_string_t &set_string(const sexp_simple_string_t &ss)
+ {
+ return data_string = ss;
+ }
+ const sexp_simple_string_t &get_presentation_hint(void) const noexcept
+ {
+ return presentation_hint;
+ }
+ const sexp_simple_string_t &set_presentation_hint(const sexp_simple_string_t &ph)
+ {
+ with_presentation_hint = true;
+ return presentation_hint = ph;
+ }
+
+ virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const;
+ virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const;
+ virtual size_t advanced_length(sexp_output_stream_t *os) const;
+
+ virtual sexp_string_t *sexp_string_view(void) noexcept { return this; }
+ virtual bool is_sexp_string(void) const noexcept { return true; }
+
+ virtual bool operator==(const char *right) const noexcept { return data_string == right; }
+ virtual bool operator!=(const char *right) const noexcept { return data_string != right; }
+
+ void parse(sexp_input_stream_t *sis);
+ virtual unsigned as_unsigned() const noexcept { return data_string.as_unsigned(); }
+};
+
+inline bool operator==(const sexp_string_t *left, const std::string &right) noexcept
+{
+ return *left == right.c_str();
+}
+
+inline bool operator!=(const sexp_string_t *left, const std::string &right) noexcept
+{
+ return *left != right.c_str();
+}
+
+/*
+ * SEXP list
+ */
+
+class sexp_list_t : public sexp_object_t, public std::vector<std::shared_ptr<sexp_object_t>> {
+ public:
+ virtual ~sexp_list_t() {}
+
+ virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const;
+ virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const;
+ virtual size_t advanced_length(sexp_output_stream_t *os) const;
+
+ virtual sexp_list_t *sexp_list_view(void) noexcept { return this; }
+ virtual bool is_sexp_list(void) const noexcept { return true; }
+
+ virtual const sexp_list_t *sexp_list_at(size_type pos) const noexcept
+ {
+ return pos < size() ? (*at(pos)).sexp_list_view() : nullptr;
+ }
+ virtual const sexp_string_t *sexp_string_at(size_type pos) const noexcept
+ {
+ return pos < size() ? (*at(pos)).sexp_string_view() : nullptr;
+ }
+ const sexp_simple_string_t *sexp_simple_string_at(size_type pos) const noexcept
+ {
+ auto s = sexp_string_at(pos);
+ return s != nullptr ? &s->get_string() : nullptr;
+ }
+
+ void parse(sexp_input_stream_t *sis);
+};
+
+/*
+ * SEXP input stream
+ */
+
+class sexp_input_stream_t : public sexp_char_defs_t {
+ protected:
+ std::istream *input_file;
+ uint32_t byte_size; /* 4 or 6 or 8 == currently scanning mode */
+ int next_char; /* character currently being scanned */
+ uint32_t bits; /* Bits waiting to be used */
+ uint32_t n_bits; /* number of such bits waiting to be used */
+ int count; /* number of 8-bit characters output by get_char */
+ size_t depth; /* current depth of nested SEXP lists */
+ size_t max_depth; /* maximum allowed depth of nested SEXP lists, 0 if no limit */
+
+ virtual int read_char(void);
+
+ public:
+ sexp_input_stream_t(std::istream *i, size_t max_depth = 0);
+ virtual ~sexp_input_stream_t() = default;
+ sexp_input_stream_t *set_input(std::istream *i, size_t max_depth = 0);
+ sexp_input_stream_t *set_byte_size(uint32_t new_byte_size);
+ uint32_t get_byte_size(void) { return byte_size; }
+ sexp_input_stream_t *get_char(void);
+ sexp_input_stream_t *skip_white_space(void);
+ sexp_input_stream_t *skip_char(int c);
+ sexp_input_stream_t *increase_depth(void)
+ {
+ 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);
+ return this;
+ }
+ sexp_input_stream_t *decrease_depth(void)
+ {
+ depth--;
+ return this;
+ }
+
+ std::shared_ptr<sexp_object_t> scan_to_eof();
+ std::shared_ptr<sexp_object_t> scan_object(void);
+ std::shared_ptr<sexp_string_t> scan_string(void);
+ std::shared_ptr<sexp_list_t> scan_list(void);
+ sexp_simple_string_t scan_simple_string(void);
+ void scan_token(sexp_simple_string_t &ss);
+ void scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length);
+ void scan_quoted_string(sexp_simple_string_t &ss, uint32_t length);
+ void scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length);
+ void scan_base64_string(sexp_simple_string_t &ss, uint32_t length);
+ uint32_t scan_decimal_string(void);
+
+ int get_next_char(void) const { return next_char; }
+ int set_next_char(int c) { return next_char = c; }
+};
+
+/*
+ * SEXP output stream
+ */
+
+class sexp_output_stream_t {
+ public:
+ const uint32_t default_line_length = 75;
+ enum sexp_print_mode { /* PRINTING MODES */
+ canonical = 1, /* standard for hashing and tranmission */
+ base64 = 2, /* base64 version of canonical */
+ advanced = 3 /* pretty-printed */
+ };
+
+ protected:
+ std::ostream * output_file;
+ uint32_t base64_count; /* number of hex or base64 chars printed this region */
+ uint32_t byte_size; /* 4 or 6 or 8 depending on output mode */
+ uint32_t bits; /* bits waiting to go out */
+ uint32_t n_bits; /* number of bits waiting to go out */
+ sexp_print_mode mode; /* base64, advanced, or canonical */
+ uint32_t column; /* column where next character will go */
+ uint32_t max_column; /* max usable column, or 0 if no maximum */
+ uint32_t indent; /* current indentation level (starts at 0) */
+ public:
+ sexp_output_stream_t(std::ostream *o);
+ sexp_output_stream_t *set_output(std::ostream *o);
+ sexp_output_stream_t *put_char(int c); /* output a character */
+ sexp_output_stream_t *new_line(sexp_print_mode mode); /* go to next line (and indent) */
+ sexp_output_stream_t *var_put_char(int c);
+ sexp_output_stream_t *flush(void);
+ sexp_output_stream_t *print_decimal(uint64_t n);
+
+ sexp_output_stream_t *change_output_byte_size(int newByteSize, sexp_print_mode mode);
+
+ sexp_output_stream_t *print_canonical(const std::shared_ptr<sexp_object_t> &obj)
+ {
+ return obj->print_canonical(this);
+ }
+ sexp_output_stream_t *print_advanced(const std::shared_ptr<sexp_object_t> &obj)
+ {
+ return obj->print_advanced(this);
+ };
+ sexp_output_stream_t *print_base64(const std::shared_ptr<sexp_object_t> &obj);
+ sexp_output_stream_t *print_canonical(const sexp_simple_string_t *ss)
+ {
+ return ss->print_canonical_verbatim(this);
+ }
+ sexp_output_stream_t *print_advanced(const sexp_simple_string_t *ss)
+ {
+ return ss->print_advanced(this);
+ };
+
+ uint32_t get_byte_size(void) const { return byte_size; }
+ uint32_t get_column(void) const { return column; }
+ sexp_output_stream_t *reset_column(void)
+ {
+ column = 0;
+ return this;
+ }
+ uint32_t get_max_column(void) const { return max_column; }
+ sexp_output_stream_t *set_max_column(uint32_t mc)
+ {
+ max_column = mc;
+ return this;
+ }
+ sexp_output_stream_t *inc_indent(void)
+ {
+ ++indent;
+ return this;
+ }
+ sexp_output_stream_t *dec_indent(void)
+ {
+ --indent;
+ return this;
+ }
+};
+
+} // namespace sexp