filedat: rework

format improvement
code cleaning
This commit is contained in:
zawz 2020-03-03 09:33:05 +01:00
parent 8d01a18f3a
commit d6a308bdbc
3 changed files with 453 additions and 413 deletions

View file

@ -105,7 +105,7 @@ namespace ztd
//! @brief Constructor with initial value //! @brief Constructor with initial value
chunkdat(const char* in); chunkdat(const char* in);
//! @brief Constructor with initial value //! @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 //! @brief Constructor with initial value
chunkdat(const char* in, const int in_size, int offset=0, filedat* parent=nullptr); chunkdat(const char* in, const int in_size, int offset=0, filedat* parent=nullptr);
//! @brief Constructor with copy //! @brief Constructor with copy
@ -127,6 +127,13 @@ namespace ztd
inline int offset() const { return m_offset; } 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 //! @brief Set data
/*! /*!
@param in C string data @param in C string data
@ -134,14 +141,7 @@ namespace ztd
@param offset Used for debugging @param offset Used for debugging
@param parent Used for debugging @param parent Used for debugging
*/ */
void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr); 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 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); }
//! @brief Copy chunk data //! @brief Copy chunk data
void set(chunkdat const& in); void set(chunkdat const& in);
@ -337,6 +337,8 @@ namespace ztd
@param aligner String used to align subchunks @param aligner String used to align subchunks
*/ */
std::string strval(std::string const& aligner="\t") const; 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 //! @brief Get reference to chunk data
inline chunkdat& data() const { return *m_dataChunk; } inline chunkdat& data() const { return *m_dataChunk; }
@ -362,25 +364,13 @@ namespace ztd
//! @see chunkdat::operator[](const unsigned int a) const //! @see chunkdat::operator[](const unsigned int a) const
inline chunkdat& operator[](const unsigned int index) const { return m_dataChunk->subChunkRef(index); } inline chunkdat& operator[](const unsigned int index) const { return m_dataChunk->subChunkRef(index); }
//! @brief add data and return *this
//! @see chunkdat::operator+=(std::pair<std::string, chunkdat> const& a)
inline filedat& operator+=(std::pair<std::string, chunkdat> const& a) { *m_dataChunk += a; return *this; }
//! @brief add data and return *this
//! @see chunkdat::operator+=(std::vector<std::pair<std::string, chunkdat>> const& a)
inline filedat& operator+=(std::vector<std::pair<std::string, chunkdat>> 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<chunkdat> const& a)
inline filedat& operator+=(std::vector<chunkdat> const& a) { *m_dataChunk += a; return *this; }
//! @brief set_data() and return *this //! @brief set_data() and return *this
//! @see chunkdat::operator+=(std::vector<chunkdat> const& a) //! @see chunkdat::operator+=(std::vector<chunkdat> const& a)
inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; } inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; }
//! @brief Is a read char //! @brief Is a read char
static bool isRead(char in); static bool isRead(char in);
static std::string removeComments(std::string str);
inline operator chunkdat() const { return *m_dataChunk; } inline operator chunkdat() const { return *m_dataChunk; }
// inline operator std::string() const { if(m_dataChunk!=nullptr) return m_dataChunk->strval(); else return ""; } // inline operator std::string() const { if(m_dataChunk!=nullptr) return m_dataChunk->strval(); else return ""; }
@ -388,6 +378,7 @@ namespace ztd
private: private:
//functions //functions
void generateChunk(); void generateChunk();
//attributes //attributes
std::string m_filePath; std::string m_filePath;
std::string m_data; std::string m_data;
@ -428,7 +419,7 @@ namespace ztd
If origin is known, displays location and discriminating line\n If origin is known, displays location and discriminating line\n
If origin is unknown, displays whole data up to discriminating line 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());}
} }

View file

@ -5,37 +5,42 @@ ZFD is composed of infinitely concatenable "chunks". There a three types of chun
- List chunk : between brackets [] - List chunk : between brackets []
- String value - String value
Formatting is ignored, all spaces will be ignored unless they are part of a value. All spaces will be ignored unless they are part of a value.
Comments can be written with //, ends at end of line 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 ### 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 key1=value
//concatenators: value ends at end of concatenation
key2 = " value " key2 = " value "
key3 = ' value ' key3 = ' value '
key4=[ //list ] // brace and brackets have to be the first valid chars for list and maps
key5={ //chunk } key4 = [ //list ]
key5 = { //map }
// multiple values in a single line
key6=foo; key7=bar
} }
``` ```
### List Chunk ### 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 ", " value ",
' value ', ' value ',
{ //chunk }, { //chunk },
[ //list ] [ //list ],
] ]
``` ```

View file

@ -1,5 +1,7 @@
#include "filedat.hpp" #include "filedat.hpp"
#include <algorithm>
// Function code // Function code
bool ztd::filedat::isRead(char in) bool ztd::filedat::isRead(char in)
{ {
@ -14,6 +16,17 @@ static std::string repeatString(const std::string& str, const unsigned int n)
return ret; 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) 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() ztd::filedat::filedat()
{ {
@ -75,7 +129,7 @@ ztd::filedat::filedat(std::string const& in)
ztd::filedat::~filedat() ztd::filedat::~filedat()
{ {
if(m_dataChunk!=nullptr) if(m_dataChunk!=nullptr)
delete m_dataChunk; delete m_dataChunk;
} }
void ztd::filedat::clear() void ztd::filedat::clear()
@ -92,18 +146,18 @@ bool ztd::filedat::readTest() const
{ {
std::ifstream stream(m_filePath); std::ifstream stream(m_filePath);
if(!stream) if(!stream)
return false; return false;
else else
return true; return true;
} }
void ztd::filedat::import_file(const std::string& path) void ztd::filedat::import_file(const std::string& path)
{ {
if(path != "") if(path != "")
m_filePath=path; m_filePath=path;
std::ifstream st(m_filePath); std::ifstream st(m_filePath);
if(!st) if(!st)
throw std::runtime_error("Cannot read file '" + m_filePath + '\''); throw std::runtime_error("Cannot read file '" + m_filePath + '\'');
this->clear(); this->clear();
std::string line; std::string line;
@ -141,11 +195,11 @@ bool ztd::filedat::export_file(std::string const& path, std::string const& align
{ {
std::ofstream stream; std::ofstream stream;
if(path=="") if(path=="")
stream.open(m_filePath); stream.open(m_filePath);
else else
stream.open(path); stream.open(path);
if(!stream) if(!stream)
return false; return false;
stream << this->strval(aligner); stream << this->strval(aligner);
return true; 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 std::string ztd::filedat::strval(std::string const& aligner) const
{ {
if(m_dataChunk == nullptr) if(m_dataChunk == nullptr)
return ""; return "";
else else
return m_dataChunk->strval(0, aligner); return m_dataChunk->strval(0, aligner);
} }
void ztd::filedat::generateChunk() void ztd::filedat::generateChunk()
@ -163,436 +217,402 @@ void ztd::filedat::generateChunk()
try try
{ {
if(m_dataChunk != nullptr) if(m_dataChunk != nullptr)
delete m_dataChunk; delete m_dataChunk;
m_dataChunk = new ztd::chunkdat(m_data.c_str(), m_data.size(), 0, this); m_data = this->removeComments(m_data);
m_dataChunk = new ztd::chunkdat(m_data, 0, nullptr);
} }
catch(ztd::format_error& e) catch(ztd::format_error& e)
{ {
m_dataChunk = nullptr;
throw ztd::format_error(e.what(), m_filePath, m_data, e.where()); 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<std::string, size_t> _skip(const std::string& str)
{ {
int i=0; size_t i=0;
*start = in_size; //default no value //skip to val start
*end = in_size; //default end while( i < str.size() )
*val_size=0; //default no value
while(i<in_size)
{ {
if(i+1<in_size && in[i] == '/' && in[i+1] == '/') // start of value
while(i<in_size && in[i] != '\n') if(ztd::filedat::isRead(str[i]))
i++; break;
if(ztd::filedat::isRead(in[i]))
break;
i++; i++;
} }
if(i >= in_size) //ends without value
return "";
int j=i; //name start
while(i<in_size && in[i] != '=') //skip to =
i++;
if(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 && in[i+j] == '/' && in[i+j+1] == '/')
while(i+j<in_size && in[i+j] != '\n')
j++;
if(in[i+j]=='\\')
j++;
if(in[i+j]=='{')
counter++;
if(in[i+j]=='}')
counter--;
j++;
}
if(i+j >= 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 && in[i+j] == '/' && in[i+j+1] == '/')
while(i+j<in_size && in[i+j] != '\n')
j++;
if(in[i+j]=='\\')
j++;
if(in[i+j]=='[')
counter++;
if(in[i+j]==']')
counter--;
j++;
}
if(i+j >= 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; std::string ret;
if(i < str.size())
while(i<in_size) ret = str.substr(i);
else
{ {
if(i+1<in_size && in[i] == '/' && in[i+1] == '/') i=str.size();
while(i<in_size && in[i] != '\n') ret="";
i++; }
return std::make_pair(ret, i);
}
if(ztd::filedat::isRead(in[i]))
break;
i++; // TODO TODO TODO
// value, rest, start of rest, start of value, delim found
static std::tuple<std::string, std::string, int, int, bool> _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<std::string, std::string, std::string, int, int, int> _getkeyval(const std::string& in)
{
std::string key, value, rstr;
std::tuple<std::string, std::string, int, int, bool> 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; int rr=-1;
if(i >= in_size) //ends without value if(rpos >= 0)
{ rr = dpos+rpos;
*end = in_size; else
return ""; rr = in.size();
}
if(in[i] == ',') //value is empty
{
*end=i+1;
return "";
}
int j=0; return std::make_tuple(key, value, rstr, rr, valstart, keystart);
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 && in[i+j] == '/' && in[i+j+1] == '/')
while(i+j<in_size && in[i+j] != '\n')
j++;
if(in[i+j]=='\\')
j++;
if(in[i+j]=='{')
counter++;
if(in[i+j]=='}')
counter--;
j++;
}
if(i+j >= 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 && in[i+j] == '/' && in[i+j+1] == '/')
while(i+j<in_size && in[i+j] != '\n')
j++;
if(in[i+j]=='\\')
j++;
if(in[i+j]=='[')
counter++;
if(in[i+j]==']')
counter--;
j++;
}
if(i+j >= 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);
} }
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_parent=parent;
this->m_offset=offset; 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 && !ztd::filedat::isRead(in[i])) //skip unread char if(str == "") //empty: make an empty strval
i++;
if(i >= in_size) //empty: make an empty strval
{ {
ztd::chunk_string* cv = new ztd::chunk_string(); ztd::chunk_string* cv = new ztd::chunk_string();
m_achunk=cv; m_achunk=cv;
cv->val = ""; cv->val = "";
return; return;
} }
else if( in[i] == '{') if ( str[0] == '{') // map
{ {
i++; auto p = _skip(rest);
int val_end=in_size-1; if( p.first != "") //rest is not empty
while(!ztd::filedat::isRead(in[val_end])) //skip unread char throw ztd::format_error("Unexpected char", "", in, i+p.second);
val_end--;
if(in[val_end] != '}')
throw ztd::format_error("Expecting closing brace", "", std::string(in, in_size), val_end+1);
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(); ztd::chunk_map* tch = new ztd::chunk_map();
m_achunk = tch; m_achunk = tch;
std::string name; if(_skip(str).first == "") // empty map
std::string val; return;
while(i < val_end)
do
{ {
int start=0; int keystart, valstart;
int _size=0; std::string key, value;
int end=0; p = _skip(str);
if(p.first[0] == '=')
while(!ztd::filedat::isRead(in[i])) throw ztd::format_error("Value has no key", "", in, i+p.second);
i++; try // get one value
std::string newstr=std::string(in+i, val_end-i);
try
{ {
name = _getname(newstr.c_str(), newstr.size(), &start, &_size, &end); auto tup2 = _getkeyval(str);
val = newstr.substr(start, _size); 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) 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(key != "") // good value
if( name == "" ) //no more values
break;
try
{ {
ztd::chunkdat* chk = new ztd::chunkdat(val.c_str(),val.size(), offset + start+i, m_parent); try // insert value
if(!tch->values.insert( std::make_pair(name, chk ) ).second)
{ {
delete chk; ztd::chunkdat* chk = new ztd::chunkdat(value, offset + valstart, m_parent);
throw ztd::format_error("Key '" + name + "' already present", "", std::string(in, in_size), 0 - start ); 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;
} }
while(str != "");
return;
} }
else if( in[i] == '[') else if ( str[0] == '[') // map
{ {
i++; auto p = _skip(rest);
int val_end=in_size-1; if( p.first != "") //rest is not empty
while(!ztd::filedat::isRead(in[val_end])) //skip unread char throw ztd::format_error("Unexpected char", "", in, i+p.second);
val_end--;
if(in[val_end] != ']')
throw ztd::format_error("Expecting closing bracket", "", std::string(in, in_size), val_end+1);
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(); ztd::chunk_list* tch = new ztd::chunk_list();
m_achunk = tch; m_achunk = tch;
int end=0,start=0; if(_skip(str).first == "") // empty list
while( i < val_end ) return;
do
{ {
std::string val; int valstart;
std::string newstr=std::string(in+i, val_end-i); std::string value;
try 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) 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 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) 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;
} }
while(str != "");
return;
} }
else // string value else
{ {
int val_end=in_size; ztd::chunk_string* cv = new ztd::chunk_string();
val_end--; m_achunk=cv;
while(!ztd::filedat::isRead(in[val_end])) //skip unread char cv->val = in;
val_end--;
ztd::chunk_string* tch = new ztd::chunk_string();
m_achunk = tch;
tch->val = std::string(in+i,val_end-i+1);
return;
} }
} }
@ -776,6 +796,8 @@ std::string ztd::chunkdat::strval(unsigned int alignment, std::string const& ali
else if(this->type()==ztd::chunk_abstract::map) else if(this->type()==ztd::chunk_abstract::map)
{ {
ztd::chunk_map* cp = dynamic_cast<chunk_map*>(m_achunk); ztd::chunk_map* cp = dynamic_cast<chunk_map*>(m_achunk);
if(cp->values.size() <= 0)
return "{}";
std::string ret="{\n"; std::string ret="{\n";
for(auto it : cp->values) 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 += it.first;
ret += " = "; ret += " = ";
if(it.second!=nullptr) 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 += '\n';
} }
ret += repeatString(aligner, alignment); 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) else if(this->type()==ztd::chunk_abstract::list)
{ {
ztd::chunk_list* lp = dynamic_cast<chunk_list*>(m_achunk); ztd::chunk_list* lp = dynamic_cast<chunk_list*>(m_achunk);
if(lp->list.size() <= 0)
return "[]";
std::string ret="[\n"; std::string ret="[\n";
for(auto it : lp->list) for(auto it : lp->list)
{ {
ret += repeatString(aligner, alignment+1); ret += repeatString(aligner, alignment+1);
if(it!=nullptr) 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 += ",\n";
} }
ret.erase(ret.end()-2); ret.erase(ret.end()-2);
@ -909,21 +951,23 @@ ztd::chunkdat& ztd::chunkdat::subChunkRef(const unsigned int a) const
ztd::chunkdat::chunkdat() ztd::chunkdat::chunkdat()
{ {
m_achunk=nullptr; m_achunk=nullptr;
m_parent=nullptr;
m_offset=0;
} }
ztd::chunkdat::chunkdat(const char* in) ztd::chunkdat::chunkdat(const char* in)
{ {
m_achunk=nullptr; m_achunk=nullptr;
set(in, strlen(in), 0, 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; 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; m_achunk=nullptr;
set(in, in_size, offset, data); set(in, in_size, offset, parent);
} }
ztd::chunkdat::chunkdat(chunkdat const& in) ztd::chunkdat::chunkdat(chunkdat const& in)
{ {