// ©2008-2017 despair #include "CFGFileParser.h" #include #include "slre.h" CFGFileParser::CFGFileParser(const char* filename){ // Open the config file, get its size, // allocate the buffer, read it into // the buffer, close the file cfg_file = fopen(filename, "rb"); // On NT, opening in text mode translates \n into \r\n stat(filename, cfg_fileinfo); buffer = static_cast(tlsf_malloc(cfg_fileinfo->st_size & INT_MAX, sizeof(char) & INT_MAX)); cfg = new BrowserConfiguration(); bytesRead = fread(buffer, sizeof(char) & INT_MAX, cfg_fileinfo->st_size & INT_MAX, cfg_file); if (!bytesRead) { std::cout << "no config" << std::endl; } fclose(cfg_file); } CFGFileParser::~CFGFileParser(){ // clean up! // This buffer has been written to and co-opted by // libc itself, but it stands that we initially allocated // it. So we'll free it ourselves. tlsf_free(buffer); // We've already copied the collected config directives // into a global class, we can safely delete the scratch // object, and its file info block. tlsf_free(cfg_fileinfo); delete cfg; } bool CFGFileParser::ParseText() { // Initial buffer for pass 1. tmp holds the config file (fmr. buffer) // token holds the actual token. pass1_length to keep track of memory, // reallocate as needed. char *tmp, *token; size_t pass1_length = 0; struct slre regex; // final validation before adding to second-pass buffer // Second pass. All comments and .tags stripped out. Starts off at 512 bytes, increases if necessary. char* directives = static_cast(tlsf_malloc(512, sizeof(char))); char* tmp2; token = strtok_r(buffer, "\n", &tmp); while (tmp != nullptr) { if (token[0] == '#' || token[0] == '.' || token[0] == '\n'){ // Comment, Perl directive, or single found, skip over token = strtok_r(nullptr, "\n", &tmp); } else if (!isalpha(token[0])){ // The leading character is NOT a #, ., , or a letter. NB: Leading numbers are also invalid. printf("ERROR: Config file is invalid\n"); printf("%s\n",token); return false; } else { if (!slre_compile(®ex, "([A-Z0-9_]*)(:)(\\[.*\\])")){ printf("Internal error.\n"); return false; } if (!slre_match(®ex, token, strlen(token), nullptr)){ printf("Invalid directive: %s\n", token); // regex matches DIREC[_]T[I1]VE:[token] but NOT directive:[token] - the directive MUST be all caps return false; } // Config directive found, add to second-pass buffer // once we reach the 0.5KB mark, realloc exactly enough to keep going if (pass1_length >= 512){ tlsf_realloc(directives, pass1_length+strlen(token)+2); } strcat(directives, token); strcat(directives, "\t"); pass1_length = strlen(directives); token = strtok_r(nullptr, "\n", &tmp); // continue } } // First pass complete, second pass: break up into single directives and pairs token = strtok_r(directives, "\t", &tmp); ntr::fast_string key, value; while (tmp != nullptr){ key=strtok_r(token, ":", &tmp2); value=strtok_r(nullptr, "[]", &tmp2); // strip ending bracket cfg->Settings.insert({key,value}); token = strtok_r(nullptr, "\t", &tmp); } #ifdef DEBUG std::cout << "Settings stringmap contains, in no particular order:\n"; for ( auto it = cfg->Settings.begin(); it != cfg->Settings.end(); ++it ){ std::cout << it->first << ":" << it->second << std::endl; } std::cout << std::endl; #endif // clean up, we're done parsing tlsf_free(directives); return true; } // Writes the fully parsed configuration to a BrowserConfiguration // object supplied by the user. void CFGFileParser::WriteConfig(BrowserConfiguration &config){ config.Settings = cfg->Settings; }