filedat: rework
format improvement code cleaning
This commit is contained in:
parent
8d01a18f3a
commit
d6a308bdbc
3 changed files with 453 additions and 413 deletions
|
|
@ -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<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
|
||||
//! @see chunkdat::operator+=(std::vector<chunkdat> 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());}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ],
|
||||
]
|
||||
```
|
||||
|
||||
|
|
|
|||
802
src/filedat.cpp
802
src/filedat.cpp
|
|
@ -1,5 +1,7 @@
|
|||
#include "filedat.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// 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<std::string, size_t> _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)
|
||||
//skip to val start
|
||||
while( i < str.size() )
|
||||
{
|
||||
if(i+1<in_size && in[i] == '/' && in[i+1] == '/')
|
||||
while(i<in_size && in[i] != '\n')
|
||||
i++;
|
||||
|
||||
if(ztd::filedat::isRead(in[i]))
|
||||
break;
|
||||
|
||||
// start of value
|
||||
if(ztd::filedat::isRead(str[i]))
|
||||
break;
|
||||
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;
|
||||
|
||||
while(i<in_size)
|
||||
if(i < str.size())
|
||||
ret = str.substr(i);
|
||||
else
|
||||
{
|
||||
if(i+1<in_size && in[i] == '/' && in[i+1] == '/')
|
||||
while(i<in_size && in[i] != '\n')
|
||||
i++;
|
||||
i=str.size();
|
||||
ret="";
|
||||
}
|
||||
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;
|
||||
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 && 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);
|
||||
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 && !ztd::filedat::isRead(in[i])) //skip unread char
|
||||
i++;
|
||||
|
||||
if(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<chunk_map*>(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<chunk_list*>(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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue