From 4f965300f7d4aa08bf91fb38ada8c2fb6fbe0a26 Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Tue, 14 May 2019 17:42:41 -0500 Subject: [PATCH] Reduce manual allocation in BML parser and cheats. Less risk of potential memory leaks. --- bml.cpp | 226 ++++++++++++++++++++-------------------------------- bml.h | 34 +++----- cheats.h | 2 +- cheats2.cpp | 58 ++++++-------- 4 files changed, 123 insertions(+), 197 deletions(-) diff --git a/bml.cpp b/bml.cpp index adbef9153..9bfe80022 100644 --- a/bml.cpp +++ b/bml.cpp @@ -5,31 +5,9 @@ #include "port.h" #include "bml.h" -static char *strndup_p(char *str, int len) +bml_node::bml_node() { - char *buffer; - 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; + depth = -1; } static inline int islf(char c) @@ -54,45 +32,42 @@ static inline int bml_valid (char c) return (isalnum (c) || c == '-'); } -static char *strndup_trim (char *str, int len) +static std::string trim(std::string str) { int start; int end; - - for (start = 0; str[start] && start != len && isblank (str[start]); start++) {} - if (!str[start] || start >= len) - return strdup (""); - - for (end = len - 1; isblank (str[end]) || str[end] == '\n' || str[end] == '\r'; end--) {} - - return strndup_p (str + start, end - start + 1); + for (start = 0; str[start] && start != (int)str.length() && isblank (str[start]); start++) {} + if (start >= (int)str.length()) + return std::string(""); + for (end = str.length() - 1; isblank (str[end]) || str[end] == '\n' || str[end] == '\r'; end--) {} + return str.substr(start, end - start + 1); } -static inline unsigned int bml_read_depth (char *data) +static inline unsigned int bml_read_depth(char *data) { unsigned int depth; - for (depth = 0; isblank (data[depth]); depth++) {} + for (depth = 0; isblank(data[depth]); 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; - 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; for (len = 0; bml_valid(*(*data + len)); len++) {}; - node->name = strndup_trim (*data, len); + node.name = trim(std::string(*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; int len; @@ -100,37 +75,37 @@ static void bml_parse_data (bml_node *node, char **data) if (p[0] == '=' && p[1] == '\"') { len = 2; - while (p[len] && p[len] != '\"' && !islf (p[len])) + while (p[len] && p[len] != '\"' && !islf(p[len])) len++; if (p[len] != '\"') return; - node->data = strndup_p (p + 2, len - 2); + node.data = std::string(p + 2, len - 2); *data += len + 1; } else if (*p == '=') { len = 1; - while (p[len] && !islf (p[len]) && p[len] != '"' && p[len] != ' ') + while (p[len] && !islf(p[len]) && p[len] != '"' && p[len] != ' ') len++; if (p[len] == '\"') return; - node->data = strndup_trim (p + 1, len - 1); + node.data = std::string(p + 1, len - 1); *data += len; } else if (*p == ':') { len = 1; - while (p[len] && !islf (p[len])) + while (p[len] && !islf(p[len])) len++; - node->data = strndup_trim (p + 1, len - 1); + node.data = std::string(p + 1, len - 1); *data += len; } return; } -static void bml_skip_empty (char **data) +static void bml_skip_empty(char **data) { char *p = *data; @@ -182,39 +157,38 @@ static char *bml_read_line (char **data) 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; - bml_node *n; int len; - while (*p && !islf (*p)) + while (*p && !islf(*p)) { if (*p != ' ') return; - while (isblank (*p)) + while (isblank(*p)) p++; if (p[0] == '/' && p[1] == '/') break; - n = bml_node_new (); + bml_node n; len = 0; - while (bml_valid (p[len])) - len++; + while (bml_valid(p[len])) + len++; if (len == 0) return; - n->name = strndup_trim (p, len); + n.name = trim(std::string(p, len)); p += len; - bml_parse_data (n, &p); - n->depth = bml_attr_type; - node->child.push_back (n); + bml_parse_data(n, &p); + n.depth = bml_attr_type; + node.child.push_back(n); } *data = p; } -static int contains_space (char *str) +static int contains_space (const char *str) { for (int i = 0; str[i]; i++) { @@ -225,39 +199,36 @@ static int contains_space (char *str) return 0; } -static void bml_print_node (bml_node *node, int depth) +static void bml_print_node(bml_node &node, int depth) { int i; - if (!node) - return; - for (i = 0; i < depth * 2; i++) { printf (" "); } - if (node->name) - printf ("%s", node->name); + if (!node.name.empty()) + printf ("%s", node.name.c_str()); - if (node->data) + if (!node.data.empty()) { - if (contains_space (node->data)) - printf ("=\"%s\"", node->data); + if (contains_space(node.data.c_str())) + printf ("=\"%s\"", node.data.c_str()); 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); - if (node->child[i]->data) + printf (" %s", node.child[i].name.c_str()); + if (!node.child[i].data.empty()) { - if (contains_space (node->child[i]->data)) - printf ("=\"%s\"", node->child[i]->data); + if (contains_space(node.child[i].data.c_str())) + printf ("=\"%s\"", node.child[i].data.c_str()); else - printf ("=%s", node->child[i]->data); + printf ("=%s", node.child[i].data.c_str()); } } } @@ -265,124 +236,97 @@ static void bml_print_node (bml_node *node, int depth) if (depth >= 0) 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) 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; - 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_name (node, &line); - bml_parse_data (node, &line); - bml_parse_attr (node, &line); + bml_parse_depth(node, &line); + bml_parse_name(node, &line); + bml_parse_data(node, &line); + bml_parse_attr(node, &line); } else - return NULL; + return node; - bml_skip_empty (doc); - while (*doc && (int) bml_read_depth (*doc) > node->depth) + bml_skip_empty(doc); + 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) - node->child.push_back (child); + if (child.depth != -1) + node.child.push_back(child); - bml_skip_empty (doc); + bml_skip_empty(doc); } return node; } -void bml_free_node (bml_node *node) +void bml_node::parse(char *doc) { - delete[] (node->name); - delete[] (node->data); + bml_node node; + 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]); - delete node->child[i]; + child.push_back(node); } return; } -bml_node *bml_parse (char **doc) -{ - 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) +bml_node *bml_node::find_subnode (std::string name) { 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)) - return n->child[i]; + if (name.compare(child[i].name) == 0) + return &child[i]; } return NULL; } -bml_node *bml_parse_file (const char *filename) +bool bml_node::parse_file(const char *filename) { FILE *file = NULL; char *buffer = NULL; int file_size = 0; - bml_node *node = NULL; - file = fopen (filename, "rb"); + file = fopen(filename, "rb"); if (!file) - return NULL; + return false; - fseek (file, 0, SEEK_END); - file_size = ftell (file); - fseek (file, 0, SEEK_SET); + fseek(file, 0, SEEK_END); + file_size = ftell(file); + fseek(file, 0, SEEK_SET); buffer = new char[file_size + 1]; - fread (buffer, file_size, 1, file); + fread(buffer, file_size, 1, file); buffer[file_size] = '\0'; + fclose(file); - fclose (file); - - node = bml_parse (&buffer); + parse(buffer); delete[] buffer; - return node; + return true; } diff --git a/bml.h b/bml.h index 65b34d96c..d1dd5c3df 100644 --- a/bml.h +++ b/bml.h @@ -1,31 +1,23 @@ #ifndef __BML_H #define __BML_H #include +#include const int bml_attr_type = -2; -typedef struct bml_node +struct bml_node { - char *name; - char *data; - + bml_node(); + 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; - - std::vector 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 *); + std::vector child; +}; #endif diff --git a/cheats.h b/cheats.h index 9171c3c69..5ca819b1d 100644 --- a/cheats.h +++ b/cheats.h @@ -86,7 +86,7 @@ void S9xUpdateCheatsInMemory (void); int S9xImportCheatsFromDatabase(const char *filename); void S9xCheatsDisable (void); void S9xCheatsEnable (void); -char *S9xCheatValidate (char *cheat); +char *S9xCheatValidate (const char *cheat); void S9xInitCheatData (void); void S9xInitWatchedAddress (void); diff --git a/cheats2.cpp b/cheats2.cpp index 0ff7fef9a..8b5ac9ac3 100644 --- a/cheats2.cpp +++ b/cheats2.cpp @@ -493,7 +493,7 @@ char *S9xCheatGroupToText (SCheatGroup *g) return strdup (text.c_str ()); } -char *S9xCheatValidate (char *code_string) +char *S9xCheatValidate (const char *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; @@ -564,26 +564,26 @@ static void S9xLoadCheatsFromBMLNode (bml_node *n) 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; - char *code = NULL; + const char *desc = NULL; + const char *code = NULL; bool8 enabled = false; - bml_node *c = n->child[i]; + bml_node *c = &n->child[i]; bml_node *tmp = NULL; - tmp = bml_find_sub(c, "name"); + tmp = c->find_subnode("name"); if (!tmp) desc = (char *) ""; else - desc = tmp->data; + desc = tmp->data.c_str(); - tmp = bml_find_sub(c, "code"); + tmp = c->find_subnode("code"); if (tmp) - code = tmp->data; + code = tmp->data.c_str(); - if (bml_find_sub(c, "enable")) + if (c->find_subnode("enable")) enabled = true; if (code && !S9xCheatIsDuplicate (desc, code)) @@ -633,23 +633,18 @@ static bool8 S9xLoadCheatFileClassic (const char *filename) bool8 S9xLoadCheatFile (const char *filename) { - bml_node *bml = NULL; - bml_node *n = NULL; - - bml = bml_parse_file (filename); - if (!bml) + bml_node bml; + if (!bml.parse_file(filename)) { return S9xLoadCheatFileClassic (filename); } - n = bml_find_sub (bml, "cheat"); + bml_node *n = bml.find_subnode("cheat"); if (n) { - S9xLoadCheatsFromBMLNode (bml); + S9xLoadCheatsFromBMLNode (&bml); } - bml_free_node (bml); - if (!n) { return S9xLoadCheatFileClassic (filename); @@ -687,7 +682,7 @@ bool8 S9xSaveCheatFile (const char *filename) txt, Cheat.g[i].enabled ? " enable\n" : "" ); - + delete[] txt; } @@ -736,15 +731,13 @@ void S9xCheatsEnable (void) int S9xImportCheatsFromDatabase (const char *filename) { - bml_node *bml; char sha256_txt[65]; char hextable[] = "0123456789abcdef"; unsigned int i; - bml = bml_parse_file (filename); - - if (!bml) - return -1; /* No file */ + bml_node bml; + if (!bml.parse_file(filename)) + return -1; // No file for (i = 0; i < 32; i++) { @@ -753,25 +746,22 @@ int S9xImportCheatsFromDatabase (const char *filename) } 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; - 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]); - bml_free_node (bml); + S9xLoadCheatsFromBMLNode (&bml.child[i]); return 0; } } } } - bml_free_node (bml); - return -2; /* No codes */ }