You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CFGFileParser.cpp 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // ©2008-2017 despair <despair@netrunner.cc>
  2. #include "CFGFileParser.h"
  3. #include <climits>
  4. #include "slre.h"
  5. CFGFileParser::CFGFileParser(const char* filename){
  6. // Open the config file, get its size,
  7. // allocate the buffer, read it into
  8. // the buffer, close the file
  9. cfg_file = fopen(filename, "rb"); // On NT, opening in text mode translates \n into \r\n
  10. stat(filename, cfg_fileinfo);
  11. buffer = static_cast<char*>(tlsf_malloc(cfg_fileinfo->st_size & INT_MAX));
  12. bytesRead = fread(buffer, sizeof(char) & INT_MAX, cfg_fileinfo->st_size & INT_MAX, cfg_file);
  13. if (!bytesRead) {
  14. std::cout << "no config" << std::endl;
  15. }
  16. fclose(cfg_file);
  17. }
  18. CFGFileParser::CFGFileParser(ntr::fast_string in_buf){
  19. buffer = static_cast<char*>(tlsf_malloc(strlen(in_buf.c_str()) & INT_MAX));
  20. strcpy(buffer, in_buf.c_str());
  21. }
  22. CFGFileParser::~CFGFileParser(){
  23. // clean up!
  24. // This buffer has been written to and co-opted by
  25. // libc itself, but it stands that we initially allocated
  26. // it. So we'll free it ourselves.
  27. tlsf_free(buffer);
  28. // We've already copied the collected config directives
  29. // into a global class, we can safely delete the scratch
  30. // object, and its file info block.
  31. tlsf_free(cfg_fileinfo);
  32. delete cfg;
  33. }
  34. bool CFGFileParser::ParseText() {
  35. // Initial buffer for pass 1. tmp holds the config file (fmr. buffer)
  36. // token holds the actual token. pass1_length to keep track of memory,
  37. // reallocate as needed.
  38. char *tmp, *token;
  39. size_t pass1_length = 0;
  40. struct slre regex; // final validation before adding to second-pass buffer
  41. // Second pass. All comments and .tags stripped out. Starts off at 512 bytes, increases if necessary.
  42. char* directives = static_cast<char*>(tlsf_malloc(512));
  43. char* tmp2;
  44. token = strtok_r(buffer, "\n", &tmp);
  45. while (tmp != nullptr) {
  46. if (token[0] == '#' || token[0] == '.' || token[0] == '\n'){ // Comment, Perl directive, or single <LF> found, skip over
  47. token = strtok_r(nullptr, "\n", &tmp);
  48. }
  49. else if (!isalpha(token[0])){ // The leading character is NOT a #, ., <LF>, or a letter. NB: Leading numbers are also invalid.
  50. printf("ERROR: Config file is invalid: ");
  51. printf("\"%s\"\n",token);
  52. return false;
  53. }
  54. else {
  55. if (!slre_compile(&regex, "([A-Z0-9_]*)(:)(\\[.*\\])")){
  56. printf("Internal error.\n");
  57. return false;
  58. }
  59. if (!slre_match(&regex, token, strlen(token), nullptr)){
  60. printf("Invalid directive: \"%s\"\n", token); // regex matches DiReC[_]T[I1]VE:[token], it simply cannot start with a number or symbol.
  61. return false;
  62. }
  63. // Config directive found, add to second-pass buffer
  64. // once we reach the 0.5KB mark, realloc exactly enough to keep going
  65. if (pass1_length >= 512){
  66. tlsf_realloc(directives, pass1_length+strlen(token)+2);
  67. }
  68. strcat(directives, token);
  69. strcat(directives, "\t");
  70. pass1_length = strlen(directives);
  71. token = strtok_r(nullptr, "\n", &tmp); // continue
  72. }
  73. }
  74. // First pass complete, second pass: break up into single directives and <key, value> pairs
  75. token = strtok_r(directives, "\t", &tmp);
  76. ntr::fast_string key, value;
  77. while (tmp != nullptr){
  78. key=strtok_r(token, ":", &tmp2);
  79. value=strtok_r(nullptr, "[]", &tmp2);
  80. // strip ending bracket
  81. cfg->Settings.insert({key,value});
  82. token = strtok_r(nullptr, "\t", &tmp);
  83. }
  84. #ifdef DEBUG
  85. std::cout << "Settings stringmap contains, in no particular order:\n";
  86. for ( auto it = cfg->Settings.begin(); it != cfg->Settings.end(); ++it ){
  87. std::cout << it->first << ":" << it->second << std::endl;
  88. }
  89. std::cout << std::endl;
  90. #endif
  91. // clean up, we're done parsing
  92. tlsf_free(directives);
  93. return true;
  94. }
  95. // Writes the fully parsed configuration to a BrowserConfiguration
  96. // object supplied by the user.
  97. void CFGFileParser::WriteConfig(BrowserConfiguration &config){
  98. config.Settings = cfg->Settings;
  99. }