bool FastXMLVisitor::VisitEnter (const XMLElement & element, const XMLAttribute* /* attr */) { const char* element_name = element.Name(); if (strcmp(element_name, "templates") == 0 ) { instruction_context context; context.ns_ = get_optional_attr(element, "templateNs", ""); context.dictionary_ = get_optional_attr(element, "dictionary", ""); context_stack_.push_back(context); return VisitEnterTemplates(element); } std::string name_attr = get_optional_attr(element, "name", ""); if (strcmp(element_name, "templateRef") == 0) { return VisitTemplateRef(element, name_attr, num_fields_.back()); } bool result = true; if (strcmp(element_name, "template") == 0 ) { save_context(element); result = VisitEnterTemplate(element, name_attr, num_fields_.back()); } else if (strcmp(element_name, "group") == 0 ) { save_context(element); result = VisitEnterGroup(element, name_attr, num_fields_.back()); } else if (strcmp(element_name, "sequence") == 0 ) { save_context(element); result = VisitEnterSequence(element, name_attr, num_fields_.back()); } else if (strcmp(element_name, "define") == 0) { return VisitEnterDefine(element, name_attr); } else { int bits; bool is_vector; if ((strncmp(element_name, "int", 3) == 0 && parse_bits(element_name+3, bits, is_vector) ) || (strncmp(element_name, "uInt", 4) == 0 && parse_bits(element_name+4, bits, is_vector) ) ) { // int8, int16 and uint8, uint16 are not standards, convert them to int32 and uint32 respectively if (is_vector) return VisitIntVector(element,bits, name_attr, num_fields_.back()); return VisitInteger(element,bits, name_attr, num_fields_.back()); } else if (strcmp(element_name, "decimal") == 0 ) { return VisitDecimal(element, name_attr, num_fields_.back()); } else if (strcmp(element_name, "string") == 0 ) { return VisitString(element, name_attr, num_fields_.back()); } else if (strcmp(element_name, "byteVector") == 0 ) { return VisitByteVector(element, name_attr, num_fields_.back()); } return true; } num_fields_.push_back(0); return result; }
void FastXMLVisitor::save_context(const XMLElement & element) { context_stack_.push_back(context_stack_.back()); instruction_context& context = context_stack_.back(); context.ns_ = get_optional_attr(element, "ns", context.ns_.c_str()); context.dictionary_ = get_optional_attr(element, "dictionary", context.dictionary_.c_str()); }
void field_op::parse_field_op(const XMLElement &field_op_element, arena_allocator &alloc) { typedef std::map<std::string, operator_enum_t> operator_map_t; static const operator_map_t operator_map = map_list_of("none", operator_none)( "constant", operator_constant)("delta", operator_delta)( "default", operator_default)("copy", operator_copy)( "increment", operator_increment)("tail", operator_tail); auto itr = operator_map.find(field_op_element.Name()); if (itr == operator_map.end()) { BOOST_THROW_EXCEPTION( fast_static_error("S1") << reason_info( std::string("Invalid field operator ") + field_op_element.Name())); } op_ = itr->second; const char *opContext_key = get_optional_attr( field_op_element, "key", context_ ? context_->key_ : nullptr); const char *opContext_dict = get_optional_attr(field_op_element, "dictionary", context_ ? context_->dictionary_ : nullptr); const char *opContext_ns = get_optional_attr( field_op_element, "ns", context_ ? context_->ns_ : nullptr); if (opContext_key || opContext_dict || opContext_ns) { auto new_context = new (alloc) op_context_t; new_context->key_ = string_dup(opContext_key, alloc); new_context->ns_ = string_dup(opContext_ns, alloc); new_context->dictionary_ = string_dup(opContext_dict, alloc); context_ = new_context; } }
field_op::field_op(const decimal_field_instruction *inst, const XMLElement *element, arena_allocator &alloc) : op_(inst->field_operator()), context_(inst->op_context()), initial_value_(inst->initial_value()), alloc_(&alloc) { if (element) { const XMLElement *field_op_element = find_field_op_element(*element); if (field_op_element) { parse_field_op(*field_op_element, alloc); const char *init_value_str = get_optional_attr(*field_op_element, "value", nullptr); if (init_value_str) { if (strcmp(element->Name(), "exponent") != 0) initial_value_.set(boost::lexical_cast<int64_t>(init_value_str)); else { short exp = 128; try { exp = boost::lexical_cast<short>(init_value_str); } catch (...) { } if (exp > 63 || exp < -63) { BOOST_THROW_EXCEPTION( fast_dynamic_error("D11") << reason_info(std::string("Invalid exponent initial value: ") + init_value_str)); } initial_value_ = decimal_value_storage(0, static_cast<uint16_t>(exp)).storage_; } } } } }
bool FastXMLVisitor::is_mandatory_constant(const XMLElement & element) { if (strcmp("mandatory", get_optional_attr(element, "presence", "mandatory")) == 0 ) { if (element.FirstChildElement("constant")) { return true; } } return false; }
bool FastXMLVisitor::VisitExit (const XMLElement & element) { const char* element_name = element.Name(); bool result = true; if (strcmp(element_name, "templates") == 0 ) { return VisitExitTemplates(element,num_fields_.back()); } std::string name_attr = get_optional_attr(element, "name", ""); if (strcmp(element_name, "templateRef") == 0) { num_fields_.back() += 1; } if (name_attr.empty()) return true; typedef bool (FastXMLVisitor::*VisitExitPtr)(const XMLElement &, const std::string&, std::size_t, std::size_t index); VisitExitPtr member_ptr; if (strcmp(element_name, "template") == 0 ) { member_ptr = &FastXMLVisitor::VisitExitTemplate; } else if (strcmp(element_name, "group") == 0 ) { member_ptr = &FastXMLVisitor::VisitExitGroup; } else if (strcmp(element_name, "sequence") == 0 ) { member_ptr = &FastXMLVisitor::VisitExitSequence; } else if (strcmp(element_name, "define") == 0) { return VisitExitDefine(element, name_attr); } else if (strncmp(element_name, "int", 3) == 0 || strncmp(element_name, "uInt", 4) == 0 || strcmp(element_name, "decimal") == 0 || strcmp(element_name, "string") == 0 || strcmp(element_name, "byteVector") == 0 ) { num_fields_.back() += 1; return true; } else { return true; } std::size_t numFields = num_fields_.back(); num_fields_.pop_back(); result = (this->*member_ptr)(element, name_attr, numFields, num_fields_.back()); num_fields_.back() += 1; context_stack_.pop_back(); return result; }
aggregate_view_info view_info_builder::build(const tinyxml2::XMLElement &element, const mfast::group_field_instruction *inst) { const char *name = get_optional_attr(element, "name", nullptr); if (name == nullptr) BOOST_THROW_EXCEPTION( fast_static_error("A view must has a name attribute")); this->visit(inst, nullptr); aggregate_view_info result; result.max_depth_ = 0; std::size_t sz = std::strlen(name) + 1; result.name_ = reinterpret_cast<const char *>( std::memcpy(new (alloc_) char[sz], name, sz)); // result.name_ = std::strcpy(new (alloc_) char[std::strlen(name) + 1], // name); std::deque<field_view_info> fields; const tinyxml2::XMLElement *child = element.FirstChildElement(); while (child != nullptr) { if (std::strcmp(child->Name(), "field") == 0) { const tinyxml2::XMLElement *grandchild = child->FirstChildElement(); while (grandchild != nullptr) { build_field_view(*grandchild, result.max_depth_, fields); grandchild = grandchild->NextSiblingElement(); } fields.back().prop &= ~field_view_info::CONTINUE_BIT; } child = child->NextSiblingElement(); } field_view_info terminator = {0, nullptr}; fields.push_back(terminator); auto data = new (alloc_) field_view_info[fields.size()]; std::copy(fields.begin(), fields.end(), data); result.data_ = mfast::array_view<const field_view_info>(data, fields.size()); result.instruction_ = inst; return result; }
void view_info_builder::build_field_view(const tinyxml2::XMLElement &element, unsigned &max_depth, std::deque<field_view_info> &fields) { std::string ref_name = get_optional_attr(element, "name", ""); if (ref_name.size()) { field_view_info result = {field_view_info::CONTINUE_BIT, nullptr}; std::vector<int> sequence_indeces; std::string ref_name_no_seq_index; // remove anything in [] and save the numbers in [] into a queue std::size_t pos = 0, new_pos; do { // find the first occurence of '[' new_pos = ref_name.find_first_of('[', pos); if (new_pos != std::string::npos) { ++new_pos; ref_name_no_seq_index += ref_name.substr(pos, (new_pos - pos)); pos = new_pos; new_pos = ref_name.find_first_of(']', pos); if (new_pos != std::string::npos) { try { sequence_indeces.push_back(boost::lexical_cast<unsigned>( ref_name.substr(pos, new_pos - pos))); pos = new_pos; } catch (boost::bad_lexical_cast &) { BOOST_THROW_EXCEPTION( fast_static_error("Invalid reference specification, the token " "inside [] must be a non-negative integer") << reference_name_info(ref_name)); } } } else { ref_name_no_seq_index += ref_name.substr(pos); } } while (new_pos != std::string::npos); // find the field index // std::cout << "finding " << ref_name_no_seq_index << "\n"; auto it = infos_.find(ref_name_no_seq_index); if (it == infos_.end()) { BOOST_THROW_EXCEPTION( fast_static_error( "Invalid reference specification, no such reference name exists") << reference_name_info(ref_name)); } const indeces_t &field_indeces = it->second; // replace every instance -2 with the indeces in [] typedef field_view_info::nest_index_t nest_index_t; nest_index_t *nest_indices = static_cast<nest_index_t *>( alloc_.allocate(sizeof(nest_index_t) * field_indeces.size() + 1)); unsigned i = 0, j = 0; for (i = 0; i < field_indeces.size(); ++i) { if (field_indeces[i] != -2) nest_indices[i] = field_indeces[i]; else { // -2 is used for specifying undefined sequence index if (j < sequence_indeces.size()) nest_indices[i] = sequence_indeces[j++]; else { BOOST_THROW_EXCEPTION( fast_static_error("Invalid reference specification, no such " "reference name exists") << reference_name_info(ref_name)); } } } // the nest_indeces must terminiated with a -1 nest_indices[i] = -1; result.nest_indices = nest_indices; max_depth = std::max<unsigned>(max_depth, static_cast<unsigned>(field_indeces.size())); result.prop += 1; if (fields.size()) { result.prop += std::mismatch(nest_indices, nest_indices + i, fields.back().nest_indices) .first - nest_indices; } fields.push_back(result); } }