snes9x/bml.cpp

292 lines
6.0 KiB
C++
Raw Normal View History

2018-04-24 21:16:22 +00:00
#include <vector>
2019-06-03 00:09:52 +00:00
#include <iostream>
#include <fstream>
#include <stack>
2018-04-24 21:16:22 +00:00
#include <stdio.h>
2018-04-27 20:42:19 +00:00
#include "port.h"
2018-04-24 21:16:22 +00:00
#include "bml.h"
bml_node::bml_node()
2018-04-27 20:42:19 +00:00
{
type = CHILD;
depth = -1;
2018-04-24 21:16:22 +00:00
}
2018-04-27 20:42:19 +00:00
static inline int islf(char c)
2018-04-24 21:16:22 +00:00
{
2018-04-27 20:42:19 +00:00
return (c == '\r' || c == '\n');
}
2018-04-24 21:16:22 +00:00
2018-04-27 20:42:19 +00:00
static inline int isblank(char c)
{
return (c == ' ' || c == '\t');
}
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
static inline int isblankorlf(char c)
{
return (islf(c) || isblank(c));
}
2018-04-27 20:42:19 +00:00
static inline int isalnum(char c)
{
return ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'));
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static inline int bml_valid(char c)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
return (isalnum(c) || c == '-');
2018-04-24 21:16:22 +00:00
}
static std::string trim(std::string str)
2018-04-24 21:16:22 +00:00
{
2018-04-27 20:42:19 +00:00
int start;
int end;
2019-06-03 00:09:52 +00:00
for (start = 0; str[start] && start != (int)str.length() && isblank(str[start]); start++) {}
if (start >= (int)str.length())
return std::string("");
2019-06-03 00:09:52 +00:00
for (end = str.length() - 1; isblank(str[end]) || str[end] == '\n' || str[end] == '\r'; end--) {}
return str.substr(start, end - start + 1);
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static std::string trimcomments(std::string str)
{
int end = str.length();
size_t comment = str.find("//");
if (comment != std::string::npos)
end = comment;
for (int i = end - 1; i >= 0; i--)
{
if (!isblankorlf(str[i]))
{
end = i + 1;
break;
}
}
return str.substr(0, end);
}
static inline int bml_read_depth(std::string &data)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
size_t depth;
for (depth = 0; isblank(data[depth]) && depth < data.length(); depth++) {}
return depth == data.length() ? -1 : depth;
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static void bml_parse_depth(bml_node &node, std::string &line)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
unsigned int depth = bml_read_depth(line);
line.erase(0, depth);
node.depth = depth;
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static void bml_parse_name(bml_node &node, std::string &line)
2018-04-24 21:16:22 +00:00
{
int len;
2019-06-03 00:09:52 +00:00
for (len = 0; bml_valid(line[len]); len++) {};
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
node.name = trim(line.substr(0, len));
line.erase(0, len);
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static void bml_parse_data(bml_node &node, std::string &line)
2018-04-24 21:16:22 +00:00
{
int len;
2019-06-03 00:09:52 +00:00
if (line[0] == '=' && line[1] == '\"')
2018-04-24 21:16:22 +00:00
{
len = 2;
2019-06-03 00:09:52 +00:00
while (line[len] && line[len] != '\"' && !islf(line[len]))
2018-04-24 21:16:22 +00:00
len++;
2019-06-03 00:09:52 +00:00
if (line[len] != '\"')
2018-04-24 21:16:22 +00:00
return;
2019-06-03 00:09:52 +00:00
node.data = line.substr(2, len - 2);
line.erase(0, len + 1);
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
else if (line[0] == '=')
2018-04-24 21:16:22 +00:00
{
len = 1;
2019-06-03 00:09:52 +00:00
while (line[len] && !islf(line[len]) && line[len] != '"' && line[len] != ' ')
2018-04-24 21:16:22 +00:00
len++;
2019-06-03 00:09:52 +00:00
if (line[len] == '\"')
2018-04-24 21:16:22 +00:00
return;
2019-06-03 00:09:52 +00:00
node.data = line.substr(1, len - 1);
line.erase(0, len);
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
else if (line[0] == ':')
2018-04-24 21:16:22 +00:00
{
len = 1;
2019-06-03 00:09:52 +00:00
while (line[len] && !islf(line[len]))
2018-04-24 21:16:22 +00:00
len++;
2019-06-03 00:09:52 +00:00
node.data = line.substr(1, len - 1);
line.erase(0, len);
2018-04-24 21:16:22 +00:00
}
return;
}
2019-06-03 00:09:52 +00:00
static std::string bml_read_line(std::ifstream &fd)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
std::string line;
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
while (fd)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
std::getline(fd, line);
line = trimcomments(line);
if (!line.empty())
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
return line;
2018-04-24 21:16:22 +00:00
}
}
2019-06-03 00:09:52 +00:00
return std::string("");
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
static void bml_parse_attr(bml_node &node, std::string &line)
2018-04-24 21:16:22 +00:00
{
int len;
2019-06-03 00:09:52 +00:00
while (line.length() > 0)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
if (!isblank(line[0]))
2018-04-24 21:16:22 +00:00
return;
2019-06-03 00:09:52 +00:00
while (isblank(line[0]))
line.erase(0, 1);
2018-04-24 21:16:22 +00:00
bml_node n;
2018-04-24 21:16:22 +00:00
len = 0;
2019-06-03 00:09:52 +00:00
while (bml_valid(line[len]))
len++;
2018-04-24 21:16:22 +00:00
if (len == 0)
return;
2019-06-03 00:09:52 +00:00
n.name = trim(line.substr(0, len));
line.erase(0, len);
bml_parse_data(n, line);
n.depth = node.depth + 1;
2019-06-03 00:09:52 +00:00
n.type = bml_node::ATTRIBUTE;
node.child.push_back(n);
2018-04-24 21:16:22 +00:00
}
}
2019-06-03 00:09:52 +00:00
static int contains_space(const char *str)
2018-04-24 21:16:22 +00:00
{
for (int i = 0; str[i]; i++)
{
2019-06-03 00:09:52 +00:00
if (isblank(str[i]))
2018-04-24 21:16:22 +00:00
return 1;
}
return 0;
}
static void bml_print_node(bml_node &node, int depth)
2018-04-24 21:16:22 +00:00
{
2018-04-26 00:29:26 +00:00
int i;
for (i = 0; i < depth * 2; i++)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
printf(" ");
2018-04-24 21:16:22 +00:00
}
if (!node.name.empty())
2019-06-03 00:09:52 +00:00
printf("%s", node.name.c_str());
2018-04-24 21:16:22 +00:00
if (!node.data.empty())
2018-04-24 21:16:22 +00:00
{
if (contains_space(node.data.c_str()))
2019-06-03 00:09:52 +00:00
printf("=\"%s\"", node.data.c_str());
2018-04-24 21:16:22 +00:00
else
2019-06-03 00:09:52 +00:00
printf(": %s", node.data.c_str());
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
for (i = 0; i < (int)node.child.size() && node.child[i].type == bml_node::ATTRIBUTE; i++)
2018-04-24 21:16:22 +00:00
{
if (!node.child[i].name.empty())
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
printf(" %s", node.child[i].name.c_str());
if (!node.child[i].data.empty())
2018-04-24 21:16:22 +00:00
{
if (contains_space(node.child[i].data.c_str()))
2019-06-03 00:09:52 +00:00
printf("=\"%s\"", node.child[i].data.c_str());
2018-04-24 21:16:22 +00:00
else
2019-06-03 00:09:52 +00:00
printf("=%s", node.child[i].data.c_str());
2018-04-24 21:16:22 +00:00
}
}
}
if (depth >= 0)
2019-06-03 00:09:52 +00:00
printf("\n");
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
for (; i < (int)node.child.size(); i++)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
bml_print_node(node.child[i], depth + 1);
2018-04-24 21:16:22 +00:00
}
if (depth == 0)
2019-06-03 00:09:52 +00:00
printf("\n");
2018-04-24 21:16:22 +00:00
}
void bml_node::print()
2018-04-24 21:16:22 +00:00
{
bml_print_node(*this, -1);
2018-04-24 21:16:22 +00:00
}
2019-06-03 00:09:52 +00:00
void bml_node::parse(std::ifstream &fd)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
std::stack<bml_node *> nodestack;
nodestack.push(this);
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
while (fd)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
bml_node newnode;
std::string line = bml_read_line(fd);
if (line.empty())
return;
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
int line_depth = bml_read_depth(line);
while (line_depth <= nodestack.top()->depth && nodestack.size() > 1)
nodestack.pop();
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
bml_parse_depth(newnode, line);
bml_parse_name(newnode, line);
bml_parse_data(newnode, line);
bml_parse_attr(newnode, line);
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
nodestack.top()->child.push_back(newnode);
nodestack.push(&nodestack.top()->child.back());
2018-04-24 21:16:22 +00:00
}
return;
}
2019-06-03 00:09:52 +00:00
bml_node *bml_node::find_subnode(std::string name)
2018-04-26 00:29:26 +00:00
{
unsigned int i;
2019-06-03 00:09:52 +00:00
for (i = 0; i < child.size(); i++)
2018-04-26 00:29:26 +00:00
{
if (name.compare(child[i].name) == 0)
return &child[i];
2018-04-26 00:29:26 +00:00
}
return NULL;
}
2019-06-03 00:09:52 +00:00
bool bml_node::parse_file(std::string filename)
2018-04-24 21:16:22 +00:00
{
2019-06-03 00:09:52 +00:00
std::ifstream file(filename, std::ios_base::binary);
2018-04-24 21:16:22 +00:00
if (!file)
return false;
2018-04-24 21:16:22 +00:00
2019-06-03 00:09:52 +00:00
parse(file);
2018-04-24 21:16:22 +00:00
return true;
2018-04-24 21:16:22 +00:00
}