Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#include "bbcode.h"
|
||||
|
||||
enum ParseState {
|
||||
PS_Text,
|
||||
PS_StartTag,
|
||||
PS_EndTag
|
||||
};
|
||||
|
||||
static const char* parseTag(BBCode::Tag& root, const char* str) {
|
||||
bool escaped = false;
|
||||
bool selfClose = false;
|
||||
ParseState state = PS_Text;
|
||||
const char* start = str;
|
||||
unsigned tagDepth = 0;
|
||||
|
||||
while(*str != 0) {
|
||||
unsigned char c = *str;
|
||||
switch(state) {
|
||||
case PS_Text:
|
||||
if(c == '\\') {
|
||||
if(escaped) {
|
||||
escaped = false;
|
||||
if(str != start) {
|
||||
BBCode::Tag t;
|
||||
t.type = -1;
|
||||
t.argument = std::string(start, str - start);
|
||||
root.contents.push_back(t);
|
||||
}
|
||||
++str;
|
||||
start = str;
|
||||
}
|
||||
else {
|
||||
escaped = true;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
else if(c == '[') {
|
||||
if(escaped) {
|
||||
--str;
|
||||
if(str != start) {
|
||||
BBCode::Tag t;
|
||||
t.type = -1;
|
||||
t.argument = std::string(start, str - start);
|
||||
root.contents.push_back(t);
|
||||
}
|
||||
++str;
|
||||
|
||||
escaped = false;
|
||||
start = str;
|
||||
++str;
|
||||
}
|
||||
else {
|
||||
if(str != start) {
|
||||
BBCode::Tag t;
|
||||
t.type = -1;
|
||||
t.argument = std::string(start, str - start);
|
||||
root.contents.push_back(t);
|
||||
}
|
||||
|
||||
state = PS_StartTag;
|
||||
++str;
|
||||
start = str;
|
||||
}
|
||||
}
|
||||
else {
|
||||
++str;
|
||||
}
|
||||
break;
|
||||
case PS_StartTag:
|
||||
if(c == '/') {
|
||||
if(str == start) {
|
||||
state = PS_EndTag;
|
||||
++str;
|
||||
start = str;
|
||||
}
|
||||
else {
|
||||
selfClose = true;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
else if(c == ']') {
|
||||
if(tagDepth > 0) {
|
||||
--tagDepth;
|
||||
++str;
|
||||
selfClose = true;
|
||||
break;
|
||||
}
|
||||
|
||||
std::string tagname;
|
||||
if(selfClose)
|
||||
tagname = std::string(start, (str - 1) - start);
|
||||
else
|
||||
tagname = std::string(start, str - start);
|
||||
++str;
|
||||
|
||||
BBCode::Tag t;
|
||||
auto argpos = tagname.find('=');
|
||||
if(argpos != std::string::npos) {
|
||||
t.name = tagname.substr(0, argpos);
|
||||
if(argpos < tagname.size() - 1)
|
||||
t.argument = tagname.substr(argpos+1);
|
||||
}
|
||||
else {
|
||||
t.name = tagname;
|
||||
}
|
||||
|
||||
if(selfClose)
|
||||
selfClose = false;
|
||||
else
|
||||
str = parseTag(t, str);
|
||||
state = PS_Text;
|
||||
start = str;
|
||||
|
||||
root.contents.push_back(t);
|
||||
}
|
||||
else {
|
||||
if(c == '[')
|
||||
++tagDepth;
|
||||
selfClose = false;
|
||||
++str;
|
||||
}
|
||||
break;
|
||||
case PS_EndTag:
|
||||
if(c == ']') {
|
||||
std::string tagname(start, str - start);
|
||||
++str;
|
||||
|
||||
if(tagname != root.name)
|
||||
throw "Unexpected close tag.";
|
||||
return str;
|
||||
}
|
||||
else {
|
||||
++str;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
++str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(state == PS_Text && str != start) {
|
||||
BBCode::Tag t;
|
||||
t.type = -1;
|
||||
t.argument = std::string(start, str - start);
|
||||
root.contents.push_back(t);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void BBCode::parse(const std::string& content) {
|
||||
//Clear everything
|
||||
root.contents.clear();
|
||||
|
||||
//Start parsing
|
||||
parseTag(root, content.c_str());
|
||||
}
|
||||
|
||||
void BBCode::clear() {
|
||||
root.contents.clear();
|
||||
}
|
||||
|
||||
BBCode::BBCode() {
|
||||
}
|
||||
|
||||
BBCode::~BBCode() {
|
||||
}
|
||||
Reference in New Issue
Block a user