Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions Jzon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,168 @@ namespace Jzon
}


StreamWriter::StreamWriter(std::ostream & stream, const Format & format)
: stream(stream), first(true)
{
this->format = format;
indentationChar = (format.useTabs ? '\t' : ' ');
spacing = (format.spacing ? " " : "");
newline = (format.newline ? "\n" : spacing);
}
StreamWriter::~StreamWriter()
{
}
void StreamWriter::startObject()
{
if (!isComplete() && streamStack.back() == StreamState::SS_OBJECT)
throw "Object members must be properties";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size()) << "{" << newline;
streamStack.push_back(StreamState::SS_OBJECT);
first = true;
}
void StreamWriter::startObject(const std::string & name)
{
if (!isComplete() && streamStack.back() != StreamState::SS_OBJECT)
throw "Cannot create property outside of an object";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size()) << "\"" << name << "\":" << spacing << "{" << newline;
streamStack.push_back(StreamState::SS_OBJECT);
first = true;
}
void StreamWriter::endObject()
{
if (streamStack.back() != StreamState::SS_OBJECT)
throw "Cannot end object while not in object";
streamStack.pop_back();
stream << newline << getIndentation(streamStack.size()) << "}";
first = false;
}
void StreamWriter::startArray()
{
if (!isComplete() && streamStack.back() == StreamState::SS_OBJECT)
throw "Object members must be properties";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size()) << "[" << newline;
streamStack.push_back(StreamState::SS_ARRAY);
first = true;
}
void StreamWriter::startArray(const std::string & name)
{
if (!isComplete() && streamStack.back() != StreamState::SS_OBJECT)
throw "Cannot create property outside of an object";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size()) << "\"" << name << "\":" << spacing << "[" << newline;
streamStack.push_back(StreamState::SS_ARRAY);
first = true;
}
void StreamWriter::endArray()
{
if (streamStack.back() != StreamState::SS_ARRAY)
throw "Cannot end array while not in array";
streamStack.pop_back();
stream << newline << getIndentation(streamStack.size()) << "]";
first = false;
}
void StreamWriter::addNode(const Node & node)
{
if (!isComplete() && streamStack.back() == StreamState::SS_OBJECT)
throw "Object members must be properties";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size());
writeNode(node, streamStack.size());
first = false;
}
void StreamWriter::addNode(const std::string & name, const Node & node)
{
if (!isComplete() && streamStack.back() != StreamState::SS_OBJECT)
throw "Cannot create property outside of an object";
if (isComplete() && !first)
throw "Root JSON is complete";
if (!first) stream << "," << newline;
stream << getIndentation(streamStack.size()) << "\"" << name << "\":" << spacing;
writeNode(node, streamStack.size());
first = false;
}
bool StreamWriter::isComplete()
{
return streamStack.size() == 0;
}
std::string StreamWriter::getIndentation(unsigned int level) const
{
if (!format.newline) return "";
else return std::string(format.indentSize * level, indentationChar);
}
void StreamWriter::writeNode(const Node& node, unsigned int level) const
{
switch (node.getType())
{
case Node::T_INVALID: break;
case Node::T_OBJECT: writeObject(node, level); break;
case Node::T_ARRAY: writeArray(node, level); break;
case Node::T_NULL: // Fallthrough
case Node::T_STRING: // Fallthrough
case Node::T_NUMBER: // Fallthrough
case Node::T_BOOL: writeValue(node); break;
}
}
void StreamWriter::writeObject(const Node& node, unsigned int level) const
{
stream << "{" << newline;

for (Node::const_iterator it = node.begin(); it != node.end(); ++it)
{
const std::string& name = (*it).first;
const Node& value = (*it).second;

if (it != node.begin())
stream << "," << newline;
stream << getIndentation(level + 1) << "\"" << name << "\"" << ":" << spacing;
writeNode(value, level + 1);
}

stream << newline << getIndentation(level) << "}";
}
void StreamWriter::writeArray(const Node& node, unsigned int level) const
{
stream << "[" << newline;

for (Node::const_iterator it = node.begin(); it != node.end(); ++it)
{
const Node& value = (*it).second;

if (it != node.begin())
stream << "," << newline;
stream << getIndentation(level + 1);
writeNode(value, level + 1);
}

stream << newline << getIndentation(level) << "]";
}
void StreamWriter::writeValue(const Node& node) const
{
if (node.isString())
{
stream << "\"" << escapeString(node.toString()) << "\"";
}
else
{
stream << node.toString();
}
}



Parser::Parser()
{
}
Expand Down
41 changes: 40 additions & 1 deletion Jzon.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ namespace Jzon
class iterator : public std::iterator<std::input_iterator_tag, NamedNode>
{
public:
iterator() : p(0) {}
iterator() : p(0) {}
iterator(NamedNode *o) : p(o) {}
iterator(const iterator &it) : p(it.p) {}

Expand Down Expand Up @@ -254,6 +254,45 @@ namespace Jzon
const char *spacing;
};

class JZON_API StreamWriter
{
public:
explicit StreamWriter(std::ostream& stream, const Format& format = NoFormat);
~StreamWriter();

void startObject();
void startObject(const std::string& name);
void endObject();
void startArray();
void startArray(const std::string& name);
void endArray();
void addNode(const Node& node);
void addNode(const std::string& name, const Node& node);

bool isComplete();

private:
enum StreamState
{
SS_OBJECT,
SS_ARRAY,
};
std::string getIndentation(unsigned int level) const;
void writeNode(const Node& node, unsigned int level) const;
void writeObject(const Node& node, unsigned int level) const;
void writeArray(const Node& node, unsigned int level) const;
void writeValue(const Node& node) const;

Format format;
char indentationChar;
const char* newline;
const char* spacing;

std::ostream& stream;
bool first;
std::vector<StreamState> streamStack;
};

class JZON_API Parser
{
public:
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,40 @@ node.add("bool", true);
}

Jzon::Writer writer;
writer.setFormat(Jzon::StandardFormat);
writer.writeStream(node, cout);
```

```c
Jzon::StreamWriter writer = Jzon::StreamWriter(std::cout, Jzon::StandardFormat);
writer.startObject();
{
writer.addNode("name", "value");
writer.addNode("number", 20);
writer.addNode("anothernumber", 15.3);
writer.addNode("bool", true);
writer.startArray("array");
{
writer.addNode(1);
writer.addNode("asdf");
writer.startObject();
{
writer.addNode("key1", "val1");
writer.addNode("key2", "val2");
}
writer.endObject();
}
writer.endArray();
writer.startObject("subnode");
{
writer.addNode("key1", "val1");
writer.addNode("key2", "val2");
}
writer.endObject();
}
writer.endObject();
```

#### Result
```json
{
Expand Down