From d6a308bdbcbba33e04dc835c4d596077fe4f298d Mon Sep 17 00:00:00 2001 From: zawz Date: Tue, 3 Mar 2020 09:33:05 +0100 Subject: [PATCH] filedat: rework format improvement code cleaning --- include/filedat.hpp | 37 +- md/filedat.md | 27 +- src/filedat.cpp | 802 +++++++++++++++++++++++--------------------- 3 files changed, 453 insertions(+), 413 deletions(-) diff --git a/include/filedat.hpp b/include/filedat.hpp index 6df103a..16d4757 100644 --- a/include/filedat.hpp +++ b/include/filedat.hpp @@ -105,7 +105,7 @@ namespace ztd //! @brief Constructor with initial value chunkdat(const char* in); //! @brief Constructor with initial value - chunkdat(std::string const& in); + chunkdat(std::string const& in, int offset=0, filedat* parent=nullptr); //! @brief Constructor with initial value chunkdat(const char* in, const int in_size, int offset=0, filedat* parent=nullptr); //! @brief Constructor with copy @@ -127,6 +127,13 @@ namespace ztd inline int offset() const { return m_offset; } + //! @brief Set data + /*! + @param in String data + @param offset Used for debugging + @param data Used for debugging + */ + void set(std::string const& in, int offset=0, filedat* parent=nullptr); //! @brief Set data /*! @param in C string data @@ -134,14 +141,7 @@ namespace ztd @param offset Used for debugging @param parent Used for debugging */ - void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr); - //! @brief Set data - /*! - @param in String data - @param offset Used for debugging - @param data Used for debugging - */ - inline void set(std::string const& in, int offset=0, filedat* parent=nullptr) { this->set(in.c_str(), in.size(), offset, parent); } + inline void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr) { this->set(std::string(in, in_size), offset, parent);} //! @brief Copy chunk data void set(chunkdat const& in); @@ -337,6 +337,8 @@ namespace ztd @param aligner String used to align subchunks */ std::string strval(std::string const& aligner="\t") const; + //! @brief Alias for strval() + inline std::string str(std::string const& aligner="\t") const { return this->strval(aligner); } //! @brief Get reference to chunk data inline chunkdat& data() const { return *m_dataChunk; } @@ -362,25 +364,13 @@ namespace ztd //! @see chunkdat::operator[](const unsigned int a) const inline chunkdat& operator[](const unsigned int index) const { return m_dataChunk->subChunkRef(index); } - //! @brief add data and return *this - //! @see chunkdat::operator+=(std::pair const& a) - inline filedat& operator+=(std::pair const& a) { *m_dataChunk += a; return *this; } - //! @brief add data and return *this - //! @see chunkdat::operator+=(std::vector> const& a) - inline filedat& operator+=(std::vector> const& a) { *m_dataChunk += a; return *this; } - //! @brief add data and return *this - //! @see chunkdat::operator+=(chunkdat const& a) - inline filedat& operator+=(chunkdat const& a) { *m_dataChunk += a; return *this; } - //! @brief add() and return *this - //! @see chunkdat::operator+=(std::vector const& a) - inline filedat& operator+=(std::vector const& a) { *m_dataChunk += a; return *this; } - //! @brief set_data() and return *this //! @see chunkdat::operator+=(std::vector const& a) inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; } //! @brief Is a read char static bool isRead(char in); + static std::string removeComments(std::string str); inline operator chunkdat() const { return *m_dataChunk; } // inline operator std::string() const { if(m_dataChunk!=nullptr) return m_dataChunk->strval(); else return ""; } @@ -388,6 +378,7 @@ namespace ztd private: //functions void generateChunk(); + //attributes std::string m_filePath; std::string m_data; @@ -428,7 +419,7 @@ namespace ztd If origin is known, displays location and discriminating line\n If origin is unknown, displays whole data up to discriminating line */ - void printFormatException(format_error& exc); + inline void printFormatException(format_error& exc) {printErrorIndex(exc.data(), exc.where(), exc.what(), exc.origin());} } diff --git a/md/filedat.md b/md/filedat.md index 3c23ac5..1151a47 100644 --- a/md/filedat.md +++ b/md/filedat.md @@ -5,37 +5,42 @@ ZFD is composed of infinitely concatenable "chunks". There a three types of chun - List chunk : between brackets [] - String value -Formatting is ignored, all spaces will be ignored unless they are part of a value. -Comments can be written with //, ends at end of line +All spaces will be ignored unless they are part of a value. +Comments can be written with // or #, ends at end of line. +Only supports ASCII -ZFD treats everything as a string, there is no number or boolean types +Everything is a string, there are no number or boolean types ### Map Chunk -A map chunk consists of pairs of keys and values. Format is as follows: +A map chunk consists of pairs of keys and values. +Key separators are \n and ; +Format is as follows: ``` { - //no concatenator: value ends at end of line. /!\ Comments on these lines will be part of the value key1=value - //concatenators: value ends at end of concatenation key2 = " value " key3 = ' value ' - key4=[ //list ] - key5={ //chunk } + // brace and brackets have to be the first valid chars for list and maps + key4 = [ //list ] + key5 = { //map } + // multiple values in a single line + key6=foo; key7=bar } ``` ### List Chunk -A list chunk consists of a linear list of values separated by commas. Format is as follows: +A list chunk consists of a linear list of values separated by commas. +Value separators are , and ; +Format is as follows: ``` [ - //comments cannot be written between a value and the separating comma value, " value ", ' value ', { //chunk }, - [ //list ] + [ //list ], ] ``` diff --git a/src/filedat.cpp b/src/filedat.cpp index e58378b..794c882 100644 --- a/src/filedat.cpp +++ b/src/filedat.cpp @@ -1,5 +1,7 @@ #include "filedat.hpp" +#include + // Function code bool ztd::filedat::isRead(char in) { @@ -14,6 +16,17 @@ static std::string repeatString(const std::string& str, const unsigned int n) return ret; } +static std::string escape(std::string str, const char c) +{ + size_t pos = str.find(c); + while(pos != std::string::npos) + { + str.insert(pos, "\\"); + pos += 2; + pos = str.find(c, pos); + } + return str; +} void ztd::printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin) { @@ -55,11 +68,52 @@ void ztd::printErrorIndex(const char* in, const int index, const std::string& me } } -void ztd::printFormatException(ztd::format_error& exc) +std::string ztd::filedat::removeComments(std::string str) { - ztd::printErrorIndex(exc.data(), exc.where(), exc.what(), exc.origin()); -} + uint32_t i=0; + while(i < str.size()) + { + if( str[i] == '"') // double quotes + { + uint32_t j=i; + i++; + while(i < str.size() && str[i]!='"') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '"') //escaped quote + i++; //ignore backslash + i++; // add char and increment + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Double quote doesn't close", "", str, j); + i++; + } + else if( str[i] == '\'') // single quotes + { + uint32_t j=i; + i++; + while(i < str.size() && str[i]!='\'') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '\'') //escaped quote + i++; //ignore backslash + + i++; // add char + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Single quote doesn't close", "", str, j); + i++; + } + else if(str[i] == '#' || (i+1 < str.size() && str.substr(i,2) == "//")) // comment + { + uint32_t j=i; + i = str.find('\n', i); + str.erase(j,i-j); + i=j; + } + i++; + } + return str; +} ztd::filedat::filedat() { @@ -75,7 +129,7 @@ ztd::filedat::filedat(std::string const& in) ztd::filedat::~filedat() { if(m_dataChunk!=nullptr) - delete m_dataChunk; + delete m_dataChunk; } void ztd::filedat::clear() @@ -92,18 +146,18 @@ bool ztd::filedat::readTest() const { std::ifstream stream(m_filePath); if(!stream) - return false; + return false; else - return true; + return true; } void ztd::filedat::import_file(const std::string& path) { if(path != "") - m_filePath=path; + m_filePath=path; std::ifstream st(m_filePath); if(!st) - throw std::runtime_error("Cannot read file '" + m_filePath + '\''); + throw std::runtime_error("Cannot read file '" + m_filePath + '\''); this->clear(); std::string line; @@ -141,11 +195,11 @@ bool ztd::filedat::export_file(std::string const& path, std::string const& align { std::ofstream stream; if(path=="") - stream.open(m_filePath); + stream.open(m_filePath); else - stream.open(path); + stream.open(path); if(!stream) - return false; + return false; stream << this->strval(aligner); return true; } @@ -153,9 +207,9 @@ bool ztd::filedat::export_file(std::string const& path, std::string const& align std::string ztd::filedat::strval(std::string const& aligner) const { if(m_dataChunk == nullptr) - return ""; + return ""; else - return m_dataChunk->strval(0, aligner); + return m_dataChunk->strval(0, aligner); } void ztd::filedat::generateChunk() @@ -163,436 +217,402 @@ void ztd::filedat::generateChunk() try { if(m_dataChunk != nullptr) - delete m_dataChunk; - m_dataChunk = new ztd::chunkdat(m_data.c_str(), m_data.size(), 0, this); + delete m_dataChunk; + m_data = this->removeComments(m_data); + m_dataChunk = new ztd::chunkdat(m_data, 0, nullptr); } catch(ztd::format_error& e) { + m_dataChunk = nullptr; throw ztd::format_error(e.what(), m_filePath, m_data, e.where()); } } -static std::string _getname(const char* in, const int in_size, int* start, int* val_size, int* end) +std::pair _skip(const std::string& str) { - int i=0; + size_t i=0; - *start = in_size; //default no value - *end = in_size; //default end - *val_size=0; //default no value - - while(i= in_size) //ends without value - return ""; - - int j=i; //name start - while(i= in_size) //no = - throw ztd::format_error("Tag has no value", "", std::string(in, in_size), j); - - if(i == j) //nothing preceding = - throw ztd::format_error("Value has no tag", "", std::string(in, in_size), i); - - int k=i-1; //name end - while( !ztd::filedat::isRead(in[k]) ) - k--; - std::string name=std::string(in+j, k-j+1); - - i++; - while(i < in_size && !ztd::filedat::isRead(in[i])) - i++; - if(i >= in_size) //no value - { - *start=i; - *val_size=0; - *end=i; - return name; - } - if(in[i] == '\"') //"" val - { - *start=i; //value starts - j=1; //size - while(i+j < in_size && in[i+j]!='\"') - { - if(in[i+j]=='\\') - j++; - j++; - } - if(i+j >= in_size) // no closing " - throw ztd::format_error("Double quote does not close", "", std::string(in, in_size), i-1); - j++; - *val_size=j; - *end=i+j; - return name; - } - if(in[i] == '\'') //"" val - { - *start=i; //value starts - j=1; //size - while(i+j < in_size && in[i+j]!='\'') - { - if(in[i+j]=='\\') - j++; - j++; - } - if(i+j >= in_size) // no closing ' - throw ztd::format_error("Single quote does not close", "", std::string(in, in_size), i-1); - j++; - *val_size=j; - *end=i+j; - return name; - } - if(in[i] == '{') - { - *start=i; - j=1; - int counter=0; - while( i+j < in_size && !( counter == 0 && in[i+j]=='}') ) - { - if(i+j+1= in_size) //reached end without closing - throw ztd::format_error("Brace does not close", "", std::string(in, in_size), i); - j++; - *val_size=j; - *end=i+j; - return name; - } - if(in[i] == '[') - { - *start=i; - j=1; - int counter=0; - while( i+j < in_size && !( counter == 0 && in[i+j]==']') ) - { - if(i+j+1= in_size) //reached end without closing - throw ztd::format_error("Bracket does not close", "", std::string(in, in_size), i); - j++; - *val_size=j; - *end=i+j; - return name; - } - { // no encapsulation: go to end of line - *start=i; //value starts - j=0; //size - while(i+j < in_size && in[i+j]!='\n') - { - if(in[i]+j=='\\') - j++; - j++; - } - while( !ztd::filedat::isRead(in[i+j]) ) - j--; - *val_size=j+1; - *end=i+j+1; - return name; - } - - return name; -} - -static std::string _getlist(const char* in, const int in_size, int* start, int* end) -{ - int i=0; std::string ret; - - while(i _getstrval(const std::string& str, const char delim=0, const char altdelim=0) +{ + std::string val; + + //skip to start of val + size_t i = _skip(str).second; + int st = i; + bool delim_found=false; + + // no value + if(i >= str.size()) + return std::make_tuple("","",0,0,false); + + while(i < str.size()) + { + if( str[i] == '"') // double quotes + { + uint32_t j=i; + i++; + while(i < str.size() && str[i]!='"') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '"') //escaped quote + i++; //ignore backslash + + val.push_back(str[i++]); // add char and increment + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Double quote doesn't close", "", str, j); + i++; + } + else if( str[i] == '\'') // single quotes + { + uint32_t j=i; + i++; + while(i < str.size() && str[i]!='\'') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '\'') //escaped quote + i++; //ignore backslash + + val += str[i++]; // add char + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Single quote doesn't close", "", str, j); + i++; + } + if(str[i] == '{') // {} map + { + uint32_t counter=0; + uint32_t j=i; + val += str[i++]; // add the bracket to the value + while(i < str.size() && !(counter == 0 && str[i] == '}') ) + { + if(str[i] == '}') + counter--; + else if(str[i] == '{') + counter++; + else if( str[i] == '"') // double quotes + { + uint32_t k=i; + val += str[i++]; + while(i < str.size() && str[i]!='"') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '"') //escaped quote + val += str[i++]; + val += str[i++]; + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Double quote does not close", "", str, k); + } + else if( str[i] == '\'') // single quotes + { + uint32_t k=i; + val += str[i++]; + while(i < str.size() && str[i]!='\'') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '\'') //escaped quote + val += str[i++]; + val += str[i++]; + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Single quote does not close", "", str, k); + } + val += str[i++]; + } + + if(i >= str.size()) //didn't close + throw ztd::format_error("Brace does not close", "", str, j); + + val += str[i++]; // add brace + } + else if(str[i] == '[') // [] list + { + uint32_t counter=0; + uint32_t j=i; + val += str[i++]; // add the bracket to the value + while(i < str.size() && !(counter == 0 && str[i] == ']') ) + { + if(str[i] == '[') + counter--; + else if(str[i] == ']') + counter++; + else if( str[i] == '"') // double quotes + { + uint32_t k=i; + val += str[i++]; + while(i < str.size() && str[i]!='"') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '"') //escaped quote + val += str[i++]; + val += str[i++]; + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Double quote does not close", "", str, k); + } + else if( str[i] == '\'') // single quotes + { + uint32_t k=i; + val += str[i++]; + while(i < str.size() && str[i]!='\'') // until end of quote + { + if(i+1 < str.size() && str[i] == '\\' && str[i+1] == '\'') //escaped quote + val += str[i++]; + val += str[i++]; + } + if(i >= str.size()) // quote didn't end + throw ztd::format_error("Single quote does not close", "", str, k); + } + val += str[i++]; + } + + if(i >= str.size()) //didn't close + throw ztd::format_error("Brace does not close", "", str, j); + + val += str[i++]; // add bracket + } + else if(!ztd::filedat::isRead(str[i])) // non read char + { + std::string tval=""; + if(delim == 0) // delim=0: stop at non read + break; + while(!ztd::filedat::isRead(str[i]) && !(str[i] == delim || str[i] == altdelim) ) // until read or delim + tval += str[i++]; + if(str[i] == delim || str[i] == altdelim) // delim: stop + { + i++; + break; + } + val += tval; + } + else // read char + { + if(str[i] == delim || str[i] == altdelim) // delim: stop without adding delim + { + i++; + break; + } + + val.push_back(str[i++]); //add char and increment + } + } + std::string ret; + if(i < str.size()) + { + ret = str.substr(i); + delim_found=true; + } + else + { + while( val.size() > 0 && !ztd::filedat::isRead(val[val.size()-1]) ) + val.pop_back(); + ret = ""; + delim_found=false; + i=str.size(); + } + return std::make_tuple(val, ret, i, st, delim_found); // return +} + +// key, value, rest, start of rest, start of value, start of key +static std::tuple _getkeyval(const std::string& in) +{ + std::string key, value, rstr; + std::tuple tup; + int dpos=-1, rpos=-1, valstart=-1, keystart=-1; + bool eq_found=false; + + try // get key + { + tup=_getstrval(in, '='); + key=std::get<0>(tup); + rstr=std::get<1>(tup); + dpos=std::get<2>(tup); + keystart=std::get<3>(tup); + eq_found=std::get<4>(tup); + } + catch(ztd::format_error& e) + { + ztd::format_error(e.what(), e.origin(), in, e.where()); + throw e; + } + if(key.size() > 0 && key[0] == ';') // ignore ; : new value + { + key.erase(key.begin()); + return std::make_tuple("", "", key+value+rstr, keystart+1, -1, -1); + } + if(key == "" && _skip(rstr).first != "") // key is empty + throw ztd::format_error("Value has no Key", "", in, in.find(dpos) ); + if(key != "" && !eq_found) // no delim + throw ztd::format_error("Key '"+key+"' has no value", "", in, keystart+key.size()); + + try // get value + { + tup=_getstrval(rstr, ';', '\n'); + value=std::get<0>(tup); + rstr=std::get<1>(tup); + rpos=std::get<2>(tup); + valstart = std::get<3>(tup); + } + catch(ztd::format_error& e) + { + ztd::format_error(e.what(), e.origin(), in, dpos+1+e.where()); + throw e; } - *start=i; - if(i >= in_size) //ends without value - { - *end = in_size; - return ""; - } - if(in[i] == ',') //value is empty - { - *end=i+1; - return ""; - } + int rr=-1; + if(rpos >= 0) + rr = dpos+rpos; + else + rr = in.size(); - int j=0; - if(in[i] == '\"') //"" val - { - j=1; //size - while(i+j < in_size && in[i+j]!='\"') - { - if(in[i+j]=='\\') - j++; - j++; - } - if(i+j >= in_size) // no closing " - throw ztd::format_error("Double quote does not close", "", std::string(in, in_size), i-1); - j++; - ret = std::string(in+i, j); - *end=i+j; - } - else if(in[i] == '\'') //"" val - { - j=1; //size - while(i+j < in_size && in[i+j]!='\'') - { - if(in[i+j]=='\\') - j++; - j++; - } - if(i+j >= in_size) // no closing ' - throw ztd::format_error("Single quote does not close", "", std::string(in, in_size), i-1); - j++; - ret = std::string(in+i, j); - *end=i+j; - } - else if(in[i] == '{') - { - j=1; - int counter=0; - while( i+j < in_size && !( counter == 0 && in[i+j]=='}') ) - { - if(i+j+1= in_size) //reached end without closing - throw ztd::format_error("Brace does not close", "", std::string(in, in_size), i); - j++; - ret = std::string(in+i, j); - *end=i+j; - } - else if(in[i] == '[') - { - j=1; - int counter=0; - while( i+j < in_size && !( counter == 0 && in[i+j]==']') ) - { - if(i+j+1= in_size) //reached end without closing - throw ztd::format_error("Bracket does not close", "", std::string(in, in_size), i); - j++; - ret = std::string(in+i, j); - *end=i+j; - } - else // no encapsulation: go to next , - { - j=0; //size - while(i+j < in_size && in[i+j]!=',') - { - if(in[i+j]=='\\') - j++; - j++; - } - if(i+j < in_size) - { - while( !ztd::filedat::isRead(in[i+j]) ) - j--; - } - ret = std::string(in+i,j); - *end=i+j; - } - - i = *end; - while(i < in_size && !ztd::filedat::isRead(in[i])) - i++; - if( i>= in_size ) //last char - { - *end=i; - return ret; - } - else if(in[i] ==',') //comma as expected - { - *end=i+1; - return ret; - } - else //Unexpected char - throw ztd::format_error("Expecting comma", "", std::string(in, in_size), i); + return std::make_tuple(key, value, rstr, rr, valstart, keystart); } -void ztd::chunkdat::set(const char* in, const int in_size, int offset, filedat* parent) +void ztd::chunkdat::set(const std::string& in, int offset, ztd::filedat* parent) { - this->clear(); //reset everything + this->clear(); this->m_parent=parent; this->m_offset=offset; - int i=0; + // isolate value + auto tup = _getstrval(in); // any exception here is caught upwards + std::string str = std::get<0>(tup); + std::string rest = std::get<1>(tup); + int i = std::get<2>(tup); + int j = std::get<3>(tup); - while(i= in_size) //empty: make an empty strval + if(str == "") //empty: make an empty strval { ztd::chunk_string* cv = new ztd::chunk_string(); m_achunk=cv; cv->val = ""; return; } - else if( in[i] == '{') + if ( str[0] == '{') // map { - i++; - int val_end=in_size-1; - while(!ztd::filedat::isRead(in[val_end])) //skip unread char - val_end--; - if(in[val_end] != '}') - throw ztd::format_error("Expecting closing brace", "", std::string(in, in_size), val_end+1); + auto p = _skip(rest); + if( p.first != "") //rest is not empty + throw ztd::format_error("Unexpected char", "", in, i+p.second); + str.erase(str.begin()); // remove first char '{' + i = j+1; + str.pop_back(); // remove last char '}' + + // create chunk ztd::chunk_map* tch = new ztd::chunk_map(); m_achunk = tch; - std::string name; - std::string val; - while(i < val_end) + if(_skip(str).first == "") // empty map + return; + + do { - int start=0; - int _size=0; - int end=0; - - while(!ztd::filedat::isRead(in[i])) - i++; - - std::string newstr=std::string(in+i, val_end-i); - try + int keystart, valstart; + std::string key, value; + p = _skip(str); + if(p.first[0] == '=') + throw ztd::format_error("Value has no key", "", in, i+p.second); + try // get one value { - name = _getname(newstr.c_str(), newstr.size(), &start, &_size, &end); - val = newstr.substr(start, _size); + auto tup2 = _getkeyval(str); + key=std::get<0>(tup2); // key + value=std::get<1>(tup2); // value + str=std::get<2>(tup2); // rest + valstart = i + std::get<4>(tup2); // start of value + keystart = i + std::get<5>(tup2); // start of key + i+=std::get<3>(tup2); // add start of rest } catch(ztd::format_error& e) { - throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where()+i); + throw ztd::format_error(e.what(), e.origin(), in, i+e.where()); } - - if( name == "" ) //no more values - break; - - try + if(key != "") // good value { - ztd::chunkdat* chk = new ztd::chunkdat(val.c_str(),val.size(), offset + start+i, m_parent); - if(!tch->values.insert( std::make_pair(name, chk ) ).second) + try // insert value { - delete chk; - throw ztd::format_error("Key '" + name + "' already present", "", std::string(in, in_size), 0 - start ); + ztd::chunkdat* chk = new ztd::chunkdat(value, offset + valstart, m_parent); + if(!tch->values.insert( std::make_pair(key, chk ) ).second) // failed to insert + { + delete chk; + throw ztd::format_error("Key '" + key + "' already present", "", in, keystart ); + } + } + catch(ztd::format_error& e) + { + throw ztd::format_error(e.what(), "", in, e.where() + valstart ); } } - catch(ztd::format_error& e) - { - throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where() + start + i ); - } - - i += end; } - - return; - + while(str != ""); } - else if( in[i] == '[') + else if ( str[0] == '[') // map { - i++; - int val_end=in_size-1; - while(!ztd::filedat::isRead(in[val_end])) //skip unread char - val_end--; - if(in[val_end] != ']') - throw ztd::format_error("Expecting closing bracket", "", std::string(in, in_size), val_end+1); + auto p = _skip(rest); + if( p.first != "") //rest is not empty + throw ztd::format_error("Unexpected char", "", in, i+p.second); + str.erase(str.begin()); // remove first char '[' + i = j+1; + str.pop_back(); // remove last char ']' + + // create chunk ztd::chunk_list* tch = new ztd::chunk_list(); m_achunk = tch; - int end=0,start=0; - while( i < val_end ) + if(_skip(str).first == "") // empty list + return; + + do { - std::string val; - std::string newstr=std::string(in+i, val_end-i); - try + int valstart; + std::string value; + try // get one value { - val = _getlist(newstr.c_str(), newstr.size(), &start, &end); + auto tup2 = _getstrval(str, ',', ';'); + value=std::get<0>(tup2); // value + str=std::get<1>(tup2); // rest + valstart = i + std::get<3>(tup2); // start of value + i+=std::get<2>(tup2); // add start of rest } catch(ztd::format_error& e) { - throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where()+i); + throw ztd::format_error(e.what(), e.origin(), in, e.where() + i); } - try { - tch->list.push_back(new ztd::chunkdat(val.c_str(),val.size(), offset + start+i, m_parent) ); + tch->list.push_back(new ztd::chunkdat(value, offset + valstart, m_parent) ); } catch(ztd::format_error& e) { - throw ztd::format_error(e.what(), "", std::string(in, in_size), e.where() + start + i ); + throw ztd::format_error(e.what(), e.origin(), in, e.where() + valstart ); } - - i+=end; } - - return; - + while(str != ""); } - else // string value + else { - int val_end=in_size; - val_end--; - while(!ztd::filedat::isRead(in[val_end])) //skip unread char - val_end--; - - ztd::chunk_string* tch = new ztd::chunk_string(); - m_achunk = tch; - - tch->val = std::string(in+i,val_end-i+1); - - return; - + ztd::chunk_string* cv = new ztd::chunk_string(); + m_achunk=cv; + cv->val = in; } } @@ -776,6 +796,8 @@ std::string ztd::chunkdat::strval(unsigned int alignment, std::string const& ali else if(this->type()==ztd::chunk_abstract::map) { ztd::chunk_map* cp = dynamic_cast(m_achunk); + if(cp->values.size() <= 0) + return "{}"; std::string ret="{\n"; for(auto it : cp->values) { @@ -783,7 +805,16 @@ std::string ztd::chunkdat::strval(unsigned int alignment, std::string const& ali ret += it.first; ret += " = "; if(it.second!=nullptr) - ret += it.second->strval(alignment+1, aligner); + { + if(it.second->type() == ztd::chunk_abstract::string) + { + ret += "\"" + escape(it.second->strval(), '"') + "\""; + } + else + { + ret += it.second->strval(alignment+1, aligner); + } + } ret += '\n'; } ret += repeatString(aligner, alignment); @@ -793,12 +824,23 @@ std::string ztd::chunkdat::strval(unsigned int alignment, std::string const& ali else if(this->type()==ztd::chunk_abstract::list) { ztd::chunk_list* lp = dynamic_cast(m_achunk); + if(lp->list.size() <= 0) + return "[]"; std::string ret="[\n"; for(auto it : lp->list) { ret += repeatString(aligner, alignment+1); if(it!=nullptr) - ret += it->strval(alignment+1, aligner); + { + if(it->type() == ztd::chunk_abstract::string) + { + ret += '"' + escape(it->strval(), '"') + '"'; + } + else + { + ret += it->strval(alignment+1, aligner); + } + } ret += ",\n"; } ret.erase(ret.end()-2); @@ -909,21 +951,23 @@ ztd::chunkdat& ztd::chunkdat::subChunkRef(const unsigned int a) const ztd::chunkdat::chunkdat() { m_achunk=nullptr; + m_parent=nullptr; + m_offset=0; } ztd::chunkdat::chunkdat(const char* in) { m_achunk=nullptr; set(in, strlen(in), 0, nullptr); } -ztd::chunkdat::chunkdat(std::string const& in) +ztd::chunkdat::chunkdat(std::string const& in, int offset, filedat* parent) { m_achunk=nullptr; - set(in, 0, nullptr); + set(in, offset, parent); } -ztd::chunkdat::chunkdat(const char* in, const int in_size, int offset, filedat* data) +ztd::chunkdat::chunkdat(const char* in, const int in_size, int offset, filedat* parent) { m_achunk=nullptr; - set(in, in_size, offset, data); + set(in, in_size, offset, parent); } ztd::chunkdat::chunkdat(chunkdat const& in) {