Panda3D
 All Classes Functions Variables Enumerations
configPage.cxx
00001 // Filename: configPage.cxx
00002 // Created by:  drose (15Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "configPage.h"
00016 #include "configDeclaration.h"
00017 #include "configVariableCore.h"
00018 #include "configVariableManager.h"
00019 #include "prcKeyRegistry.h"
00020 #include "config_prc.h"
00021 #include "encryptStream.h"
00022 
00023 #include <ctype.h>
00024 
00025 #ifdef HAVE_OPENSSL
00026 #include "openssl/evp.h"
00027 #endif
00028 
00029 ConfigPage *ConfigPage::_default_page = NULL;
00030 ConfigPage *ConfigPage::_local_page = NULL;
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: ConfigPage::Constructor
00034 //       Access: Private
00035 //  Description: The constructor is private because a ConfigPage
00036 //               should be constructed via the ConfigPageManager
00037 //               make_page() interface.
00038 ////////////////////////////////////////////////////////////////////
00039 ConfigPage::
00040 ConfigPage(const string &name, bool implicit_load, int page_seq) :
00041   _name(name),
00042   _implicit_load(implicit_load),
00043   _page_seq(page_seq),
00044   _sort(implicit_load ? 10 : 0),
00045   _next_decl_seq(1),
00046   _trust_level(0)
00047 {
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: ConfigPage::Destructor
00052 //       Access: Private
00053 //  Description: The destructor is private because a ConfigPage
00054 //               should be deleted via the ConfigPageManager
00055 //               delete_page() interface.
00056 ////////////////////////////////////////////////////////////////////
00057 ConfigPage::
00058 ~ConfigPage() {
00059   clear();
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: ConfigPage::get_default_page
00064 //       Access: Published, Static
00065 //  Description: Returns a pointer to the global "default page".  This
00066 //               is the ConfigPage that lists all variables' original
00067 //               default values.
00068 ////////////////////////////////////////////////////////////////////
00069 ConfigPage *ConfigPage::
00070 get_default_page() {
00071   if (_default_page == (ConfigPage *)NULL) {
00072     _default_page = new ConfigPage("default", false, 0);
00073   }
00074   return _default_page;
00075 }
00076 
00077 ////////////////////////////////////////////////////////////////////
00078 //     Function: ConfigPage::get_local_page
00079 //       Access: Published, Static
00080 //  Description: Returns a pointer to the global "local page".  This
00081 //               is the ConfigPage that lists the locally-assigned
00082 //               values for any variables in the world that have such
00083 //               a local assignment.
00084 ////////////////////////////////////////////////////////////////////
00085 ConfigPage *ConfigPage::
00086 get_local_page() {
00087   if (_local_page == (ConfigPage *)NULL) {
00088     _local_page = new ConfigPage("local", false, 0);
00089   }
00090   return _local_page;
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: ConfigPage::set_sort
00095 //       Access: Published
00096 //  Description: Changes the explicit sort order of this particular
00097 //               ConfigPage.  Lower-numbered pages supercede
00098 //               higher-numbered pages.  Initially, all
00099 //               explicitly-loaded pages have sort value 0, and
00100 //               implicitly-loaded pages (found on disk) have sort
00101 //               value 10; you may set an individual page higher or
00102 //               lower to influence its priority relative to other
00103 //               pages.
00104 ////////////////////////////////////////////////////////////////////
00105 void ConfigPage::
00106 set_sort(int sort) {
00107   if (_sort != sort) {
00108     _sort = sort;
00109     ConfigPageManager::get_global_ptr()->mark_unsorted();
00110   }
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: ConfigPage::clear
00115 //       Access: Published
00116 //  Description: Removes all of the declarations from the page.
00117 ////////////////////////////////////////////////////////////////////
00118 void ConfigPage::
00119 clear() {
00120   Declarations::iterator di;
00121   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00122     ConfigDeclaration *decl = (*di);
00123     delete decl;
00124   }
00125   _declarations.clear();
00126   _trust_level = 0;
00127   _signature = string();
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: ConfigPage::read_prc
00132 //       Access: Published
00133 //  Description: Reads the contents of a complete prc file, as
00134 //               returned by the indicated istream, into the current
00135 //               page file.  Returns true on success, or false on some
00136 //               I/O error.
00137 //
00138 //               This is a low-level interface.  Normally you do not
00139 //               need to call it directly.  See the global functions
00140 //               load_prc_file() and unload_prc_file(), defined in
00141 //               panda/src/putil, for a higher-level interface.
00142 ////////////////////////////////////////////////////////////////////
00143 bool ConfigPage::
00144 read_prc(istream &in) {
00145   // We must empty the page before we start to read it; otherwise
00146   // trust level is meaningless.
00147   clear();
00148 
00149   // We avoid getline() here because of its notorious problem with
00150   // last lines that lack a trailing newline character.
00151   static const size_t buffer_size = 1024;
00152   char buffer[buffer_size];
00153 
00154 #ifdef HAVE_OPENSSL
00155   // Set up the evp context for verifying the signature, if we find
00156   // one.
00157 #ifdef SSL_097
00158   _md_ctx = EVP_MD_CTX_create();
00159 #else
00160   _md_ctx = new EVP_MD_CTX;
00161 #endif
00162   EVP_VerifyInit((EVP_MD_CTX *)_md_ctx, EVP_sha1());
00163 #endif  // HAVE_OPENSSL
00164 
00165   string prev_line;
00166 
00167   in.read(buffer, buffer_size);
00168   size_t count = in.gcount();
00169   while (count != 0) {
00170     char *buffer_end = buffer + count;
00171 
00172     // Look for the first line in the buffer..
00173     char *newline = (char *)memchr((void *)buffer, '\n', count);
00174     if (newline == (char *)NULL) {
00175       // The buffer was one long line.  Huh.
00176       prev_line += string(buffer, count);
00177 
00178     } else {
00179       // Process the first line in the buffer.
00180       size_t length = newline - buffer;
00181       read_prc_line(prev_line + string(buffer, length + 1));
00182 
00183       // Now look for the next line, etc.
00184       char *start = newline + 1;
00185       newline = (char *)memchr((void *)start, '\n', buffer_end - start);
00186       while (newline != (char *)NULL) {
00187         length = newline - start;
00188         read_prc_line(string(start, length + 1));
00189         start = newline + 1;
00190         newline = (char *)memchr((void *)start, '\n', buffer_end - start);
00191       }
00192 
00193       // The remaining text in the buffer is the start of the next
00194       // line.
00195       length = buffer_end - start;
00196       prev_line = string(start, length);
00197     }
00198 
00199     if (in.fail() || in.eof()) {
00200       // If we got a failure reading the buffer last time, don't keep
00201       // reading again.  Irix seems to require this test; otherwise,
00202       // it repeatedly returns the same text at the end of the file.
00203       count = 0;
00204 
00205     } else {
00206       in.read(buffer, buffer_size);
00207       count = in.gcount();
00208     }
00209   }
00210 
00211   if (!prev_line.empty()) {
00212     read_prc_line(prev_line);
00213   }
00214 
00215 #ifdef HAVE_OPENSSL
00216   // Now validate the signature and free the SSL structures.
00217   if (!_signature.empty()) {
00218     PrcKeyRegistry *pkr = PrcKeyRegistry::get_global_ptr();
00219     int num_keys = pkr->get_num_keys();
00220     for (int i = 1; i < num_keys && _trust_level == 0; i++) {
00221       EVP_PKEY *pkey = pkr->get_key(i);
00222       if (pkey != (EVP_PKEY *)NULL) {
00223         int verify_result = 
00224           EVP_VerifyFinal((EVP_MD_CTX *)_md_ctx, 
00225                           (unsigned char *)_signature.data(), 
00226                           _signature.size(), pkey);
00227         if (verify_result == 1) {
00228           _trust_level = i;
00229         }
00230       }
00231     }
00232     if (_trust_level == 0) {
00233       prc_cat->info() 
00234         << "invalid signature found in " << get_name() << "\n";
00235     }
00236   }
00237 #ifdef SSL_097
00238   EVP_MD_CTX_destroy((EVP_MD_CTX *)_md_ctx);
00239 #else
00240   delete (EVP_MD_CTX *)_md_ctx;
00241 #endif
00242 #endif  // HAVE_OPENSSL
00243 
00244   bool failed = (in.fail() && !in.eof());
00245 
00246   return !failed;
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: ConfigPage::read_encrypted_prc
00251 //       Access: Published
00252 //  Description: Automatically decrypts and reads the stream, given
00253 //               the indicated password.  Note that if the password is
00254 //               incorrect, the result may be garbage.
00255 ////////////////////////////////////////////////////////////////////
00256 bool ConfigPage::
00257 read_encrypted_prc(istream &in, const string &password) {
00258 #ifdef HAVE_OPENSSL
00259   IDecryptStream decrypt(&in, false, password);
00260   return read_prc(decrypt);
00261 #else
00262   return false;
00263 #endif  // HAVE_OPENSSL
00264 }
00265 
00266 ////////////////////////////////////////////////////////////////////
00267 //     Function: ConfigPage::make_declaration
00268 //       Access: Published
00269 //  Description: Adds the indicated variable/value pair as a new
00270 //               declaration on the page.
00271 ////////////////////////////////////////////////////////////////////
00272 ConfigDeclaration *ConfigPage::
00273 make_declaration(const string &variable, const string &value) {
00274   ConfigVariableManager *variable_mgr = ConfigVariableManager::get_global_ptr();
00275   return make_declaration(variable_mgr->make_variable(variable), value);
00276 }
00277 
00278 ////////////////////////////////////////////////////////////////////
00279 //     Function: ConfigPage::make_declaration
00280 //       Access: Published
00281 //  Description: Adds the indicated variable/value pair as a new
00282 //               declaration on the page.
00283 ////////////////////////////////////////////////////////////////////
00284 ConfigDeclaration *ConfigPage::
00285 make_declaration(ConfigVariableCore *variable, const string &value) {
00286   ConfigDeclaration *decl = new ConfigDeclaration
00287     (this, variable, value, _next_decl_seq);
00288   _next_decl_seq++;
00289 
00290   _declarations.push_back(decl);
00291   make_dirty();
00292 
00293   return decl;
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: ConfigPage::delete_declaration
00298 //       Access: Published
00299 //  Description: Removes the indicated declaration from the page and
00300 //               deletes it.  Returns true if the declaration is
00301 //               successfully removed, false if it was not on the
00302 //               page.
00303 ////////////////////////////////////////////////////////////////////
00304 bool ConfigPage::
00305 delete_declaration(ConfigDeclaration *decl) {
00306   Declarations::iterator di;
00307   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00308     if ((*di) == decl) {
00309       _declarations.erase(di);
00310       delete decl;
00311       make_dirty();
00312       return true;
00313     }
00314   }
00315 
00316   return false;
00317 }
00318 
00319 ////////////////////////////////////////////////////////////////////
00320 //     Function: ConfigPage::get_num_declarations
00321 //       Access: Published
00322 //  Description: Returns the number of declarations on the page.
00323 ////////////////////////////////////////////////////////////////////
00324 int ConfigPage::
00325 get_num_declarations() const {
00326   return _declarations.size();
00327 }
00328 
00329 ////////////////////////////////////////////////////////////////////
00330 //     Function: ConfigPage::get_declaration
00331 //       Access: Published
00332 //  Description: Returns the nth declaration on the page.
00333 ////////////////////////////////////////////////////////////////////
00334 const ConfigDeclaration *ConfigPage::
00335 get_declaration(int n) const {
00336   nassertr(n >= 0 && n < (int)_declarations.size(), (ConfigDeclaration *)NULL);
00337   return _declarations[n];
00338 }
00339 
00340 ////////////////////////////////////////////////////////////////////
00341 //     Function: ConfigPage::modify_declaration
00342 //       Access: Published
00343 //  Description: Returns a modifiable pointer to the nth declaration
00344 //               on the page.  Any modifications will appear in the
00345 //               output, if the page is written out with
00346 //               ConfigPage::write().
00347 ////////////////////////////////////////////////////////////////////
00348 ConfigDeclaration *ConfigPage::
00349 modify_declaration(int n) {
00350   nassertr(n >= 0 && n < (int)_declarations.size(), (ConfigDeclaration *)NULL);
00351   return _declarations[n];
00352 }
00353 
00354 ////////////////////////////////////////////////////////////////////
00355 //     Function: ConfigPage::get_variable_name
00356 //       Access: Published
00357 //  Description: Returns the variable named by the nth declaration on
00358 //               the page.
00359 ////////////////////////////////////////////////////////////////////
00360 string ConfigPage::
00361 get_variable_name(int n) const {
00362   nassertr(n >= 0 && n < (int)_declarations.size(), string());
00363   return _declarations[n]->get_variable()->get_name();
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: ConfigPage::get_string_value
00368 //       Access: Published
00369 //  Description: Returns the value assigned by the nth declaration on
00370 //               the page.
00371 ////////////////////////////////////////////////////////////////////
00372 string ConfigPage::
00373 get_string_value(int n) const {
00374   nassertr(n >= 0 && n < (int)_declarations.size(), string());
00375   return _declarations[n]->get_string_value();
00376 }
00377 
00378 ////////////////////////////////////////////////////////////////////
00379 //     Function: ConfigPage::is_variable_used
00380 //       Access: Published
00381 //  Description: Returns true if the nth active variable on
00382 //               the page has been used by code, false otherwise.
00383 ////////////////////////////////////////////////////////////////////
00384 bool ConfigPage::
00385 is_variable_used(int n) const {
00386   nassertr(n >= 0 && n < (int)_declarations.size(), false);
00387   return _declarations[n]->get_variable()->is_used();
00388 }
00389 
00390 ////////////////////////////////////////////////////////////////////
00391 //     Function: ConfigPage::output
00392 //       Access: Published
00393 //  Description: 
00394 ////////////////////////////////////////////////////////////////////
00395 void ConfigPage::
00396 output(ostream &out) const {
00397   out << "ConfigPage " << get_name() << ", " << get_num_declarations()
00398       << " declarations.";
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: ConfigPage::output_brief_signature
00403 //       Access: Published
00404 //  Description: Outputs the first few hex digits of the signature.
00405 ////////////////////////////////////////////////////////////////////
00406 void ConfigPage::
00407 output_brief_signature(ostream &out) const {
00408   size_t num_bytes = min(_signature.size(), (size_t)8);
00409   for (size_t p = 0; p < num_bytes; ++p) {
00410     unsigned int byte = _signature[p];
00411 
00412     unsigned int hi = (byte >> 4) & 0xf;
00413     if (hi >= 10) {
00414       out << (char)((hi - 10) + 'a');
00415     } else {
00416       out << (char)(hi + '0');
00417     }
00418 
00419     unsigned int lo = byte & 0xf;
00420     if (lo >= 10) {
00421       out << (char)((lo - 10) + 'a');
00422     } else {
00423       out << (char)(lo + '0');
00424     }
00425   }
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: ConfigPage::write
00430 //       Access: Published
00431 //  Description: 
00432 ////////////////////////////////////////////////////////////////////
00433 void ConfigPage::
00434 write(ostream &out) const {
00435   Declarations::const_iterator di;
00436   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00437     (*di)->write(out);
00438   }
00439 }
00440 
00441 ////////////////////////////////////////////////////////////////////
00442 //     Function: ConfigPage::read_prc_line
00443 //       Access: Private
00444 //  Description: Handles reading in a single line from a .prc file.
00445 //               This is called internally by read_prc() for each
00446 //               line.
00447 ////////////////////////////////////////////////////////////////////
00448 void ConfigPage::
00449 read_prc_line(const string &line) {
00450   if (line.substr(0, 7) == "##!sig ") {
00451     // This is a signature.  Accumulate it into the signature and
00452     // return, and don't count it as contributing to the hash.
00453     for (size_t p = 7; p < line.length() - 1; p += 2) {
00454       unsigned char digit = (hex_digit(line[p]) << 4) | hex_digit(line[p + 1]);
00455       _signature += digit;
00456     }
00457     return;
00458   }
00459 
00460 #ifdef HAVE_OPENSSL
00461   // Accumulate any line that's not itself a signature into the hash,
00462   // so we can validate the signature at the end.
00463   EVP_VerifyUpdate((EVP_MD_CTX *)_md_ctx, line.data(), line.size());
00464 #endif  // HAVE_OPENSSL
00465 
00466   // Separate the line into a variable and a value.
00467   size_t p = 0;
00468   while (p < line.length() && isspace((unsigned char)line[p])) {
00469     p++;
00470   }
00471 
00472   if (p == line.length() || line[p] == '#') {
00473     // Blank line or comment; do nothing.
00474     return;
00475   }
00476 
00477   size_t variable_begin = p;
00478   while (p < line.length() && !isspace((unsigned char)line[p])) {
00479     p++;
00480   }
00481   size_t variable_end = p;
00482 
00483   while (p < line.length() && isspace((unsigned char)line[p])) {
00484     p++;
00485   }
00486   size_t value_begin = p;
00487 
00488   // Is there an embedded comment on this line?
00489   p = line.find(" #", value_begin);
00490   if (p == string::npos) {
00491     // No, the value extends all the way to the end of the line.
00492     p = line.length();
00493   }
00494 
00495   // The value extends from here to the end of the line (or to the
00496   // start of the embedded comment), so trim whitespace backwards off
00497   // from there.
00498   while (p > value_begin && isspace((unsigned char)line[p - 1])) {
00499     p--;
00500   }
00501   size_t value_end = p;
00502 
00503   string variable = line.substr(variable_begin, variable_end - variable_begin);
00504   string value = line.substr(value_begin, value_end - value_begin);
00505 
00506   make_declaration(variable, value);
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: ConfigPage::hex_digit
00511 //       Access: Private, Static
00512 //  Description: Decodes a hex digit into its numeric value.
00513 ////////////////////////////////////////////////////////////////////
00514 unsigned int ConfigPage::
00515 hex_digit(unsigned char digit) {
00516   if (isalpha(digit)) {
00517     return tolower(digit) - 'a' + 10;
00518   } else if (isdigit(digit)) {
00519     return digit - '0';
00520   } else {
00521     return 0;
00522   }
00523 }
 All Classes Functions Variables Enumerations