Update path to xapp descriptor. Add schema parser library
[ric-app/mc.git] / schemaparser / schemaparser.cc
diff --git a/schemaparser/schemaparser.cc b/schemaparser/schemaparser.cc
new file mode 100644 (file)
index 0000000..5c5990e
--- /dev/null
@@ -0,0 +1,1169 @@
+/* ------------------------------------------------
+Copyright 2020 AT&T Intellectual Property
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ ------------------------------------------- */
+
+#include "schemaparser_impl.h"
+#include<string.h>
+
+namespace mc_schema{
+
+int type_size(int dt){
+       switch(dt){
+       case INT_TYPE:
+               return(sizeof(int));
+       case UINT_TYPE:
+       case USHORT_TYPE:
+       case BOOL_TYPE:
+       case IP_TYPE:
+               return(sizeof(unsigned int));
+       case ULLONG_TYPE:
+               return(sizeof(unsigned long long int));
+       case LLONG_TYPE:
+               return(sizeof(long long int));
+       case FLOAT_TYPE:
+               return(sizeof(double));
+       case IPV6_TYPE:
+               return(sizeof(mc_ipv6_str));
+       case TIMEVAL_TYPE:
+               return(sizeof(timeval));
+       case VSTR_TYPE:
+               return(sizeof(mc_string));      
+       default:
+               return(UNDEFINED_TYPE);
+       }
+       return(UNDEFINED_TYPE);
+};
+
+int assign_type_from_string(std::string st){
+//             convert to upper case
+       std::for_each(st.begin(), st.end(), [](char & c) {
+               c = ::toupper(c);
+       });
+
+       if(st == "BOOL"){
+               return BOOL_TYPE;
+       }
+       if(st == "USHORT"){
+               return USHORT_TYPE;
+       }
+       if(st == "UINT"){
+               return UINT_TYPE;
+       }
+       if(st == "INT"){
+               return INT_TYPE;
+       }
+       if(st == "ULLONG"){
+               return ULLONG_TYPE;
+       }
+       if(st == "LLONG"){
+               return LLONG_TYPE;
+       }
+       if(st == "FLOAT"){
+               return FLOAT_TYPE;
+       }
+       if(st == "STRING" || st == "V_STR"){
+               return VSTR_TYPE;               
+       }
+       if(st == "TIMEVAL"){
+               return TIMEVAL_TYPE;
+       }
+       if(st == "IP"){
+               return IP_TYPE;
+       }
+       if(st == "IPV6"){
+               return IPV6_TYPE;
+       }
+       return 0;
+}
+
+std::string type_to_string(int typ){
+       switch(typ){
+       case BOOL_TYPE:
+               return "BOOL";
+       case USHORT_TYPE:
+               return "USHORT";
+       case UINT_TYPE:
+               return "UINT";
+       case INT_TYPE:
+               return "INT";
+       case ULLONG_TYPE:
+               return  "ULLONG";
+       case LLONG_TYPE:
+               return "LLONG";
+       case FLOAT_TYPE:
+               return "FLOAT";
+       case VSTR_TYPE:
+               return "STRING";
+       case TIMEVAL_TYPE:
+               return "TIMEVAL";
+       case IP_TYPE:
+               return "IP";
+       case IPV6_TYPE:
+               return "IPV6_TYPE";
+       default:
+               return "UNDEFINED";
+       }
+       return "UNDEFINED";
+}
+       
+//             there is a casting function
+bool is_castable(int src, int dst){
+       switch(src){
+       case BOOL_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case USHORT_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case UINT_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case INT_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case ULLONG_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case LLONG_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case FLOAT_TYPE:
+               switch(dst){
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case VSTR_TYPE:
+               switch(dst){
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case TIMEVAL_TYPE:
+               switch(dst){
+               case TIMEVAL_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case IP_TYPE:
+               switch(dst){
+               case IP_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case IPV6_TYPE:
+               switch(dst){
+               case IPV6_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       default:
+               return false;
+       }
+       return false;
+}
+
+//             cast without loss of information
+bool is_compatible(int src, int dst){
+       switch(src){
+       case BOOL_TYPE:
+               switch(dst){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case USHORT_TYPE:
+               switch(dst){
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case UINT_TYPE:
+               switch(dst){
+               case UINT_TYPE:
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case INT_TYPE:
+               switch(dst){
+               case INT_TYPE:
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case ULLONG_TYPE:
+               switch(dst){
+               case ULLONG_TYPE:
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case LLONG_TYPE:
+               switch(dst){
+               case LLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case FLOAT_TYPE:
+               switch(dst){
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case VSTR_TYPE:
+               switch(dst){
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case TIMEVAL_TYPE:
+               switch(dst){
+               case TIMEVAL_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case IP_TYPE:
+               switch(dst){
+               case IP_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       case IPV6_TYPE:
+               switch(dst){
+               case IPV6_TYPE:
+               case VSTR_TYPE:
+                       return true;
+               default:
+                       return false;
+               }
+       default:
+               return false;
+       }
+       return false;
+}
+
+//////////////////////////////////////////////////////
+//             Field_entry
+
+std::string field_entry::load_from_json(mc_json::json_value *froot){
+       this->init();
+       for(mc_json::json_value *fparts=froot->first_child; fparts!=NULL; fparts=fparts->next_sibling){
+               if(strcmp(fparts->name, "name")==0){
+                       if(fparts->type!=mc_json::JSON_STRING){
+                               return "Error, the name of a field must be a string ("+std::to_string(fparts->type)+")";
+                       }
+                       name = fparts->string_value;
+               }
+               if(strcmp(fparts->name, "type")==0){
+                       if(fparts->type!=mc_json::JSON_STRING){
+                               return "Error, the type of a field must be a string ("+std::to_string(fparts->type)+")";
+                       }
+                       type = fparts->string_value;
+               }
+               if(strcmp(fparts->name, "pos")==0){
+                       if(fparts->type!=mc_json::JSON_STRING){
+                               return "Error, the pos of a field must be an int ("+std::to_string(fparts->type)+")";
+                       }
+                       pos = atoi(fparts->string_value);
+               }
+               if(strcmp(fparts->name, "is_ts")==0){
+                       if(fparts->type!=mc_json::JSON_BOOL){
+                               return "Error, the is_ts of a field must be a bool ("+std::to_string(fparts->type)+")";
+                       }
+                       is_ts = fparts->int_value;
+               }
+       }
+       return "";
+}
+
+       
+       
+
+
+int tuple_access_info::init(field_entry *fe){
+       field_name = fe->name;
+       pdt = assign_type_from_string(fe->type);
+       is_ts = fe->is_ts;
+       offset = 0;
+       return(pdt);
+};
+
+std::string tuple_access_info::to_string(){
+       std::string ret = field_name+": offset="+std::to_string(offset)+", type="+type_to_string(pdt);
+       if(is_ts){
+               ret+=", is_ts";
+       }
+       return ret;
+}
+
+//////////////////////////////////////////////////////////////////
+//             query_rep implementation
+/////////////////////////////////////////////////////////////////
+
+
+std::string _query_rep::init(const mc_json::json_value *strm){
+       min_tuple_size = 0;
+
+       if(strm->type != mc_json::JSON_OBJECT){
+               return "Error, json stream must be a dict ("+std::to_string(strm->type)+").";
+       }
+       this->name = strm->name;
+       for(mc_json::json_value *sparts=strm->first_child; sparts!=NULL; sparts=sparts->next_sibling){
+//keys
+               if(strcmp(sparts->name, "keys")==0){
+                       if(sparts->type != mc_json::JSON_ARRAY){
+                               return "Error, the keys in stream must be an array (" +std::to_string(sparts->type)+ ").";
+                               }
+                               for(mc_json::json_value *kparts=sparts->first_child; kparts!=NULL; kparts=kparts->next_sibling){
+                                       if(kparts->type != mc_json::JSON_STRING){
+                                               return "Error, the key entries in a stream must all be strings (" +std::to_string(kparts->type)+").";
+                                       }
+                                       keys.push_back(kparts->string_value);
+                               }
+                       }
+// fields
+               if(strcmp(sparts->name, "fields")==0){
+                       if(sparts->type != mc_json::JSON_ARRAY){
+                               return "Error, the fields in a stream must all be dict (" +std::to_string(sparts->type )+ ").";
+                       }
+                       for(mc_json::json_value *field=sparts->first_child; field!=NULL; field=field->next_sibling){
+                               if(field->type != mc_json::JSON_OBJECT){
+                                       return "Error, the field entries in a stream must all be dicts (" +std::to_string(field->type )+ ").";
+                               }
+                               field_entry fe;
+                               std::string err = fe.load_from_json(field);
+                               if(err!=""){
+                                       return "Error loading stream "+std::string(this->name)+": "+err;
+                               }
+                               tuple_access_info tai;
+                               int pdt = tai.init(&fe);
+                               if(pdt==UNDEFINED_TYPE){
+                                       err = "Error in field "+fe.name+" of stream "+this->name+", unknown type "+fe.type;
+                                       return err;
+                               }
+                               field_info.push_back(tai);
+                       }
+               }
+       }
+
+       return "";
+}
+
+
+int _query_rep::finalize(){
+       int f;
+       int curr_pos = 0;
+       int fld_undefined = 0;
+       for(f=0;f<field_info.size();++f){
+               field_info[f].offset = curr_pos;
+               int sz = type_size(field_info[f].pdt);
+               if(sz==0) fld_undefined = 1;
+               curr_pos += sz;
+       }
+       min_tuple_size = curr_pos;
+       if(fld_undefined) return(-1);
+       else return(0);
+}
+
+//             Return a text representation
+std::string _query_rep::to_string(){
+       std::string ret = name + ": keys=[";
+       for(int k=0;k<keys.size();++k){
+               if(k>0)
+                       ret+=",";
+               ret += keys[k];
+       }
+       ret += "], fields=\n";
+       for(int f=0;f<field_info.size();++f){
+               ret += field_info[f].to_string()+"\n";
+       }
+       ret+="\tmin_size="+std::to_string(min_tuple_size)+"\n";
+       return ret;
+}
+
+//             Number of fields
+int  _query_rep::get_num_fields(){
+       return field_info.size();
+}
+
+//             name of ith field (starting at zero)
+std::string _query_rep::get_field_name(int i){
+       return field_info[i].field_name;
+}
+
+//             lookup field index by name, -1 if not found
+int _query_rep::get_index_of_field(std::string name){
+       for(int i=0;i<field_info.size();++i){
+               if(field_info[i].field_name==name)
+                       return i;
+       }
+       return -1;
+}
+
+//             lookup field handle by name, offset is -1 if not found
+field_handle _query_rep::get_handle_of_field(std::string name){
+       field_handle ret;
+       ret.offset = -1;
+       for(int i=0;i<field_info.size();++i){
+               if(field_info[i].field_name==name){
+                       ret.offset = field_info[i].offset;
+                       ret.type = field_info[i].pdt;
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+
+//             data type of ith field.
+int _query_rep::get_type(int i){
+       if(i<0 || i>=field_info.size())
+               return UNDEFINED_TYPE;
+       return field_info[i].pdt;
+}
+
+std::string _query_rep::get_type_name(int i){
+       return type_to_string(this->get_type(i));
+}
+
+//             byte offset of ith field in a data block
+int _query_rep::get_offset(int i){
+       if(i<0 || i>field_info.size())
+               return 0;
+       return field_info[i].offset;
+}
+
+//             byte offset of ith field in a data block
+field_handle _query_rep::get_handle(int i){
+       field_handle ret;
+       ret.offset = -1;
+       if(i<0 || i>field_info.size())
+               return ret;
+       ret.offset = field_info[i].offset;
+       ret.type = field_info[i].pdt;
+       return ret;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////
+//     mc_schemas implementation
+
+//             n is a char buffer holding the json description of the stream schemas
+_mc_schemas::_mc_schemas(const char *n) : mc_schemas() {
+       this->init(n);
+}
+//             n is a string holding the json description of the stream schemas
+_mc_schemas::_mc_schemas(std::string s){
+       this->init(s.c_str());
+}
+
+void _mc_schemas::init(const char *n){
+       nib_str = strdup(n);
+
+       char *errorPos = 0;
+       char *errorDesc = 0;
+       int errorLine = 0;
+       mc_json::block_allocator allocator(1 << 10); // 1 KB per block
+       mc_json::json_value *jroot = mc_json::json_parse(nib_str, &errorPos, (const char**)&errorDesc, &errorLine, &allocator);
+
+       if(jroot->type != mc_json::JSON_OBJECT){
+               err =  "Error, root of the nib json must be a dict.";
+               return ; 
+       }
+
+       for(mc_json::json_value *stream=jroot->first_child; stream!=NULL; stream=stream->next_sibling){
+               if(stream->type != mc_json::JSON_OBJECT){
+                       err = "Error, the streams in the nib json must all be dict (" +std::to_string(stream->type )+ ").";
+                       return ;
+               }
+               std::string stream_name = stream->name;
+               _query_rep *qr = new _query_rep();
+               std::string stream_err = qr->init(stream);
+               if(stream_err == ""){
+                       qr->finalize();
+                       qreps[stream_name] = qr;
+               }else{
+                       qerrs[stream_name] = stream_err;
+                       delete qr;
+               }
+       }
+}
+
+//             true if there are any errors.
+bool _mc_schemas::has_errors(){
+       if(err!="")
+               return true;
+       if(qerrs.size()>0)
+               return true;
+       return false;
+}
+
+//             string with the error reports.  empty if there is no error.
+std::string _mc_schemas::get_errors(){
+       std::string ret = this->err;
+       for(auto mi=qerrs.begin(); mi!=qerrs.end(); ++mi){
+               if(err!="")
+                       err += "\n";
+               err += (*mi).first+": "+(*mi).second;
+       }
+       return err;
+}
+
+//             return the names of the parsed streams.
+std::vector<std::string> _mc_schemas::get_streams(){
+       std::vector<std::string> ret;
+       for(auto mi=qreps.begin(); mi!=qreps.end(); ++mi){
+               ret.push_back(mi->first);
+       }
+       return ret;
+}
+
+//             return the names of the unsucessfully parsed streams
+std::vector<std::string> _mc_schemas::get_error_streams(){
+       std::vector<std::string> ret;
+       for(auto mi=qerrs.begin(); mi!=qerrs.end(); ++mi){
+               ret.push_back(mi->first);
+       }
+       return ret;
+}
+
+//             true if some stream was parsed successful or not
+bool _mc_schemas::stream_found(std::string s){
+       if(qreps.count(s)+qerrs.count(s) > 0)
+               return true;
+       return false;
+}
+
+//             true if there is a stream with name s which parsed successfully
+bool _mc_schemas::stream_ok(std::string s){
+       return qreps.count(s) > 0;
+}
+
+//             return the error associated with a stream, if any.
+std::string _mc_schemas::get_stream_error(std::string s){
+       if(qerrs.count(s)>0)
+               return qerrs[s];
+       if(qreps.count(s)>0)
+               return "";
+       return "not_found";
+}
+
+//             Get the query representation of a successfully parsed stream
+query_rep *_mc_schemas::get_query_rep(std::string s){
+       if(qreps.count(s)>0)
+               return qreps[s];
+       return NULL;
+}
+
+//     Destructor
+_mc_schemas::~_mc_schemas(){
+       free(nib_str);
+       for(auto q=qreps.begin(); q!=qreps.end();++q){
+               delete q->second;
+       }
+}
+
+
+////////////
+//     mc_schemas factory
+mc_schemas *new_mc_schemas(std::string s){
+       return new _mc_schemas(s);
+}
+mc_schemas *new_mc_schemas(const char *s){
+       return new _mc_schemas(s);
+}
+
+
+////////////////////////////////////////////
+//                     Direct tuple access functions.
+
+unsigned int unpack_uint(void *data, int len, int offset, int *problem){
+       unsigned int retval;
+       if(offset+sizeof(unsigned int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(unsigned int));
+       return(retval);
+}
+unsigned int unpack_ushort(void *data, int len, int offset, int *problem){
+       unsigned int retval;
+       if(offset+sizeof(unsigned int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(unsigned int));
+       return(retval);
+}
+unsigned int unpack_bool(void *data, int len, int offset, int *problem){
+       unsigned int retval;
+       if(offset+sizeof(unsigned int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(unsigned int));
+       return(retval);
+}
+int unpack_int(void *data, int len, int offset, int *problem){
+       int retval;
+       if(offset+sizeof(int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(unsigned int));
+       return(retval);
+}
+unsigned long long int unpack_ullong(void *data, int len, int offset, int *problem){
+       unsigned long long int retval;
+       if(offset+sizeof(unsigned long long int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(unsigned long long int));
+       return(retval);
+}
+long long int unpack_llong(void *data, int len, int offset, int *problem){
+       long long int retval;
+       if(offset+sizeof(long long int) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(long long int));
+       return(retval);
+}
+double unpack_float(void *data, int len, int offset, int *problem){
+       double retval;
+       if(offset+sizeof(double) > len){
+               *problem = 1;
+               return(0);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(double));
+       return(retval);
+}
+timeval unpack_timeval(void *data, int len, int offset, int *problem){
+       timeval retval;
+       if(offset+sizeof(timeval) > len){
+               *problem = 1;
+               retval.tv_sec = 0;
+               retval.tv_usec = 0;
+               return(retval);
+       }
+       memcpy(&retval, ((char *)data)+offset, sizeof(timeval));
+       return(retval);
+}
+mc_string unpack_vstr(void *data,  int len, int offset, int *problem){
+       mc_string retval;
+       vstring32 unpack_s;
+
+       if(offset+sizeof( vstring32) > len){
+               *problem = 1;
+               return(retval);
+       }
+
+       memcpy(&unpack_s, ((char *)data)+offset, sizeof(vstring32));
+
+       retval.length = unpack_s.length;
+
+       if(unpack_s.offset + retval.length > len){
+               *problem = 1;
+               return(retval);
+       }
+       retval.data = (char *)data + unpack_s.offset;
+       return(retval);
+}
+
+struct mc_ipv6_str unpack_ipv6(void *data,  int len, int offset, int *problem){
+        struct mc_ipv6_str retval;
+        if(offset+sizeof(mc_ipv6_str) > len){
+               *problem = 1;
+               return(retval);
+        }
+        memcpy(&retval, ((char *)data)+offset, sizeof(mc_ipv6_str));
+        return(retval);
+}
+
+
+access_result get_field_by_index(query_rep *qr, int index,
+                       void * data, int len){
+       access_result retval;
+       retval.field_data_type = UNDEFINED_TYPE;
+       int problem = 0;
+
+       if(index >= qr->get_num_fields()){
+               return(retval);
+       }
+
+       switch(qr->get_type(index)){
+       case UINT_TYPE:
+               retval.r.ui = unpack_uint(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = UINT_TYPE;
+               break;
+       case IP_TYPE:
+               retval.r.ui = unpack_uint(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = IP_TYPE;
+               break;
+       case INT_TYPE:
+               retval.r.i = unpack_int(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = INT_TYPE;
+               break;
+       case ULLONG_TYPE:
+               retval.r.ul = unpack_ullong(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = ULLONG_TYPE;
+               break;
+       case LLONG_TYPE:
+               retval.r.l = unpack_llong(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = LLONG_TYPE;
+               break;
+       case USHORT_TYPE:
+               retval.r.ui = unpack_ushort(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = USHORT_TYPE;
+               break;
+       case FLOAT_TYPE:
+               retval.r.f = unpack_float(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = FLOAT_TYPE;
+               break;
+       case BOOL_TYPE:
+               retval.r.ui = unpack_bool(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = BOOL_TYPE;
+               break;
+       case VSTR_TYPE:
+               retval.r.vs = unpack_vstr(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = VSTR_TYPE;
+               break;
+       case TIMEVAL_TYPE:
+               retval.r.t = unpack_timeval(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = TIMEVAL_TYPE;
+               break;
+       case IPV6_TYPE:
+               retval.r.ip6 = unpack_ipv6(data,  len,
+                       qr->get_offset(index), &problem);
+               if(!problem) retval.field_data_type = IPV6_TYPE;
+               break;
+       case UNDEFINED_TYPE:
+               break;
+       }
+       return(retval);
+}
+
+access_result get_field_by_handle(field_handle f, void * data, int len){
+       access_result retval;
+       retval.field_data_type = UNDEFINED_TYPE;
+       int problem = 0;
+
+       switch(f.type){
+       case UINT_TYPE:
+               retval.r.ui = unpack_uint(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = UINT_TYPE;
+               break;
+       case IP_TYPE:
+               retval.r.ui = unpack_uint(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = IP_TYPE;
+               break;
+       case INT_TYPE:
+               retval.r.i = unpack_int(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = INT_TYPE;
+               break;
+       case ULLONG_TYPE:
+               retval.r.ul = unpack_ullong(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = ULLONG_TYPE;
+               break;
+       case LLONG_TYPE:
+               retval.r.l = unpack_llong(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = LLONG_TYPE;
+               break;
+       case USHORT_TYPE:
+               retval.r.ui = unpack_ushort(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = USHORT_TYPE;
+               break;
+       case FLOAT_TYPE:
+               retval.r.f = unpack_float(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = FLOAT_TYPE;
+               break;
+       case BOOL_TYPE:
+               retval.r.ui = unpack_bool(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = BOOL_TYPE;
+               break;
+       case VSTR_TYPE:
+               retval.r.vs = unpack_vstr(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = VSTR_TYPE;
+               break;
+       case TIMEVAL_TYPE:
+               retval.r.t = unpack_timeval(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = TIMEVAL_TYPE;
+               break;
+       case IPV6_TYPE:
+               retval.r.ip6 = unpack_ipv6(data,  len, f.offset, &problem);
+               if(!problem) retval.field_data_type = IPV6_TYPE;
+               break;
+       case UNDEFINED_TYPE:
+               break;
+       }
+       return(retval);
+}
+
+int get_field_int(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return (int)(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return (int)(a.r.i);
+               case LLONG_TYPE:
+                       return (int)(a.r.l);
+               case ULLONG_TYPE:
+                       return (int)(a.r.ul);
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+               case IPV6_TYPE:
+                       return 0;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+
+unsigned int get_field_uint(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return (unsigned int)(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return (unsigned int)(a.r.i);
+               case LLONG_TYPE:
+                       return (unsigned int)(a.r.l);
+               case ULLONG_TYPE:
+                       return (unsigned int)(a.r.ul);
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+               case IPV6_TYPE:
+                       return 0;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+
+long long int get_field_llong(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return (long long int)(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return (long long int)(a.r.i);
+               case LLONG_TYPE:
+                       return (long long int)(a.r.l);
+               case ULLONG_TYPE:
+                       return (long long int)(a.r.ul);
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+               case IPV6_TYPE:
+                       return 0;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+                       
+unsigned long long int get_field_ullong(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return (unsigned long long int)(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return (unsigned long long int)(a.r.i);
+               case LLONG_TYPE:
+                       return (unsigned long long int)(a.r.l);
+               case ULLONG_TYPE:
+                       return (unsigned long long int)(a.r.ul);
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+               case IPV6_TYPE:
+                       return 0;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+
+double get_field_float(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return (unsigned long long int)(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return (unsigned long long int)(a.r.i);
+               case LLONG_TYPE:
+                       return (unsigned long long int)(a.r.l);
+               case ULLONG_TYPE:
+                       return (unsigned long long int)(a.r.ul);
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+               case IPV6_TYPE:
+                       return 0;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+timeval get_field_timeval(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case IP_TYPE:
+               case LLONG_TYPE:
+               case ULLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case IPV6_TYPE:
+                       a.r.t.tv_sec = 0;
+                       a.r.t.tv_usec = 0;
+                       return a.r.t;
+               case TIMEVAL_TYPE:
+                       return a.r.t;
+               default:
+                       a.r.t.tv_sec = 0;
+                       a.r.t.tv_usec = 0;
+                       return a.r.t;
+       }
+       a.r.t.tv_sec = 0;
+       a.r.t.tv_usec = 0;
+       return a.r.t;
+}
+
+mc_ipv6_str get_field_ipv6(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+               case INT_TYPE:
+               case IP_TYPE:
+               case LLONG_TYPE:
+               case ULLONG_TYPE:
+               case FLOAT_TYPE:
+               case VSTR_TYPE:
+               case TIMEVAL_TYPE:
+                       a.r.ip6.v[0] = 0;
+                       a.r.ip6.v[1] = 0;
+                       a.r.ip6.v[2] = 0;
+                       a.r.ip6.v[3] = 0;
+                       return a.r.ip6;
+               case IPV6_TYPE:
+                       return a.r.ip6;
+               default:
+                       a.r.ip6.v[0] = 0;
+                       a.r.ip6.v[1] = 0;
+                       a.r.ip6.v[2] = 0;
+                       a.r.ip6.v[3] = 0;
+                       return a.r.ip6;
+       }
+       a.r.ip6.v[0] = 0;
+       a.r.ip6.v[1] = 0;
+       a.r.ip6.v[2] = 0;
+       a.r.ip6.v[3] = 0;
+       return a.r.ip6;
+}
+       
+
+std::string get_field_string(field_handle f, void * data, int len){
+       access_result a = get_field_by_handle(f, data, len);
+       switch(f.type){
+               case BOOL_TYPE:
+               case USHORT_TYPE:
+               case UINT_TYPE:
+                       return std::to_string(a.r.ui);
+               case INT_TYPE:
+               case IP_TYPE:
+                       return std::to_string(a.r.i);
+               case LLONG_TYPE:
+                       return std::to_string(a.r.l);
+               case ULLONG_TYPE:
+                       return std::to_string(a.r.ul);
+               case FLOAT_TYPE:
+                       return std::to_string(a.r.f);
+               case VSTR_TYPE:{
+                       std::string rets(a.r.vs.data, a.r.vs.length);
+                       return rets;
+               }
+               case TIMEVAL_TYPE:{
+                       double tv = a.r.t.tv_sec + ((double)a.r.t.tv_usec)/1000000.0;
+                       return std::to_string(tv);
+               }
+               case IPV6_TYPE:{
+                       char buf[100];
+                       sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+                               a.r.ip6.v[0] >> 16, (a.r.ip6.v[0]) & 0xffff,
+                               a.r.ip6.v[1] >> 16, (a.r.ip6.v[1]) & 0xffff,
+                               a.r.ip6.v[2] >> 16, (a.r.ip6.v[2]) & 0xffff,
+                               a.r.ip6.v[3] >> 16, (a.r.ip6.v[3]) & 0xffff
+                       );
+                       return buf;
+               }
+               default:
+                       return "";
+       }
+       return "";
+}
+               
+}
+
+