diff options
Diffstat (limited to 'libxsde/xsde/cxx/parser/validating/base64-binary.cxx')
-rw-r--r-- | libxsde/xsde/cxx/parser/validating/base64-binary.cxx | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/libxsde/xsde/cxx/parser/validating/base64-binary.cxx b/libxsde/xsde/cxx/parser/validating/base64-binary.cxx new file mode 100644 index 0000000..994c14b --- /dev/null +++ b/libxsde/xsde/cxx/parser/validating/base64-binary.cxx @@ -0,0 +1,281 @@ +// file : xsde/cxx/parser/validating/base64-binary.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <xsde/cxx/config.hxx> + +#include <xsde/cxx/parser/validating/base64-binary.hxx> + +static unsigned char +base64_decode (char c) +{ + unsigned char r = 0xFF; + + if (c >= 'A' && c <= 'Z') + r = static_cast<unsigned char> (c - 'A'); + else if (c >= 'a' && c <= 'z') + r = static_cast<unsigned char> (c - 'a' + 26); + else if (c >= '0' && c <= '9') + r = static_cast<unsigned char> (c - '0' + 52); + else if (c == '+') + r = 62; + else if (c == '/') + r = 63; + + return r; +} + +namespace xsde +{ + namespace cxx + { + namespace parser + { + namespace validating + { + base64_binary_pimpl:: + ~base64_binary_pimpl () + { + if (!base_) + delete buf_; + } + + void base64_binary_pimpl:: + _reset () + { + base64_binary_pskel::_reset (); + + if (!base_) + { + delete buf_; + buf_ = 0; + } + } + + base64_binary_pimpl:: + base64_binary_pimpl (bool base) + : base_ (base), buf_ (0) + { + } + + void base64_binary_pimpl:: + pre_impl (buffer* b) + { + buf_ = b; + } + + void base64_binary_pimpl:: + _pre () + { + if (buf_ == 0) + { + buf_ = new buffer (); + +#ifndef XSDE_EXCEPTIONS + if (buf_ == 0) + { + _sys_error (sys_error::no_memory); + return; + } +#endif + } + +#ifdef XSDE_EXCEPTIONS + str_.assign ("", 0); +#else + if (str_.assign ("", 0)) + _sys_error (sys_error::no_memory); +#endif + } + + void base64_binary_pimpl:: + _characters (const ro_string& s) + { + if (str_.size () == 0) + { + ro_string tmp (s.data (), s.size ()); + + if (trim_left (tmp) != 0) + { +#ifdef XSDE_EXCEPTIONS + str_.append (tmp.data (), tmp.size ()); +#else + if (str_.append (tmp.data (), tmp.size ())) + _sys_error (sys_error::no_memory); +#endif + } + } + else + { +#ifdef XSDE_EXCEPTIONS + str_.append (s.data (), s.size ()); +#else + if (str_.append (s.data (), s.size ())) + _sys_error (sys_error::no_memory); +#endif + } + } + + void base64_binary_pimpl:: + _post () + { + typedef string::size_type size_type; + + size_type size = str_.size (); + const char* src = str_.data (); + + // Remove all whitespaces. + // + { + size_type j = 0; + bool subs = false; + + for (size_type i = 0; i < size; ++i) + { + char c = str_[i]; + + if (c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09) + { + subs = true; + } + else + { + if (subs) + subs = false; + + str_[j++] = c; + } + } + + size = j; + str_.truncate (size); + } + + // Our length should be a multiple of four. + // + if (size == 0 || size % 4 != 0) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + size_type quad_count = size / 4; + size_type capacity = quad_count * 3 + 1; + +#ifdef XSDE_EXCEPTIONS + buf_->size (capacity); +#else + if (buf_->size (capacity)) + { + _sys_error (sys_error::no_memory); + return; + } +#endif + char* dst = buf_->data (); + + // Source and destination indexes. + // + size_type si = 0; + size_type di = 0; + + // Process all quads except the last one. + // + unsigned char b1, b2, b3, b4; + + for (size_type q = 0; q < quad_count - 1; ++q) + { + b1 = base64_decode (src[si++]); + b2 = base64_decode (src[si++]); + b3 = base64_decode (src[si++]); + b4 = base64_decode (src[si++]); + + if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF || b4 == 0xFF) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + dst[di++] = (b1 << 2) | (b2 >> 4); + dst[di++] = (b2 << 4) | (b3 >> 2); + dst[di++] = (b3 << 6) | b4; + } + + // Process the last quad. The first two octets are always there. + // + b1 = base64_decode (src[si++]); + b2 = base64_decode (src[si++]); + + if (b1 == 0xFF || b2 == 0xFF) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + char e3 = src[si++]; + char e4 = src[si++]; + + if (e4 == '=') + { + if (e3 == '=') + { + // Two pads. Last 4 bits in b2 should be zero. + // + if ((b2 & 0x0F) != 0) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + dst[di++] = (b1 << 2) | (b2 >> 4); + } + else + { + // One pad. Last 2 bits in b3 should be zero. + // + b3 = base64_decode (e3); + + if (b3 == 0xFF || (b3 & 0x03) != 0) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + dst[di++] = (b1 << 2) | (b2 >> 4); + dst[di++] = (b2 << 4) | (b3 >> 2); + } + } + else + { + // No pads. + // + b3 = base64_decode (e3); + b4 = base64_decode (e4); + + if (b3 == 0xFF || b4 == 0xFF) + { + _schema_error (schema_error::invalid_base64_binary_value); + return; + } + + dst[di++] = (b1 << 2) | (b2 >> 4); + dst[di++] = (b2 << 4) | (b3 >> 2); + dst[di++] = (b3 << 6) | b4; + } + + // Set the real size. + // + buf_->size (di); + } + + buffer* base64_binary_pimpl:: + post_base64_binary () + { + buffer* r = buf_; + buf_ = 0; + return r; + } + } + } + } +} |