]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/binaryparser.cpp
More efficient way of loading binary files
[libs/datafile.git] / source / binaryparser.cpp
index 098a5fd4f96c936cad7aae6bfba31b0627c357ef..051133f79a32cecb540c021f87b6930f5e168566 100644 (file)
@@ -2,9 +2,11 @@
 #include <sys/param.h>
 #include <msp/core/maputils.h>
 #include <msp/strings/format.h>
+#include "argumentstore.h"
 #include "binaryparser.h"
 #include "binfloat.h"
 #include "input.h"
+#include "loaderaction.h"
 
 using namespace std;
 
@@ -21,31 +23,48 @@ public:
        virtual ~bad_definition() throw() { }
 };
 
+class nesting_error: public logic_error
+{
+public:
+       nesting_error(const std::string &w):
+               logic_error(w)
+       { }
+
+       virtual ~nesting_error() throw() { }
+};
+
 
 BinaryParser::BinaryParser(Input &i, const string &s):
        ParserMode(i, s),
-       float_precision(32)
+       float_precision(32),
+       cur_info(0)
 {
-       dict[-1] = StatementKey("__kwd", "iss");
-       dict[-2] = StatementKey("__str", "is");
-       dict[-3] = StatementKey("__flt", "i");
+       dict[-1] = StatementInfo("__kwd", "iss");
+       dict[-2] = StatementInfo("__str", "is");
+       dict[-3] = StatementInfo("__flt", "i");
 }
 
 Statement BinaryParser::parse()
 {
-       int id = parse_int();
-       if(!in)
-               return Statement();
+       const StatementKey *key;
+       if(cur_info)
+               key = &cur_info->key;
+       else
+       {
+               int id = parse_int();
+               if(!in)
+                       return Statement();
 
-       const StatementKey &key = get_item(dict, id);
+               key = &get_item(dict, id).key;
+       }
 
        Statement result;
-       result.keyword = key.keyword;
+       result.keyword = key->keyword;
        result.source = src;
 
-       for(unsigned j=0; j<key.signature.size(); ++j)
+       for(unsigned j=0; j<key->signature.size(); ++j)
        {
-               switch(key.signature[j])
+               switch(key->signature[j])
                {
                case IntType::signature:
                        result.args.push_back(parse_int());
@@ -65,11 +84,15 @@ Statement BinaryParser::parse()
                }
        }
 
+       if(!sub_remaining.empty())
+               --sub_remaining.back();
+
        unsigned nsub = parse_int();
        for(unsigned j = 0; j<nsub; ++j)
                result.sub.push_back(parse());
 
        result.valid = true;
+       cur_info = 0;
 
        return result;
 }
@@ -89,7 +112,7 @@ void BinaryParser::process_control_statement(const Statement &st)
                                if(!valid_signatures[j])
                                        throw bad_definition("__kwd");
 
-               dict[id] = StatementKey(kw, args);
+               dict[id] = StatementInfo(kw, args);
        }
        else if(st.keyword=="__str")
        {
@@ -103,6 +126,73 @@ void BinaryParser::process_control_statement(const Statement &st)
                float_precision = st.args[0].get<unsigned>();
 }
 
+const StatementKey *BinaryParser::peek(unsigned level)
+{
+       if(level>sub_remaining.size())
+               throw nesting_error("bad level");
+       while(level<sub_remaining.size())
+       {
+               // Discard any substatements that haven't been parsed yet
+               for(unsigned i=sub_remaining.back(); i-->0; )
+                       parse();
+               sub_remaining.pop_back();
+               cur_info = 0;
+       }
+
+       if(!sub_remaining.empty() && sub_remaining.back()==0)
+       {
+               // No more substatements on this level
+               cur_info = 0;
+               return 0;
+       }
+
+       if(cur_info)
+               return &cur_info->key;
+
+       int id = parse_int();
+       if(!in)
+               return 0;
+
+       cur_info = &get_item(dict, id);
+       return &cur_info->key;
+}
+
+bool BinaryParser::parse_and_load(unsigned level, Loader &ldr, const LoaderAction &act)
+{
+       if(!cur_info && !peek(level))
+               return false;
+
+       ArgumentStore args(*cur_info);
+       for(unsigned i=0; i<cur_info->key.signature.size(); ++i)
+               switch(cur_info->key.signature[i])
+               {
+               case IntType::signature:
+                       args.set(i, parse_int());
+                       break;
+               case FloatType::signature:
+                       args.set(i, parse_float());
+                       break;
+               case BoolType::signature:
+                       args.set(i, parse_bool());
+                       break;
+               case StringType::signature:
+                       args.set(i, parse_string());
+                       break;
+               case SymbolType::signature:
+                       args.set(i, parse_symbol());
+                       break;
+               }
+
+       if(!sub_remaining.empty())
+               --sub_remaining.back();
+       sub_remaining.push_back(parse_int());
+       cur_info = 0;
+
+       act.execute(ldr, args);
+
+       return true;
+}
+
 IntType::Store BinaryParser::parse_int()
 {
        IntType::Store result = 0;