Configuration_Import_Export.cpp

Go to the documentation of this file.
00001 // $Id: Configuration_Import_Export.cpp 80826 2008-03-04 14:51:23Z wotte $
00002 
00003 #include "ace/Configuration_Import_Export.h"
00004 #include "ace/OS_Errno.h"
00005 #include "ace/OS_NS_stdio.h"
00006 #include "ace/OS_NS_ctype.h"
00007 #include "ace/OS_NS_string.h"
00008 
00009 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00010 
00011 ACE_Config_ImpExp_Base::ACE_Config_ImpExp_Base (ACE_Configuration& config)
00012   : config_ (config)
00013 {
00014 }
00015 
00016 ACE_Config_ImpExp_Base::~ACE_Config_ImpExp_Base (void)
00017 {
00018 }
00019 
00020 ACE_Registry_ImpExp::ACE_Registry_ImpExp (ACE_Configuration& config)
00021     : ACE_Config_ImpExp_Base (config)
00022 {
00023 }
00024 
00025 ACE_Registry_ImpExp::~ACE_Registry_ImpExp (void)
00026 {
00027 }
00028 
00029 // Imports the configuration database from filename.
00030 // No existing data is removed.
00031 int
00032 ACE_Registry_ImpExp::import_config (const ACE_TCHAR* filename)
00033 {
00034   if (0 == filename)
00035     {
00036       errno = EINVAL;
00037       return -1;
00038     }
00039   FILE* in = ACE_OS::fopen (filename, ACE_TEXT ("r"));
00040   if (!in)
00041     return -1;
00042 
00043   u_int buffer_size = 4096;
00044   u_int read_pos = 0;
00045   ACE_TCHAR *buffer = 0;
00046   ACE_NEW_NORETURN (buffer, ACE_TCHAR[buffer_size]);
00047   if (!buffer)
00048     {
00049       ACE_Errno_Guard guard (errno);
00050       (void) ACE_OS::fclose (in);
00051       return -1;
00052     }
00053   ACE_Configuration_Section_Key section;
00054   ACE_TCHAR *end = 0;
00055 
00056   while (ACE_OS::fgets (buffer+read_pos, buffer_size - read_pos, in))
00057     {
00058       // Check if we got all the line.
00059       end = ACE_OS::strrchr (buffer + read_pos,
00060                              ACE_TEXT ('\n')); // look for end of line
00061       if (!end) // we havn't reach the end of the line yet
00062         {
00063           // allocate a new buffer - double size the previous one
00064           ACE_TCHAR *temp_buffer;
00065           ACE_NEW_NORETURN (temp_buffer, ACE_TCHAR[buffer_size * 2]);
00066           if (!temp_buffer)
00067             {
00068               ACE_Errno_Guard guard (errno);
00069               delete [] buffer;
00070               (void) ACE_OS::fclose (in);
00071               return -1;
00072             }
00073 
00074           // copy the beginnning of the line
00075           ACE_OS::memcpy (temp_buffer, buffer, buffer_size);
00076           read_pos = buffer_size - 1;
00077           buffer_size *= 2;
00078           delete [] buffer;
00079           buffer = temp_buffer;
00080           continue;
00081         }
00082       read_pos = 0;
00083 
00084       // Check for a comment
00085       if (buffer[0] == ACE_TEXT (';') || buffer[0] == ACE_TEXT ('#'))
00086         continue;
00087 
00088       if (buffer[0] == ACE_TEXT ('['))
00089         {
00090           // We have a new section here, strip out the section name
00091           end = ACE_OS::strrchr (buffer, ACE_TEXT (']'));
00092           if (!end)
00093             {
00094               ACE_OS::fclose (in);
00095               delete [] buffer;
00096               return -3;
00097             }
00098           *end = 0;
00099 
00100           if (config_.expand_path (config_.root_section (), buffer + 1, section, 1))
00101             {
00102               ACE_OS::fclose (in);
00103               delete [] buffer;
00104               return -3;
00105             }
00106           continue;
00107         }              // end if firs char is a [
00108 
00109       if (buffer[0] == ACE_TEXT ('"'))
00110         {
00111           // we have a value
00112           end = ACE_OS::strchr (buffer+1, '"');
00113           if (!end)  // no closing quote, not a value so just skip it
00114             continue;
00115 
00116           // null terminate the name
00117           *end = 0;
00118           ACE_TCHAR* name = buffer + 1;
00119           end+=2;
00120           // determine the type
00121           if (*end == '\"')
00122             {
00123               // string type
00124               // truncate trailing "
00125               ++end;
00126               ACE_TCHAR* trailing = ACE_OS::strrchr (end, '"');
00127               if (trailing)
00128                 *trailing = 0;
00129               if (config_.set_string_value (section, name, end))
00130                 {
00131                   ACE_OS::fclose (in);
00132                   delete [] buffer;
00133                   return -4;
00134                 }
00135             }
00136           else if (ACE_OS::strncmp (end, ACE_TEXT ("dword:"), 6) == 0)
00137             {
00138               // number type
00139               ACE_TCHAR* endptr = 0;
00140               unsigned long value = ACE_OS::strtoul (end + 6, &endptr, 16);
00141               if (config_.set_integer_value (section, name, value))
00142                 {
00143                   ACE_OS::fclose (in);
00144                   delete [] buffer;
00145                   return -4;
00146                 }
00147             }
00148           else if (ACE_OS::strncmp (end, ACE_TEXT ("hex:"), 4) == 0)
00149             {
00150               // binary type
00151               size_t string_length = ACE_OS::strlen (end + 4);
00152               // divide by 3 to get the actual buffer length
00153               size_t length = string_length / 3;
00154               size_t remaining = length;
00155               u_char* data = 0;
00156               ACE_NEW_RETURN (data,
00157                               u_char[length],
00158                               -1);
00159               u_char* out = data;
00160               ACE_TCHAR* inb = end + 4;
00161               ACE_TCHAR* endptr = 0;
00162               while (remaining)
00163                 {
00164                   u_char charin = (u_char) ACE_OS::strtoul (inb, &endptr, 16);
00165                   *out = charin;
00166                   ++out;
00167                   --remaining;
00168                   inb += 3;
00169                 }
00170               if (config_.set_binary_value (section, name, data, length))
00171                 {
00172                   ACE_OS::fclose (in);
00173                   delete [] data;
00174                   delete [] buffer;
00175                   return -4;
00176                 }
00177               else
00178                 delete [] data;
00179             }
00180           else
00181             {
00182               // invalid type, ignore
00183               continue;
00184             }
00185         }// end if first char is a "
00186       else
00187         {
00188           // if the first character is not a ", [, ;, or # we may be
00189           // processing a file in the old format.
00190           // Try and process the line as such and if it fails,
00191           // return an error
00192           int rc = process_previous_line_format (buffer, section);
00193           if (rc != 0)
00194             {
00195               ACE_OS::fclose (in);
00196               delete [] buffer;
00197               return rc;
00198             }
00199         }             // end if maybe old format
00200     }                 // end while fgets
00201 
00202   if (ferror (in))
00203     {
00204       ACE_OS::fclose (in);
00205       delete [] buffer;
00206       return -1;
00207     }
00208 
00209   ACE_OS::fclose (in);
00210   delete [] buffer;
00211   return 0;
00212 }
00213 
00214 // This method exports the entire configuration database to <filename>.
00215 // Once the file is opened this method calls 'export_section' passing
00216 // the root section.
00217 int
00218 ACE_Registry_ImpExp::export_config (const ACE_TCHAR* filename)
00219 {
00220   if (0 == filename)
00221     {
00222       errno = EINVAL;
00223       return -1;
00224     }
00225   int result = -1;
00226 
00227   FILE* out = ACE_OS::fopen (filename, ACE_TEXT ("w"));
00228   if (out)
00229     {
00230       result = this->export_section (config_.root_section (),
00231                                      ACE_TEXT (""),
00232                                      out);
00233       // The data may have been buffered and will be flush on close,
00234       // so we need to check that the close succeeds.
00235       if (ACE_OS::fclose (out) < 0)
00236         result = -7;
00237     }
00238   return result;
00239 }
00240 
00241 // Method provided by derived classes in order to write one section
00242 // to the file specified.  Called by export_config when exporting
00243 // the entire configuration object.
00244 
00245 int
00246 ACE_Registry_ImpExp::export_section (const ACE_Configuration_Section_Key& section,
00247                                      const ACE_TString& path,
00248                                      FILE* out)
00249 {
00250   // don't export the root
00251   if (path.length ())
00252     {
00253       // Write out the section header
00254       ACE_TString header = ACE_TEXT ("[");
00255       header += path;
00256       header += ACE_TEXT ("]");
00257       header += ACE_TEXT (" \n");
00258       if (ACE_OS::fputs (header.fast_rep (), out) < 0)
00259         return -1;
00260       // Write out each value
00261       int index = 0;
00262       ACE_TString name;
00263       ACE_Configuration::VALUETYPE type;
00264       ACE_TString line;
00265       ACE_TCHAR int_value[32];
00266       ACE_TCHAR bin_value[3];
00267       void* binary_data;
00268       size_t binary_length;
00269       ACE_TString string_value;
00270       while (!config_.enumerate_values (section, index, name, type))
00271         {
00272           line = ACE_TEXT ("\"") + name + ACE_TEXT ("\"=");
00273           switch (type)
00274             {
00275             case ACE_Configuration::INTEGER:
00276               {
00277                 u_int value;
00278                 if (config_.get_integer_value (section, name.fast_rep (), value))
00279                   return -2;
00280                 ACE_OS::sprintf (int_value, ACE_TEXT ("%08x"), value);
00281                 line += ACE_TEXT ("dword:");
00282                 line += int_value;
00283                 break;
00284               }
00285             case ACE_Configuration::STRING:
00286               {
00287                 if (config_.get_string_value (section,
00288                                               name.fast_rep (),
00289                                               string_value))
00290                   return -2;
00291                 line += ACE_TEXT ("\"");
00292                 line += string_value + ACE_TEXT ("\"");
00293                 break;
00294               }
00295 #ifdef _WIN32
00296             case ACE_Configuration::INVALID:
00297               break;  // JDO added break.  Otherwise INVALID is processed
00298               // like BINARY. If that's correct, please remove the
00299               // break and these comments
00300 #endif
00301             case ACE_Configuration::BINARY:
00302               {
00303                 // not supported yet - maybe use BASE64 codeing?
00304                 if (config_.get_binary_value (section,
00305                                               name.fast_rep (),
00306                                               binary_data,
00307                                               binary_length))
00308                   return -2;
00309                 line += ACE_TEXT ("hex:");
00310                 unsigned char* ptr = (unsigned char*)binary_data;
00311                 while (binary_length)
00312                   {
00313                     if (ptr != binary_data)
00314                       {
00315                         line += ACE_TEXT (",");
00316                       }
00317                     ACE_OS::sprintf (bin_value, ACE_TEXT ("%02x"), *ptr);
00318                     line += bin_value;
00319                     --binary_length;
00320                     ++ptr;
00321                   }
00322                 delete [] (char*) binary_data;
00323                 break;
00324               }
00325             default:
00326               return -3;
00327             }
00328           line += ACE_TEXT ("\n");
00329           if (ACE_OS::fputs (line.fast_rep (), out) < 0)
00330             return -4;
00331           ++index;
00332         }
00333     }
00334   // Export all sub sections
00335   int index = 0;
00336   ACE_TString name;
00337   ACE_Configuration_Section_Key sub_key;
00338   ACE_TString sub_section;
00339   while (!config_.enumerate_sections (section, index, name))
00340     {
00341       ACE_TString sub_section (path);
00342       if (path.length ())
00343         sub_section += ACE_TEXT ("\\");
00344       sub_section += name;
00345       if (config_.open_section (section, name.fast_rep (), 0, sub_key))
00346         return -5;
00347       if (export_section (sub_key, sub_section.fast_rep (), out))
00348         return -6;
00349       ++index;
00350     }
00351   return 0;
00352 }
00353 
00354 //
00355 // This method read the line format origionally used in ACE 5.1
00356 //
00357 int
00358 ACE_Registry_ImpExp::process_previous_line_format (ACE_TCHAR* buffer,
00359                                                    ACE_Configuration_Section_Key& section)
00360 {
00361   // Chop any cr/lf at the end of the line.
00362   ACE_TCHAR *endp = ACE_OS::strpbrk (buffer, ACE_TEXT ("\r\n"));
00363   if (endp != 0)
00364     *endp = '\0';
00365 
00366   // assume this is a value, read in the value name
00367   ACE_TCHAR* end = ACE_OS::strchr (buffer, '=');
00368   if (end)  // no =, not a value so just skip it
00369     {
00370       // null terminate the name
00371       *end = 0;
00372       ++end;
00373       // determine the type
00374       if (*end == '\"')
00375         {
00376           // string type
00377           if(config_.set_string_value (section, buffer, end + 1))
00378             return -4;
00379         }
00380       else if (*end == '#')
00381         {
00382           // number type
00383           u_int value = ACE_OS::atoi (end + 1);
00384           if (config_.set_integer_value (section, buffer, value))
00385             return -4;
00386         }
00387     }
00388   return 0;
00389 }                // end read_previous_line_format
00390 
00391 
00392 ACE_Ini_ImpExp::ACE_Ini_ImpExp (ACE_Configuration& config)
00393     : ACE_Config_ImpExp_Base (config)
00394 {
00395 }
00396 
00397 ACE_Ini_ImpExp::~ACE_Ini_ImpExp (void)
00398 {
00399 }
00400 
00401 // Method to read file and populate object.
00402 int
00403 ACE_Ini_ImpExp::import_config (const ACE_TCHAR* filename)
00404 {
00405   if (0 == filename)
00406     {
00407       errno = EINVAL;
00408       return -1;
00409     }
00410   FILE* in = ACE_OS::fopen (filename, ACE_TEXT ("r"));
00411   if (!in)
00412     return -1;
00413 
00414   // @@ Make this a dynamic size!
00415   ACE_TCHAR buffer[4096];
00416   ACE_Configuration_Section_Key section;
00417   while (ACE_OS::fgets (buffer, sizeof buffer, in))
00418     {
00419       ACE_TCHAR *line = this->squish (buffer);
00420       // Check for a comment and blank line
00421       if (line[0] == ACE_TEXT (';')  ||
00422           line[0] == ACE_TEXT ('#')  ||
00423           line[0] == '\0')
00424         continue;
00425 
00426       if (line[0] == ACE_TEXT ('['))
00427         {
00428           // We have a new section here, strip out the section name
00429           ACE_TCHAR* end = ACE_OS::strrchr (line, ACE_TEXT (']'));
00430           if (!end)
00431             {
00432               ACE_OS::fclose (in);
00433               return -3;
00434             }
00435           *end = 0;
00436 
00437           if (config_.expand_path (config_.root_section (),
00438                                    line + 1,
00439                                    section,
00440                                    1))
00441             {
00442               ACE_OS::fclose (in);
00443               return -3;
00444             }
00445 
00446           continue;
00447         }
00448 
00449       // We have a line; name ends at equal sign.
00450       ACE_TCHAR *end = ACE_OS::strchr (line, ACE_TEXT ('='));
00451       if (end == 0)                            // No '='
00452         {
00453           ACE_OS::fclose (in);
00454           return -3;
00455         }
00456       *end++ = '\0';
00457       ACE_TCHAR *name = this->squish (line);
00458 #if 0
00459       if (ACE_OS::strlen (name) == 0)          // No name; just an '='
00460         {
00461           ACE_OS::fclose (in);
00462           return -3;
00463         }
00464 #endif
00465       // Now find the start of the value
00466       ACE_TCHAR *value = this->squish (end);
00467       size_t value_len = ACE_OS::strlen (value);
00468       if (value_len > 0)
00469         {
00470           // ACE 5.2 (and maybe earlier) exported strings may be enclosed
00471           // in quotes. If string is quote-delimited, strip the quotes.
00472           // Newer exported files don't have quote delimiters.
00473           if (value[0] == ACE_TEXT ('"') &&
00474               value[value_len - 1] == ACE_TEXT ('"'))
00475             {
00476               // Strip quotes off both ends.
00477               value[value_len - 1] = '\0';
00478               ++value;
00479             }
00480         }
00481 
00482       if (config_.set_string_value (section, name, value))
00483         {
00484           ACE_OS::fclose (in);
00485           return -4;
00486         }
00487     }             // end while fgets
00488 
00489   if (ferror (in))
00490     {
00491       ACE_OS::fclose (in);
00492       return -1;
00493     }
00494 
00495   ACE_OS::fclose (in);
00496   return 0;
00497 }
00498 
00499 // This method exports the entire configuration database to <filename>.
00500 // Once the file is opened this method calls 'export_section' passing
00501 // the root section.
00502 int
00503 ACE_Ini_ImpExp::export_config (const ACE_TCHAR* filename)
00504 {
00505   if (0 == filename)
00506     {
00507       errno = EINVAL;
00508       return -1;
00509     }
00510   int result = -1;
00511 
00512   FILE* out = ACE_OS::fopen (filename, ACE_TEXT ("w"));
00513   if (out)
00514     {
00515       result = this->export_section (config_.root_section (),
00516                                      ACE_TEXT (""),
00517                                      out);
00518       // The data may have been buffered and will be flush on close,
00519       // so we need to check that the close succeeds.
00520       if (ACE_OS::fclose (out) < 0)
00521         result = -7;
00522     }
00523   return result;
00524 }
00525 
00526 // Method provided by derived classes in order to write one section to the
00527 // file specified.  Called by export_config when exporting the entire
00528 // configuration objet
00529 
00530 int
00531 ACE_Ini_ImpExp::export_section (const ACE_Configuration_Section_Key& section,
00532                                 const ACE_TString& path,
00533                                 FILE* out)
00534 {
00535   // don't export the root
00536   if (path.length ())
00537     {
00538       // Write out the section header
00539       ACE_TString header = ACE_TEXT ("[");
00540       header += path;
00541       header += ACE_TEXT ("]\n");
00542       if (ACE_OS::fputs (header.fast_rep (), out) < 0)
00543         return -1;
00544       // Write out each value
00545       int index = 0;
00546       ACE_TString name;
00547       ACE_Configuration::VALUETYPE type;
00548       ACE_TString line;
00549       ACE_TCHAR int_value[32];
00550       ACE_TCHAR bin_value[3];
00551       void* binary_data;
00552       size_t binary_length;
00553       ACE_TString string_value;
00554       while (!config_.enumerate_values (section, index, name, type))
00555         {
00556           line = name + ACE_TEXT ("=");
00557           switch (type)
00558             {
00559             case ACE_Configuration::INTEGER:
00560               {
00561                 u_int value;
00562                 if (config_.get_integer_value (section, name.fast_rep (), value))
00563                   return -2;
00564                 ACE_OS::sprintf (int_value, ACE_TEXT ("%08x"), value);
00565                 line += int_value;
00566                 break;
00567               }
00568             case ACE_Configuration::STRING:
00569               {
00570                 if (config_.get_string_value (section,
00571                                               name.fast_rep (),
00572                                               string_value))
00573                   return -2;
00574                 line += string_value;
00575                 break;
00576               }
00577 #ifdef _WIN32
00578             case ACE_Configuration::INVALID:
00579               break;  // JDO added break.  Otherwise INVALID is processed
00580               // like BINARY. If that's correct, please remove the
00581               // break and these comments
00582 #endif
00583             case ACE_Configuration::BINARY:
00584               {
00585                 // not supported yet - maybe use BASE64 codeing?
00586                 if (config_.get_binary_value (section,
00587                                               name.fast_rep (),
00588                                               binary_data,
00589                                               binary_length))
00590                   return -2;
00591                 line += ACE_TEXT ("\"");
00592                 unsigned char* ptr = (unsigned char*)binary_data;
00593                 while (binary_length)
00594                   {
00595                     if (ptr != binary_data)
00596                       {
00597                         line += ACE_TEXT (",");
00598                       }
00599                     ACE_OS::sprintf (bin_value, ACE_TEXT ("%02x"), *ptr);
00600                     line += bin_value;
00601                     --binary_length;
00602                     ++ptr;
00603                   }
00604                 line += ACE_TEXT ("\"");
00605                 delete [] (char *) binary_data;
00606                 break;
00607               }
00608             default:
00609               return -3;
00610 
00611             }// end switch on type
00612 
00613           line += ACE_TEXT ("\n");
00614           if (ACE_OS::fputs (line.fast_rep (), out) < 0)
00615             return -4;
00616           ++index;
00617         }// end while enumerating values
00618     }
00619   // Export all sub sections
00620   int index = 0;
00621   ACE_TString name;
00622   ACE_Configuration_Section_Key sub_key;
00623   ACE_TString sub_section;
00624   while (!config_.enumerate_sections (section, index, name))
00625     {
00626       ACE_TString sub_section (path);
00627       if (path.length ())
00628         sub_section += ACE_TEXT ("\\");
00629       sub_section += name;
00630       if (config_.open_section (section, name.fast_rep (), 0, sub_key))
00631         return -5;
00632       if (export_section (sub_key, sub_section.fast_rep (), out))
00633         return -6;
00634       ++index;
00635     }
00636   return 0;
00637 
00638 }
00639 
00640 // Method to squish leading and trailing whitespaces from a string.
00641 // Whitespace is defined as: spaces (' '), tabs ('\t') or end-of-line
00642 // (cr/lf).  The terminating nul is moved up to expunge trailing
00643 // whitespace and the returned pointer points at the first
00644 // non-whitespace character in the string, which may be the nul
00645 // terminator if the string is all whitespace.
00646 
00647 ACE_TCHAR *
00648 ACE_Ini_ImpExp::squish (ACE_TCHAR *src)
00649 {
00650   ACE_TCHAR *cp = 0;
00651 
00652   if (src == 0)
00653     return 0;
00654 
00655   // Start at the end and work backwards over all whitespace.
00656   for (cp = src + ACE_OS::strlen (src) - 1;
00657        cp != src;
00658        --cp)
00659     if (!ACE_OS::ace_isspace (*cp))
00660       break;
00661   cp[1] = '\0';          // Chop trailing whitespace
00662 
00663   // Now start at the beginning and move over all whitespace.
00664   for (cp = src; ACE_OS::ace_isspace (*cp); ++cp)
00665     continue;
00666 
00667   return cp;
00668 }
00669 
00670 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Tue Feb 2 17:18:38 2010 for ACE by  doxygen 1.4.7