// file : xsd/cxx/parser/validating/xml-schema-pimpl.txx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2008 Code Synthesis Tools CC // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include #include #include #include namespace xsd { namespace cxx { namespace parser { namespace validating { // Note that most of the types implemented here cannot have // whitespaces in the value. As result we don't need to waste // time collapsing whitespaces. All we need to do is trim the // string representation which can be done without copying. // // Character table. // namespace bits { const unsigned char ncname_mask = 0x1; const unsigned char name_first_mask = 0x2; const unsigned char name_mask = 0x4; template struct char_table { static C table[0x80]; }; template C char_table::table[0x80] = { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD0, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x48, 0x58, 0x48, 0x48, 0x48, 0x40, 0x58, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4D, 0x4D, 0x58, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 0x48, 0x50, 0x48, 0x58, 0x48, 0x48, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x48, 0x48, 0x40, 0x48, 0x4F, 0x48, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x48, 0x48, 0x48, 0x48, 0x48 }; } // any_type // template void any_type_pimpl:: post_any_type () { } // any_simple_type // template void any_simple_type_pimpl:: post_any_simple_type () { } // boolean // template void boolean_pimpl:: _pre () { str_.clear (); } template void boolean_pimpl:: _characters (const ro_string& s) { str_ += s; } template void boolean_pimpl:: _post () { ro_string str (str_); trim (str); if (str == bits::true_ () || str == bits::one ()) value_ = true; else if (str == bits::false_ () || str == bits::zero ()) value_ = false; else throw invalid_value (bits::boolean (), str); } template bool boolean_pimpl:: post_boolean () { return value_; } // byte // template void byte_pimpl:: _pre () { str_.clear (); } template void byte_pimpl:: _characters (const ro_string& s) { str_ += s; } template void byte_pimpl:: _post () { ro_string str (str_); trim (str); short t; zc_istream is (str); if (is >> t && is.exhausted () && t >= -128 && t <= 127) value_ = static_cast (t); else throw invalid_value (bits::byte (), str); } template signed char byte_pimpl:: post_byte () { return value_; } // unsigned_byte // template void unsigned_byte_pimpl:: _pre () { str_.clear (); } template void unsigned_byte_pimpl:: _characters (const ro_string& s) { str_ += s; } template void unsigned_byte_pimpl:: _post () { ro_string str (str_); trim (str); unsigned short t; zc_istream is (str); if (is >> t && is.exhausted () && t <= 255) value_ = static_cast (t); else throw invalid_value (bits::unsigned_byte (), str); } template unsigned char unsigned_byte_pimpl:: post_unsigned_byte () { return value_; } // short // template void short_pimpl:: _pre () { str_.clear (); } template void short_pimpl:: _characters (const ro_string& s) { str_ += s; } template void short_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::short_ (), str); } template short short_pimpl:: post_short () { return value_; } // unsigned_short // template void unsigned_short_pimpl:: _pre () { str_.clear (); } template void unsigned_short_pimpl:: _characters (const ro_string& s) { str_ += s; } template void unsigned_short_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::unsigned_short (), str); } template unsigned short unsigned_short_pimpl:: post_unsigned_short () { return value_; } // int // template void int_pimpl:: _pre () { str_.clear (); } template void int_pimpl:: _characters (const ro_string& s) { str_ += s; } template void int_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::int_ (), str); } template int int_pimpl:: post_int () { return value_; } // unsigned_int // template void unsigned_int_pimpl:: _pre () { str_.clear (); } template void unsigned_int_pimpl:: _characters (const ro_string& s) { str_ += s; } template void unsigned_int_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::unsigned_int (), str); } template unsigned int unsigned_int_pimpl:: post_unsigned_int () { return value_; } // long // template void long_pimpl:: _pre () { str_.clear (); } template void long_pimpl:: _characters (const ro_string& s) { str_ += s; } template void long_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::long_ (), str); } template long long long_pimpl:: post_long () { return value_; } // unsigned_long // template void unsigned_long_pimpl:: _pre () { str_.clear (); } template void unsigned_long_pimpl:: _characters (const ro_string& s) { str_ += s; } template void unsigned_long_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::unsigned_long (), str); } template unsigned long long unsigned_long_pimpl:: post_unsigned_long () { return value_; } // integer // template void integer_pimpl:: _pre () { str_.clear (); } template void integer_pimpl:: _characters (const ro_string& s) { str_ += s; } template void integer_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::integer (), str); } template long long integer_pimpl:: post_integer () { return value_; } // negative_integer // template void negative_integer_pimpl:: _pre () { str_.clear (); } template void negative_integer_pimpl:: _characters (const ro_string& s) { str_ += s; } template void negative_integer_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted () && value_ < 0)) throw invalid_value (bits::negative_integer (), str); } template long long negative_integer_pimpl:: post_negative_integer () { return value_; } // non_positive_integer // template void non_positive_integer_pimpl:: _pre () { str_.clear (); } template void non_positive_integer_pimpl:: _characters (const ro_string& s) { str_ += s; } template void non_positive_integer_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted () && value_ <= 0)) throw invalid_value (bits::non_positive_integer (), str); } template long long non_positive_integer_pimpl:: post_non_positive_integer () { return value_; } // positive_integer // template void positive_integer_pimpl:: _pre () { str_.clear (); } template void positive_integer_pimpl:: _characters (const ro_string& s) { str_ += s; } template void positive_integer_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted () && value_ > 0)) throw invalid_value (bits::positive_integer (), str); } template unsigned long long positive_integer_pimpl:: post_positive_integer () { return value_; } // non_negative_integer // template void non_negative_integer_pimpl:: _pre () { str_.clear (); } template void non_negative_integer_pimpl:: _characters (const ro_string& s) { str_ += s; } template void non_negative_integer_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::non_negative_integer (), str); } template unsigned long long non_negative_integer_pimpl:: post_non_negative_integer () { return value_; } // float // template void float_pimpl:: _pre () { str_.clear (); } template void float_pimpl:: _characters (const ro_string& s) { str_ += s; } template void float_pimpl:: _post () { ro_string str (str_); trim (str); if (str == bits::positive_inf ()) value_ = std::numeric_limits::infinity (); else if (str == bits::negative_inf ()) value_ = -std::numeric_limits::infinity (); else if (str == bits::nan ()) value_ = std::numeric_limits::quiet_NaN (); else { zc_istream is (str); is.imbue (std::locale::classic ()); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::float_ (), str); } } template float float_pimpl:: post_float () { return value_; } // double // template void double_pimpl:: _pre () { str_.clear (); } template void double_pimpl:: _characters (const ro_string& s) { str_ += s; } template void double_pimpl:: _post () { ro_string str (str_); trim (str); if (str == bits::positive_inf ()) value_ = std::numeric_limits::infinity (); else if (str == bits::negative_inf ()) value_ = -std::numeric_limits::infinity (); else if (str == bits::nan ()) value_ = std::numeric_limits::quiet_NaN (); else { zc_istream is (str); is.imbue (std::locale::classic ()); if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::double_ (), str); } } template double double_pimpl:: post_double () { return value_; } // decimal // template void decimal_pimpl:: _pre () { str_.clear (); } template void decimal_pimpl:: _characters (const ro_string& s) { str_ += s; } template void decimal_pimpl:: _post () { ro_string str (str_); trim (str); zc_istream is (str); is.imbue (std::locale::classic ()); //@@ TODO: now we accept scientific notations and INF/NaN. // if (!(is >> value_ && is.exhausted ())) throw invalid_value (bits::decimal (), str); } template double decimal_pimpl:: post_decimal () { return value_; } // string // template void string_pimpl:: _pre () { str_.clear (); } template void string_pimpl:: _characters (const ro_string& s) { str_ += s; } template std::basic_string string_pimpl:: post_string () { std::basic_string r; r.swap (str_); return r; } // normalized_string // template void normalized_string_pimpl:: _pre () { str_.clear (); } template void normalized_string_pimpl:: _characters (const ro_string& s) { str_ += s; } template std::basic_string normalized_string_pimpl:: post_normalized_string () { typedef typename std::basic_string::size_type size_type; size_type size (str_.size ()); for (size_type i (0); i < size; ++i) { C& c = str_[i]; if (c == C (0x0A) || c == C (0x0D) || c == C (0x09)) c = C (0x20); } std::basic_string r; r.swap (str_); return r; } // token // template void token_pimpl:: _pre () { str_.clear (); } template void token_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template std::basic_string token_pimpl:: post_token () { typedef typename std::basic_string::size_type size_type; size_type size (str_.size ()); size_type j (0); bool subs (false); for (size_type i (0); i < size; ++i) { C c = str_[i]; if (c == C (0x20) || c == C (0x0A) || c == C (0x0D) || c == C (0x09)) { subs = true; } else { if (subs) { subs = false; str_[j++] = C (0x20); } str_[j++] = c; } } str_.resize (j); std::basic_string r; r.swap (str_); return r; } // name // template void name_pimpl:: _pre () { str_.clear (); } template void name_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void name_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); // For now we are only checking the US-ASCII characters. // bool ok (size != 0); if (ok) { unsigned int c (static_cast (str_[0])); ok = c >= 0x80 || (bits::char_table::table[c] & bits::name_first_mask); if (ok) { for (size_type i (1); i < size; ++i) { c = static_cast (str_[i]); if (c < 0x80 && !(bits::char_table::table[c] & bits::name_mask)) { ok = false; break; } } } } if (!ok) throw invalid_value (bits::name (), tmp); str_.resize (size); } template std::basic_string name_pimpl:: post_name () { std::basic_string r; r.swap (str_); return r; } // nmtoken // template void nmtoken_pimpl:: _pre () { str_.clear (); } template void nmtoken_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void nmtoken_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); // For now we are only checking the US-ASCII characters. // bool ok (size != 0); if (ok) { for (size_type i (0); i < size; ++i) { unsigned int c (static_cast (str_[i])); if (c < 0x80 && !(bits::char_table::table[c] & bits::name_mask)) { ok = false; break; } } } if (!ok) throw invalid_value (bits::nmtoken (), tmp); str_.resize (size); } template std::basic_string nmtoken_pimpl:: post_nmtoken () { std::basic_string r; r.swap (str_); return r; } // nmtokens // template void nmtokens_pimpl:: _pre () { nmtokens_pskel::_pre (); seq_.clear (); } template void nmtokens_pimpl:: _post () { nmtokens_pskel::_post (); // Should have at least one element. // if (seq_.size () < 1) { ro_string tmp; throw invalid_value (bits::nmtokens (), tmp); } } template string_sequence nmtokens_pimpl:: post_nmtokens () { string_sequence r; r.swap (seq_); return r; } template void nmtokens_pimpl:: _xsd_parse_item (const ro_string& s) { parser_.pre (); parser_._pre (); parser_._characters (s); parser_._post (); seq_.push_back (parser_.post_nmtoken ()); } // ncname // namespace bits { template bool valid_ncname (const C* s, typename ro_string::size_type size) { typedef typename ro_string::size_type size_type; // For now we are only checking the US-ASCII characters. // bool ok (size != 0); if (ok) { unsigned int c (static_cast (s[0])); ok = c >= 0x80 || ((bits::char_table::table[c] & bits::name_first_mask) && c != C (':')); if (ok) { for (size_type i (1); i < size; ++i) { c = static_cast (s[i]); if (c < 0x80 && !(bits::char_table::table[c] & bits::ncname_mask)) { ok = false; break; } } } } return ok; } } template void ncname_pimpl:: _pre () { str_.clear (); } template void ncname_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void ncname_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); if (!bits::valid_ncname (tmp.data (), size)) throw invalid_value (bits::ncname (), tmp); str_.resize (size); } template std::basic_string ncname_pimpl:: post_ncname () { std::basic_string r; r.swap (str_); return r; } // id // template std::basic_string id_pimpl:: post_id () { return this->post_ncname (); } // idref // template std::basic_string idref_pimpl:: post_idref () { return this->post_ncname (); } // idrefs // template void idrefs_pimpl:: _pre () { idrefs_pskel::_pre (); seq_.clear (); } template void idrefs_pimpl:: _post () { idrefs_pskel::_post (); // Should have at least one element. // if (seq_.size () < 1) { ro_string tmp; throw invalid_value (bits::idrefs (), tmp); } } template string_sequence idrefs_pimpl:: post_idrefs () { string_sequence r; r.swap (seq_); return r; } template void idrefs_pimpl:: _xsd_parse_item (const ro_string& s) { parser_.pre (); parser_._pre (); parser_._characters (s); parser_._post (); seq_.push_back (parser_.post_idref ()); } // language // template void language_pimpl:: _pre () { str_.clear (); } template void language_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void language_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); // language := ALPHA{1,8} *(-(ALPHA | DIGIT){1,8}) // bool ok (true); for (size_type tag (0), i (0); ; ++tag) { size_type n (0); for (; i < size && n < 8; ++n, ++i) { C c (tmp[i]); if (!((c >= C ('a') && c <= C ('z')) || (c >= C ('A') && c <= C ('Z')) || (tag != 0 && c >= C ('0') && c <= C ('9')))) break; } if (n == 0) { ok = false; break; } if (i == size) break; if (tmp[i++] != C ('-')) { ok = false; break; } } if (!ok) throw invalid_value (bits::language (), tmp); str_.resize (size); } template std::basic_string language_pimpl:: post_language () { std::basic_string r; r.swap (str_); return r; } // uri // template void uri_pimpl:: _pre () { str_.clear (); } template void uri_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template std::basic_string uri_pimpl:: post_uri () { // According to Datatypes 3.2.17 and RFC2396 pretty much anything // can be a URI and conforming processors do not need to figure // out and verify particular URI schemes. // ro_string tmp (str_); str_.resize (trim_right (tmp)); std::basic_string r; r.swap (str_); return r; } // qname // template void qname_pimpl:: _pre () { str_.clear (); } template void qname_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void qname_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); size_type pos (tmp.find (C (':'))); const C* s (tmp.data ()); if (pos != ro_string::npos) { if (!bits::valid_ncname (s, pos) || !bits::valid_ncname (s + pos + 1, size - pos - 1)) throw invalid_value (bits::qname (), tmp); prefix_.assign (s, pos); name_.assign (s + pos + 1, size - pos - 1); } else { if (!bits::valid_ncname (s, size)) throw invalid_value (bits::qname (), tmp); prefix_.clear (); str_.resize (size); name_.swap (str_); } } template qname qname_pimpl:: post_qname () { return prefix_.empty () ? qname (name_) : qname (prefix_, name_); } // base64_binary // template void base64_binary_pimpl:: _pre () { str_.clear (); } template 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) str_ += tmp; } else str_ += s; } namespace bits { template inline unsigned char base64_decode (C c) { unsigned char r (0xFF); if (c >= C('A') && c <= C ('Z')) r = static_cast (c - C ('A')); else if (c >= C('a') && c <= C ('z')) r = static_cast (c - C ('a') + 26); else if (c >= C('0') && c <= C ('9')) r = static_cast (c - C ('0') + 52); else if (c == C ('+')) r = 62; else if (c == C ('/')) r = 63; return r; } } template void base64_binary_pimpl:: _post () { typedef typename std::basic_string::size_type size_type; size_type size (str_.size ()); const C* src (str_.c_str ()); // Remove all whitespaces. // { size_type j (0); bool subs (false); for (size_type i (0); i < size; ++i) { C c = str_[i]; if (c == C (0x20) || c == C (0x0A) || c == C (0x0D) || c == C (0x09)) { subs = true; } else { if (subs) subs = false; str_[j++] = c; } } size = j; str_.resize (size); } // Our length should be a multiple of four. // if (size == 0 || size % 4 != 0) throw invalid_value (bits::base64_binary (), str_); size_type quad_count (size / 4); size_type capacity (quad_count * 3 + 1); buf_.reset (new buffer (capacity, capacity)); char* dst (buf_->data ()); size_type si (0), di (0); // Source and destination indexes. // Process all quads except the last one. // unsigned char b1, b2, b3, b4; for (size_type q (0); q < quad_count - 1; ++q) { b1 = bits::base64_decode (src[si++]); b2 = bits::base64_decode (src[si++]); b3 = bits::base64_decode (src[si++]); b4 = bits::base64_decode (src[si++]); if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF || b4 == 0xFF) throw invalid_value (bits::base64_binary (), str_); 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 = bits::base64_decode (src[si++]); b2 = bits::base64_decode (src[si++]); if (b1 == 0xFF || b2 == 0xFF) throw invalid_value (bits::base64_binary (), str_); C e3 (src[si++]); C e4 (src[si++]); if (e4 == C ('=')) { if (e3 == C ('=')) { // Two pads. Last 4 bits in b2 should be zero. // if ((b2 & 0x0F) != 0) throw invalid_value (bits::base64_binary (), str_); dst[di++] = (b1 << 2) | (b2 >> 4); } else { // One pad. Last 2 bits in b3 should be zero. // b3 = bits::base64_decode (e3); if (b3 == 0xFF || (b3 & 0x03) != 0) throw invalid_value (bits::base64_binary (), str_); dst[di++] = (b1 << 2) | (b2 >> 4); dst[di++] = (b2 << 4) | (b3 >> 2); } } else { // No pads. // b3 = bits::base64_decode (e3); b4 = bits::base64_decode (e4); if (b3 == 0xFF || b4 == 0xFF) throw invalid_value (bits::base64_binary (), str_); dst[di++] = (b1 << 2) | (b2 >> 4); dst[di++] = (b2 << 4) | (b3 >> 2); dst[di++] = (b3 << 6) | b4; } // Set the real size. // buf_->size (di); } template std::auto_ptr base64_binary_pimpl:: post_base64_binary () { return buf_; } // hex_binary // template void hex_binary_pimpl:: _pre () { str_.clear (); } template void hex_binary_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } namespace bits { template inline unsigned char hex_decode (C c) { unsigned char r (0xFF); if (c >= C('0') && c <= C ('9')) r = static_cast (c - C ('0')); else if (c >= C ('A') && c <= C ('F')) r = static_cast (10 + (c - C ('A'))); else if (c >= C ('a') && c <= C ('f')) r = static_cast (10 + (c - C ('a'))); return r; } } template void hex_binary_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); if (size % 2 != 0) throw invalid_value (bits::hex_binary (), tmp); buffer::size_t n (size / 2); buf_.reset (new buffer (n)); if (n != 0) { const C* src (tmp.data ()); char* dst (buf_->data ()); buffer::size_t i (0); for (; i < n; ++i) { unsigned char h (bits::hex_decode (src[2 * i])); unsigned char l (bits::hex_decode (src[2 * i + 1])); if (h == 0xFF || l == 0xFF) break; dst[i] = (h << 4) | l; } if (i != n) throw invalid_value (bits::hex_binary (), tmp); } } template std::auto_ptr hex_binary_pimpl:: post_hex_binary () { return buf_; } // time_zone // namespace bits { // Datatypes 3.2.7.3. Return false if time zone is invalid. // template bool parse_tz (const C* s, typename std::basic_string::size_type n, short& h, short& m) { // time_zone := Z|(+|-)HH:MM // if (n == 0) { return false; } else if (s[0] == 'Z') { if (n != 1) return false; h = 0; m = 0; } else { if (n != 6 || (s[0] != '-' && s[0] != '+') || s[3] != ':') return false; // Parse hours. // char d1 = s[1]; char d2 = s[2]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') return false; h = 10 * (d1 - '0') + (d2 - '0'); if (h > 14) return false; // Parse minutes. // d1 = s[4]; d2 = s[5]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') return false; m = 10 * (d1 - '0') + (d2 - '0'); if (m > 59 || (h == 14 && m != 0)) return false; if (s[0] == '-') { h = -h; m = -m; } } return true; } } // gday // template void gday_pimpl:: _pre () { str_.clear (); } template void gday_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void gday_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // gday := ---DD[Z|(+|-)HH:MM] // if (size < 5 || s[0] != C ('-') || s[1] != C ('-') || s[2] != C ('-')) throw invalid_value (bits::gday (), tmp); C d1 (s[3]), d2 (s[4]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::gday (), tmp); day_ = 10 * (d1 - '0') + (d2 - '0'); if (day_ < 1 || day_ > 31) throw invalid_value (bits::gday (), tmp); if (size > 5) { if (!bits::parse_tz (s + 5, size - 5, zh_, zm_)) throw invalid_value (bits::gday (), tmp); z_ = true; } else z_ = false; } template gday gday_pimpl:: post_gday () { return z_ ? gday (day_, zh_, zm_) : gday (day_); } // gmonth // template void gmonth_pimpl:: _pre () { str_.clear (); } template void gmonth_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void gmonth_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // gmonth := --MM[Z|(+|-)HH:MM] // if (size < 4 || s[0] != C ('-') || s[1] != C ('-')) throw invalid_value (bits::gmonth (), tmp); C d1 (s[2]), d2 (s[3]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::gmonth (), tmp); month_ = 10 * (d1 - '0') + (d2 - '0'); if (month_ < 1 || month_ > 12) throw invalid_value (bits::gmonth (), tmp); if (size > 4) { if (!bits::parse_tz (s + 4, size - 4, zh_, zm_)) throw invalid_value (bits::gmonth (), tmp); z_ = true; } else z_ = false; } template gmonth gmonth_pimpl:: post_gmonth () { return z_ ? gmonth (month_, zh_, zm_) : gmonth (month_); } // gyear // template void gyear_pimpl:: _pre () { str_.clear (); } template void gyear_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void gyear_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // gyear := [-]CCYY[N]*[Z|(+|-)HH:MM] // if (size < 4 || (s[0] == C ('-') && size < 5)) throw invalid_value (bits::gyear (), tmp); // Find the end of the year token. // size_type pos (s[0] == C ('-') ? 5 : 4); for (; pos < size; ++pos) { C c (s[pos]); if (c == C ('Z') || c == C ('+') || c == C ('-')) break; } ro_string year_fragment (s, pos); zc_istream is (year_fragment); if (!(is >> year_ && is.exhausted () && year_ != 0)) throw invalid_value (bits::gyear (), tmp); if (pos < size) { if (!bits::parse_tz (s + pos, size - pos, zh_, zm_)) throw invalid_value (bits::gyear (), tmp); z_ = true; } else z_ = false; } template gyear gyear_pimpl:: post_gyear () { return z_ ? gyear (year_, zh_, zm_) : gyear (year_); } // gmonth_day // template void gmonth_day_pimpl:: _pre () { str_.clear (); } template void gmonth_day_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void gmonth_day_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // gmonth_day := --MM-DD[Z|(+|-)HH:MM] // if (size < 7 || s[0] != C ('-') || s[1] != C ('-') || s[4] != C ('-')) throw invalid_value (bits::gmonth_day (), tmp); // month // C d1 (s[2]), d2 (s[3]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::gmonth_day (), tmp); month_ = 10 * (d1 - '0') + (d2 - '0'); if (month_ < 1 || month_ > 12) throw invalid_value (bits::gmonth_day (), tmp); // day // d1 = s[5]; d2 = s[6]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::gmonth_day (), tmp); day_ = 10 * (d1 - '0') + (d2 - '0'); if (day_ < 1 || day_ > 31) throw invalid_value (bits::gmonth_day (), tmp); // zone // if (size > 7) { if (!bits::parse_tz (s + 7, size - 7, zh_, zm_)) throw invalid_value (bits::gmonth_day (), tmp); z_ = true; } else z_ = false; } template gmonth_day gmonth_day_pimpl:: post_gmonth_day () { return z_ ? gmonth_day (month_, day_, zh_, zm_) : gmonth_day (month_, day_); } // gyear_month // template void gyear_month_pimpl:: _pre () { str_.clear (); } template void gyear_month_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void gyear_month_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // gyear_month := [-]CCYY[N]*-MM[Z|(+|-)HH:MM] // if (size < 7 || (s[0] == C ('-') && size < 8)) throw invalid_value (bits::gyear_month (), tmp); // Find the end of the year token. // size_type pos (tmp.find (C ('-'), s[0] == C ('-') ? 5 : 4)); if (pos == ro_string::npos || (size - pos - 1) < 2) throw invalid_value (bits::gyear_month (), tmp); ro_string year_fragment (s, pos); zc_istream yis (year_fragment); if (!(yis >> year_ && yis.exhausted () && year_ != 0)) throw invalid_value (bits::gyear_month (), tmp); // month // C d1 (s[pos + 1]), d2 (s[pos + 2]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::gyear_month (), tmp); month_ = 10 * (d1 - '0') + (d2 - '0'); if (month_ < 1 || month_ > 12) throw invalid_value (bits::gyear_month (), tmp); // zone // pos += 3; if (pos < size) { if (!bits::parse_tz (s + pos, size - pos, zh_, zm_)) throw invalid_value (bits::gyear_month (), tmp); z_ = true; } else z_ = false; } template gyear_month gyear_month_pimpl:: post_gyear_month () { return z_ ? gyear_month (year_, month_, zh_, zm_) : gyear_month (year_, month_); } // date // template void date_pimpl:: _pre () { str_.clear (); } template void date_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void date_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // date := [-]CCYY[N]*-MM-DD[Z|(+|-)HH:MM] // if (size < 10 || (s[0] == C ('-') && size < 11)) throw invalid_value (bits::date (), tmp); // Find the end of the year token. // size_type pos (tmp.find (C ('-'), s[0] == C ('-') ? 5 : 4)); if (pos == ro_string::npos || (size - pos - 1) < 5 || s[pos + 3] != C ('-')) throw invalid_value (bits::date (), tmp); ro_string year_fragment (s, pos); zc_istream yis (year_fragment); if (!(yis >> year_ && yis.exhausted () && year_ != 0)) throw invalid_value (bits::date (), tmp); // month // C d1 (s[pos + 1]), d2 (s[pos + 2]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date (), tmp); month_ = 10 * (d1 - '0') + (d2 - '0'); if (month_ < 1 || month_ > 12) throw invalid_value (bits::date (), tmp); // day // d1 = s[pos + 4]; d2 = s[pos + 5]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date (), tmp); day_ = 10 * (d1 - '0') + (d2 - '0'); if (day_ < 1 || day_ > 31) throw invalid_value (bits::date (), tmp); // zone // pos += 6; if (pos < size) { if (!bits::parse_tz (s + pos, size - pos, zh_, zm_)) throw invalid_value (bits::date (), tmp); z_ = true; } else z_ = false; } template date date_pimpl:: post_date () { return z_ ? date (year_, month_, day_, zh_, zm_) : date (year_, month_, day_); } // time // template void time_pimpl:: _pre () { str_.clear (); } template void time_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void time_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // time := HH:MM:SS[.S+][Z|(+|-)HH:MM] // if (size < 8 || s[2] != C (':') || s[5] != C (':')) throw invalid_value (bits::time (), tmp); // hours // C d1 (s[0]), d2 (s[1]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::time (), tmp); hours_ = 10 * (d1 - '0') + (d2 - '0'); if (hours_ > 24) throw invalid_value (bits::time (), tmp); // minutes // d1 = s[3]; d2 = s[4]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::time (), tmp); minutes_ = 10 * (d1 - '0') + (d2 - '0'); if (minutes_ > 59) throw invalid_value (bits::time (), tmp); // Find the end of the seconds fragment. // size_type pos (8); for (; pos < size; ++pos) { C c (s[pos]); if (c == C ('Z') || c == C ('+') || c == C ('-')) break; } // At least one digit should follow the fraction point. // if ((pos - 6) == 3) throw invalid_value (bits::time (), tmp); ro_string seconds_fragment (s + 6, pos - 6); zc_istream sis (seconds_fragment); if (!(sis >> seconds_ && sis.exhausted () && seconds_ < 60.0)) throw invalid_value (bits::time (), tmp); if (hours_ == 24 && (minutes_ != 0 || seconds_ != 0.0)) throw invalid_value (bits::time (), tmp); // zone // if (pos < size) { if (!bits::parse_tz (s + pos, size - pos, zh_, zm_)) throw invalid_value (bits::time (), tmp); z_ = true; } else z_ = false; } template time time_pimpl:: post_time () { return z_ ? time (hours_, minutes_, seconds_, zh_, zm_) : time (hours_, minutes_, seconds_); } // date_time // template void date_time_pimpl:: _pre () { str_.clear (); } template void date_time_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } template void date_time_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); const C* s (tmp.data ()); // date_time := [-]CCYY[N]*-MM-DDTHH:MM:SS[.S+][Z|(+|-)HH:MM] // if (size < 19 || (s[0] == C ('-') && size < 20)) throw invalid_value (bits::date_time (), tmp); // Find the end of the year token. // size_type pos (tmp.find (C ('-'), s[0] == C ('-') ? 5 : 4)); if (pos == ro_string::npos || (size - pos - 1) < 14 || s[pos + 3] != C ('-') || s[pos + 6] != C ('T') || s[pos + 9] != C (':') || s[pos + 12] != C (':')) throw invalid_value (bits::date_time (), tmp); // year // ro_string year_fragment (s, pos); zc_istream yis (year_fragment); if (!(yis >> year_ && yis.exhausted () && year_ != 0)) throw invalid_value (bits::date_time (), tmp); // month // C d1 (s[pos + 1]), d2 (s[pos + 2]); if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date_time (), tmp); month_ = 10 * (d1 - '0') + (d2 - '0'); if (month_ < 1 || month_ > 12) throw invalid_value (bits::date_time (), tmp); // day // d1 = s[pos + 4]; d2 = s[pos + 5]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date_time (), tmp); day_ = 10 * (d1 - '0') + (d2 - '0'); if (day_ < 1 || day_ > 31) throw invalid_value (bits::date_time (), tmp); pos += 7; // Point to the first H. // hours // d1 = s[pos]; d2 = s[pos + 1]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date_time (), tmp); hours_ = 10 * (d1 - '0') + (d2 - '0'); if (hours_ > 24) throw invalid_value (bits::date_time (), tmp); // minutes // d1 = s[pos + 3]; d2 = s[pos + 4]; if (d1 < '0' || d1 > '9' || d2 < '0' || d2 > '9') throw invalid_value (bits::date_time (), tmp); minutes_ = 10 * (d1 - '0') + (d2 - '0'); if (minutes_ > 59) throw invalid_value (bits::date_time (), tmp); // Find the end of the seconds fragment. // pos += 6; // Point to the first S. size_type sec_end (pos + 2); for (; sec_end < size; ++sec_end) { C c (s[sec_end]); if (c == C ('Z') || c == C ('+') || c == C ('-')) break; } // At least one digit should should follow the fraction point. // if ((sec_end - pos) == 3) throw invalid_value (bits::date_time (), tmp); ro_string seconds_fragment (s + pos, sec_end - pos); zc_istream sis (seconds_fragment); if (!(sis >> seconds_ && sis.exhausted () && seconds_ < 60.0)) throw invalid_value (bits::date_time (), tmp); if (hours_ == 24 && (minutes_ != 0 || seconds_ != 0.0)) throw invalid_value (bits::date_time (), tmp); // zone // if (sec_end < size) { if (!bits::parse_tz (s + sec_end, size - sec_end, zh_, zm_)) throw invalid_value (bits::date_time (), tmp); z_ = true; } else z_ = false; } template date_time date_time_pimpl:: post_date_time () { return z_ ? date_time (year_, month_, day_, hours_, minutes_, seconds_, zh_, zm_) : date_time (year_, month_, day_, hours_, minutes_, seconds_); } // duration // template void duration_pimpl:: _pre () { str_.clear (); } template void duration_pimpl:: _characters (const ro_string& s) { if (str_.size () == 0) { ro_string tmp (s.data (), s.size ()); if (trim_left (tmp) != 0) str_ += tmp; } else str_ += s; } namespace bits { template inline typename ro_string::size_type duration_delim (const C* s, typename ro_string::size_type pos, typename ro_string::size_type size) { const C* p (s + pos); for (; p < (s + size); ++p) { if (*p == C ('Y') || *p == C ('D') || *p == C ('M') || *p == C ('H') || *p == C ('M') || *p == C ('S') || *p == C ('T')) break; } return p - s; } } template void duration_pimpl:: _post () { typedef typename ro_string::size_type size_type; ro_string tmp (str_); size_type size (trim_right (tmp)); negative_ = false; years_ = 0; months_ = 0; days_ = 0; hours_ = 0; minutes_ = 0; seconds_ = 0.0; // duration := [-]P[nY][nM][nD][TnHnMn[.n+]S] // const C* s (tmp.data ()); if (size < 3 || (s[0] == C ('-') && size < 4)) throw invalid_value (bits::duration (), tmp); size_type pos (0); if (s[0] == C ('-')) { negative_ = true; pos++; } if (s[pos++] != C ('P')) throw invalid_value (bits::duration (), tmp); size_type del (bits::duration_delim (s, pos, size)); // Duration should contain at least one component. // if (del == size) throw invalid_value (bits::duration (), tmp); if (s[del] == C ('Y')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> years_ && is.exhausted ())) throw invalid_value (bits::duration (), tmp); pos = del + 1; del = bits::duration_delim (s, pos, size); } if (del != size && s[del] == C ('M')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> months_ && is.exhausted ())) throw invalid_value (bits::duration (), tmp); pos = del + 1; del = bits::duration_delim (s, pos, size); } if (del != size && s[del] == C ('D')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> days_ && is.exhausted ())) throw invalid_value (bits::duration (), tmp); pos = del + 1; del = bits::duration_delim (s, pos, size); } if (del != size && s[del] == C ('T')) { pos = del + 1; del = bits::duration_delim (s, pos, size); // At least one time component should be present. // if (del == size) throw invalid_value (bits::duration (), tmp); if (s[del] == C ('H')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> hours_ && is.exhausted ())) throw invalid_value (bits::duration (), tmp); pos = del + 1; del = bits::duration_delim (s, pos, size); } if (del != size && s[del] == C ('M')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> minutes_ && is.exhausted ())) throw invalid_value (bits::duration (), tmp); pos = del + 1; del = bits::duration_delim (s, pos, size); } if (del != size && s[del] == C ('S')) { ro_string fragment (s + pos, del - pos); zc_istream is (fragment); if (!(is >> seconds_ && is.exhausted () && seconds_ >= 0.0)) throw invalid_value (bits::duration (), tmp); pos = del + 1; } } // Something did not match or appeared in the wrong order. // if (pos != size) throw invalid_value (bits::duration (), tmp); } template duration duration_pimpl:: post_duration () { return duration ( negative_, years_, months_, days_, hours_, minutes_, seconds_); } } } } }