Reduce manual allocation in BML parser and cheats.

Less risk of potential memory leaks.
This commit is contained in:
Brandon Wright 2019-05-14 17:42:41 -05:00
parent f8a0fadfa1
commit 4f965300f7
4 changed files with 122 additions and 196 deletions

176
bml.cpp
View File

@ -5,31 +5,9 @@
#include "port.h" #include "port.h"
#include "bml.h" #include "bml.h"
static char *strndup_p(char *str, int len) bml_node::bml_node()
{ {
char *buffer; depth = -1;
int n;
buffer = (char *) malloc (len + 1);
if (buffer)
{
for (n = 0; ((n < len) && (str[n] != 0)); n++) buffer[n] = str[n];
buffer[n] = '\0';
}
return buffer;
}
static inline bml_node *bml_node_new (void)
{
bml_node *node = new bml_node;
node->data = NULL;
node->name = NULL;
node->depth = -1;
return node;
} }
static inline int islf(char c) static inline int islf(char c)
@ -54,18 +32,15 @@ static inline int bml_valid (char c)
return (isalnum (c) || c == '-'); return (isalnum (c) || c == '-');
} }
static char *strndup_trim (char *str, int len) static std::string trim(std::string str)
{ {
int start; int start;
int end; int end;
for (start = 0; str[start] && start != (int)str.length() && isblank (str[start]); start++) {}
for (start = 0; str[start] && start != len && isblank (str[start]); start++) {} if (start >= (int)str.length())
if (!str[start] || start >= len) return std::string("");
return strdup (""); for (end = str.length() - 1; isblank (str[end]) || str[end] == '\n' || str[end] == '\r'; end--) {}
return str.substr(start, end - start + 1);
for (end = len - 1; isblank (str[end]) || str[end] == '\n' || str[end] == '\r'; end--) {}
return strndup_p (str + start, end - start + 1);
} }
static inline unsigned int bml_read_depth(char *data) static inline unsigned int bml_read_depth(char *data)
@ -75,24 +50,24 @@ static inline unsigned int bml_read_depth (char *data)
return depth; return depth;
} }
static void bml_parse_depth (bml_node *node, char **data) static void bml_parse_depth(bml_node &node, char **data)
{ {
unsigned int depth = bml_read_depth(*data); unsigned int depth = bml_read_depth(*data);
*data += depth; *data += depth;
node->depth = depth; node.depth = depth;
} }
static void bml_parse_name (bml_node *node, char **data) static void bml_parse_name(bml_node &node, char **data)
{ {
int len; int len;
for (len = 0; bml_valid(*(*data + len)); len++) {}; for (len = 0; bml_valid(*(*data + len)); len++) {};
node->name = strndup_trim (*data, len); node.name = trim(std::string(*data, len));
*data += len; *data += len;
} }
static void bml_parse_data (bml_node *node, char **data) static void bml_parse_data(bml_node &node, char **data)
{ {
char *p = *data; char *p = *data;
int len; int len;
@ -105,7 +80,7 @@ static void bml_parse_data (bml_node *node, char **data)
if (p[len] != '\"') if (p[len] != '\"')
return; return;
node->data = strndup_p (p + 2, len - 2); node.data = std::string(p + 2, len - 2);
*data += len + 1; *data += len + 1;
} }
else if (*p == '=') else if (*p == '=')
@ -115,7 +90,7 @@ static void bml_parse_data (bml_node *node, char **data)
len++; len++;
if (p[len] == '\"') if (p[len] == '\"')
return; return;
node->data = strndup_trim (p + 1, len - 1); node.data = std::string(p + 1, len - 1);
*data += len; *data += len;
} }
else if (*p == ':') else if (*p == ':')
@ -123,7 +98,7 @@ static void bml_parse_data (bml_node *node, char **data)
len = 1; len = 1;
while (p[len] && !islf(p[len])) while (p[len] && !islf(p[len]))
len++; len++;
node->data = strndup_trim (p + 1, len - 1); node.data = std::string(p + 1, len - 1);
*data += len; *data += len;
} }
@ -182,10 +157,9 @@ static char *bml_read_line (char **data)
return line; return line;
} }
static void bml_parse_attr (bml_node *node, char **data) static void bml_parse_attr(bml_node &node, char **data)
{ {
char *p = *data; char *p = *data;
bml_node *n;
int len; int len;
while (*p && !islf(*p)) while (*p && !islf(*p))
@ -198,23 +172,23 @@ static void bml_parse_attr (bml_node *node, char **data)
if (p[0] == '/' && p[1] == '/') if (p[0] == '/' && p[1] == '/')
break; break;
n = bml_node_new (); bml_node n;
len = 0; len = 0;
while (bml_valid(p[len])) while (bml_valid(p[len]))
len++; len++;
if (len == 0) if (len == 0)
return; return;
n->name = strndup_trim (p, len); n.name = trim(std::string(p, len));
p += len; p += len;
bml_parse_data(n, &p); bml_parse_data(n, &p);
n->depth = bml_attr_type; n.depth = bml_attr_type;
node->child.push_back (n); node.child.push_back(n);
} }
*data = p; *data = p;
} }
static int contains_space (char *str) static int contains_space (const char *str)
{ {
for (int i = 0; str[i]; i++) for (int i = 0; str[i]; i++)
{ {
@ -225,39 +199,36 @@ static int contains_space (char *str)
return 0; return 0;
} }
static void bml_print_node (bml_node *node, int depth) static void bml_print_node(bml_node &node, int depth)
{ {
int i; int i;
if (!node)
return;
for (i = 0; i < depth * 2; i++) for (i = 0; i < depth * 2; i++)
{ {
printf (" "); printf (" ");
} }
if (node->name) if (!node.name.empty())
printf ("%s", node->name); printf ("%s", node.name.c_str());
if (node->data) if (!node.data.empty())
{ {
if (contains_space (node->data)) if (contains_space(node.data.c_str()))
printf ("=\"%s\"", node->data); printf ("=\"%s\"", node.data.c_str());
else else
printf (": %s", node->data); printf (": %s", node.data.c_str());
} }
for (i = 0; i < (int) node->child.size () && node->child[i]->depth == bml_attr_type; i++) for (i = 0; i < (int) node.child.size () && node.child[i].depth == bml_attr_type; i++)
{ {
if (node->child[i]->name) if (!node.child[i].name.empty())
{ {
printf (" %s", node->child[i]->name); printf (" %s", node.child[i].name.c_str());
if (node->child[i]->data) if (!node.child[i].data.empty())
{ {
if (contains_space (node->child[i]->data)) if (contains_space(node.child[i].data.c_str()))
printf ("=\"%s\"", node->child[i]->data); printf ("=\"%s\"", node.child[i].data.c_str());
else else
printf ("=%s", node->child[i]->data); printf ("=%s", node.child[i].data.c_str());
} }
} }
} }
@ -265,44 +236,42 @@ static void bml_print_node (bml_node *node, int depth)
if (depth >= 0) if (depth >= 0)
printf ("\n"); printf ("\n");
for (; i < (int) node->child.size(); i++) for (; i < (int) node.child.size(); i++)
{ {
bml_print_node (node->child[i], depth + 1); bml_print_node (node.child[i], depth + 1);
} }
if (depth == 0) if (depth == 0)
printf ("\n"); printf ("\n");
} }
void bml_print_node (bml_node *node) void bml_node::print()
{ {
bml_print_node (node, -1); bml_print_node(*this, -1);
} }
static bml_node *bml_parse_node (char **doc) static bml_node bml_parse_node(char **doc)
{ {
char *line; char *line;
bml_node *node = NULL; bml_node node;
if ((line = bml_read_line(doc))) if ((line = bml_read_line(doc)))
{ {
node = bml_node_new ();
bml_parse_depth(node, &line); bml_parse_depth(node, &line);
bml_parse_name(node, &line); bml_parse_name(node, &line);
bml_parse_data(node, &line); bml_parse_data(node, &line);
bml_parse_attr(node, &line); bml_parse_attr(node, &line);
} }
else else
return NULL; return node;
bml_skip_empty(doc); bml_skip_empty(doc);
while (*doc && (int) bml_read_depth (*doc) > node->depth) while (*doc && (int)bml_read_depth(*doc) > node.depth)
{ {
bml_node *child = bml_parse_node (doc); bml_node child = bml_parse_node(doc);
if (child) if (child.depth != -1)
node->child.push_back (child); node.child.push_back(child);
bml_skip_empty(doc); bml_skip_empty(doc);
} }
@ -310,66 +279,42 @@ static bml_node *bml_parse_node (char **doc)
return node; return node;
} }
void bml_free_node (bml_node *node) void bml_node::parse(char *doc)
{ {
delete[] (node->name); bml_node node;
delete[] (node->data); char *ptr = doc;
for (unsigned int i = 0; i < node->child.size(); i++) while ((node = bml_parse_node (&ptr)).depth != -1)
{ {
bml_free_node (node->child[i]); child.push_back(node);
delete node->child[i];
} }
return; return;
} }
bml_node *bml_parse (char **doc) bml_node *bml_node::find_subnode (std::string name)
{
bml_node *root = NULL;
bml_node *node = NULL;
char *ptr = *doc;
root = bml_node_new ();
while ((node = bml_parse_node (&ptr)))
{
root->child.push_back (node);
}
if (!root->child.size())
{
delete root;
root = NULL;
}
return root;
}
bml_node *bml_find_sub (bml_node *n, const char *name)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < n->child.size (); i++) for (i = 0; i < child.size (); i++)
{ {
if (!strcasecmp (n->child[i]->name, name)) if (name.compare(child[i].name) == 0)
return n->child[i]; return &child[i];
} }
return NULL; return NULL;
} }
bml_node *bml_parse_file (const char *filename) bool bml_node::parse_file(const char *filename)
{ {
FILE *file = NULL; FILE *file = NULL;
char *buffer = NULL; char *buffer = NULL;
int file_size = 0; int file_size = 0;
bml_node *node = NULL;
file = fopen(filename, "rb"); file = fopen(filename, "rb");
if (!file) if (!file)
return NULL; return false;
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
file_size = ftell(file); file_size = ftell(file);
@ -378,11 +323,10 @@ bml_node *bml_parse_file (const char *filename)
buffer = new char[file_size + 1]; buffer = new char[file_size + 1];
fread(buffer, file_size, 1, file); fread(buffer, file_size, 1, file);
buffer[file_size] = '\0'; buffer[file_size] = '\0';
fclose(file); fclose(file);
node = bml_parse (&buffer); parse(buffer);
delete[] buffer; delete[] buffer;
return node; return true;
} }

32
bml.h
View File

@ -1,31 +1,23 @@
#ifndef __BML_H #ifndef __BML_H
#define __BML_H #define __BML_H
#include <vector> #include <vector>
#include <string>
const int bml_attr_type = -2; const int bml_attr_type = -2;
typedef struct bml_node struct bml_node
{ {
char *name; bml_node();
char *data; bool parse_file(const char *filename);
void parse(char *buffer);
bml_node *find_subnode(std::string name);
void print();
static const int bml_attr_type = -2;
std::string name;
std::string data;
int depth; int depth;
std::vector<bml_node> child;
std::vector<bml_node *> child; };
} bml_node;
bml_node *bml_find_sub (bml_node *node, const char *name);
bml_node *bml_parse_file (const char *filename);
/* Parse character array into BML tree. Destructive to input. */
bml_node *bml_parse (char **buffer);
/* Recursively free bml_node and substructures */
void bml_free_node (bml_node *);
/* Print node structure to stdout */
void bml_print_node (bml_node *);
#endif #endif

View File

@ -86,7 +86,7 @@ void S9xUpdateCheatsInMemory (void);
int S9xImportCheatsFromDatabase(const char *filename); int S9xImportCheatsFromDatabase(const char *filename);
void S9xCheatsDisable (void); void S9xCheatsDisable (void);
void S9xCheatsEnable (void); void S9xCheatsEnable (void);
char *S9xCheatValidate (char *cheat); char *S9xCheatValidate (const char *cheat);
void S9xInitCheatData (void); void S9xInitCheatData (void);
void S9xInitWatchedAddress (void); void S9xInitWatchedAddress (void);

View File

@ -493,7 +493,7 @@ char *S9xCheatGroupToText (SCheatGroup *g)
return strdup (text.c_str ()); return strdup (text.c_str ());
} }
char *S9xCheatValidate (char *code_string) char *S9xCheatValidate (const char *code_string)
{ {
SCheatGroup g = S9xCreateCheatGroup ("temp", code_string); SCheatGroup g = S9xCreateCheatGroup ("temp", code_string);
@ -532,7 +532,7 @@ void S9xUpdateCheatsInMemory (void)
} }
} }
static int S9xCheatIsDuplicate (char *name, char *code) static int S9xCheatIsDuplicate (const char *name, const char *code)
{ {
unsigned int i; unsigned int i;
@ -564,26 +564,26 @@ static void S9xLoadCheatsFromBMLNode (bml_node *n)
for (i = 0; i < n->child.size (); i++) for (i = 0; i < n->child.size (); i++)
{ {
if (!strcasecmp (n->child[i]->name, "cheat")) if (!strcasecmp (n->child[i].name.c_str(), "cheat"))
{ {
char *desc = NULL; const char *desc = NULL;
char *code = NULL; const char *code = NULL;
bool8 enabled = false; bool8 enabled = false;
bml_node *c = n->child[i]; bml_node *c = &n->child[i];
bml_node *tmp = NULL; bml_node *tmp = NULL;
tmp = bml_find_sub(c, "name"); tmp = c->find_subnode("name");
if (!tmp) if (!tmp)
desc = (char *) ""; desc = (char *) "";
else else
desc = tmp->data; desc = tmp->data.c_str();
tmp = bml_find_sub(c, "code"); tmp = c->find_subnode("code");
if (tmp) if (tmp)
code = tmp->data; code = tmp->data.c_str();
if (bml_find_sub(c, "enable")) if (c->find_subnode("enable"))
enabled = true; enabled = true;
if (code && !S9xCheatIsDuplicate (desc, code)) if (code && !S9xCheatIsDuplicate (desc, code))
@ -633,23 +633,18 @@ static bool8 S9xLoadCheatFileClassic (const char *filename)
bool8 S9xLoadCheatFile (const char *filename) bool8 S9xLoadCheatFile (const char *filename)
{ {
bml_node *bml = NULL; bml_node bml;
bml_node *n = NULL; if (!bml.parse_file(filename))
bml = bml_parse_file (filename);
if (!bml)
{ {
return S9xLoadCheatFileClassic (filename); return S9xLoadCheatFileClassic (filename);
} }
n = bml_find_sub (bml, "cheat"); bml_node *n = bml.find_subnode("cheat");
if (n) if (n)
{ {
S9xLoadCheatsFromBMLNode (bml); S9xLoadCheatsFromBMLNode (&bml);
} }
bml_free_node (bml);
if (!n) if (!n)
{ {
return S9xLoadCheatFileClassic (filename); return S9xLoadCheatFileClassic (filename);
@ -736,15 +731,13 @@ void S9xCheatsEnable (void)
int S9xImportCheatsFromDatabase (const char *filename) int S9xImportCheatsFromDatabase (const char *filename)
{ {
bml_node *bml;
char sha256_txt[65]; char sha256_txt[65];
char hextable[] = "0123456789abcdef"; char hextable[] = "0123456789abcdef";
unsigned int i; unsigned int i;
bml = bml_parse_file (filename); bml_node bml;
if (!bml.parse_file(filename))
if (!bml) return -1; // No file
return -1; /* No file */
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
{ {
@ -753,25 +746,22 @@ int S9xImportCheatsFromDatabase (const char *filename)
} }
sha256_txt[64] = '\0'; sha256_txt[64] = '\0';
for (i = 0; i < bml->child.size (); i++) for (i = 0; i < bml.child.size (); i++)
{ {
if (!strcasecmp (bml->child[i]->name, "cartridge")) if (!strcasecmp (bml.child[i].name.c_str(), "cartridge"))
{ {
bml_node *n; bml_node *n;
if ((n = bml_find_sub (bml->child[i], "sha256"))) if ((n = bml.child[i].find_subnode ("sha256")))
{ {
if (!strcasecmp (n->data, sha256_txt)) if (!strcasecmp (n->data.c_str(), sha256_txt))
{ {
S9xLoadCheatsFromBMLNode (bml->child[i]); S9xLoadCheatsFromBMLNode (&bml.child[i]);
bml_free_node (bml);
return 0; return 0;
} }
} }
} }
} }
bml_free_node (bml);
return -2; /* No codes */ return -2; /* No codes */
} }