VirtualBox

Changeset 76167 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 11, 2018 5:03:05 PM (6 years ago)
Author:
vboxsync
Message:

Main: Split out the two text script classes from UnattendedScript since they are now used separately from unattended installation. bugref:9152

Location:
trunk/src/VBox/Main
Files:
3 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r76165 r76167  
    485485        src-server/UnattendedInstaller.cpp \
    486486        src-server/UnattendedScript.cpp \
     487        src-all/TextScript.cpp \
    487488        ,) \
    488489        src-server/USBControllerImpl.cpp \
  • trunk/src/VBox/Main/include/TextScript.h

    r76159 r76167  
    11/* $Id$ */
    22/** @file
    3  * Implementeation of algorithms which read/parse/save scripts for unattended installation.
     3 * Classes for reading/parsing/saving text scripts (unattended installation, ++).
    44 */
    55
     
    1616 */
    1717
    18 #ifndef ____H_UNATTENDEDSCRIPT
    19 #define ____H_UNATTENDEDSCRIPT
     18#ifndef ____H_TEXTSCRIPT
     19#define ____H_TEXTSCRIPT
    2020
    2121#include "VirtualBoxBase.h"
     
    2323#include <vector>
    2424
    25 using namespace xml;
    26 
    27 class Unattended;
    28 
    2925
    3026/**
    3127 * Base class for all the script readers/editors.
    3228 *
    33  * @todo get rid of this bugger
     29 * @todo get rid of this silly bugger.
    3430 */
    3531class AbstractScript : public RTCNonCopyable
     
    152148
    153149/**
    154  * Generic unattended text script template editor.
    155  *
    156  * This just perform variable replacements, no other editing possible.
    157  *
    158  * Everything happens during saveToString, parse is a noop.
    159  */
    160 class UnattendedScriptTemplate : public BaseTextScript
    161 {
    162 protected:
    163     /** Where to get the replacement strings from. */
    164     Unattended *mpUnattended;
    165 
    166 public:
    167     UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename, const char *pszDefaultFilename);
    168     virtual ~UnattendedScriptTemplate()             {}
    169 
    170     HRESULT parse()                                 { return S_OK; }
    171     HRESULT saveToString(Utf8Str &rStrDst);
    172 
    173 protected:
    174     /**
    175      * Gets the replacement value for the given placeholder.
    176      *
    177      * @returns COM status code.
    178      * @param   pachPlaceholder The placholder string.  Not zero terminated.
    179      * @param   cchPlaceholder  The length of the placeholder.
    180      * @param   fOutputting     Indicates whether we actually need the correct value
    181      *                          or is just syntax checking excluded template parts.
    182      * @param   rValue          Where to return the value.
    183      */
    184     HRESULT getReplacement(const char *pachPlaceholder, size_t cchPlaceholder, bool fOutputting, RTCString &rValue);
    185 
    186     /**
    187      * Overridable worker for getReplacement.
    188      *
    189      * @returns COM status code.
    190      * @param   pachPlaceholder     The placholder string.  Not zero terminated.
    191      * @param   cchPlaceholder      The length of the placeholder.
    192      * @param   cchFullPlaceholder  The full placeholder length, including suffixes
    193      *                              indicating how it should be escaped (for error
    194      *                              messages).
    195      * @param   fOutputting         Indicates whether we actually need the correct
    196      *                              value or is just syntax checking excluded
    197      *                              template parts.  Intended for voiding triggering
    198      *                              sanity checks regarding which replacements
    199      *                              should be used and not (e.g. no guest additions
    200      *                              path when installing GAs aren't enabled).
    201      * @param   rValue              Where to return the value.
    202      * @throws  std::bad_alloc
    203      */
    204     virtual HRESULT getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
    205                                             size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue);
    206 
    207 
    208     /**
    209      * Get the result of a conditional.
    210      *
    211      * @returns COM status code.
    212      * @param   pachPlaceholder     The placholder string.  Not zero terminated.
    213      * @param   cchPlaceholder      The length of the placeholder.
    214      * @param   pfOutputting        Where to return the result of the conditional.
    215      *                              This holds the current outputting state on input
    216      *                              in case someone want to sanity check anything.
    217      */
    218     virtual HRESULT getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting);
    219 };
    220 
    221 
    222 /**
    223150 * Generic line based text script editor.
    224151 *
     
    298225
    299226
    300 #if 0 /* convert when we fix SUSE */
    301 /**
    302  * SUSE unattended XML file editor.
    303  */
    304 class UnattendedSUSEXMLScript : public UnattendedXMLScript
    305 {
    306 public:
    307     UnattendedSUSEXMLScript(VirtualBoxBase *pSetError, const char *pszDefaultFilename = "autoinst.xml")
    308         : UnattendedXMLScript(pSetError, pszDefaultFilename) {}
    309     ~UnattendedSUSEXMLScript() {}
    310 
    311     HRESULT parse();
    312 
    313 protected:
    314     HRESULT setFieldInElement(xml::ElementNode *pElement, const DataId enmDataId, const Utf8Str &rStrValue);
    315 
    316 private:
    317     //////////////////New functions//////////////////////////////
    318     /** @throws std::bad_alloc */
    319     HRESULT LoopThruSections(const xml::ElementNode *pelmRoot);
    320     /** @throws std::bad_alloc */
    321     HRESULT HandleUserAccountsSection(const xml::ElementNode *pelmSection);
    322     /** @throws std::bad_alloc */
    323     Utf8Str createProbableValue(const DataId enmDataId, const xml::ElementNode *pCurElem);
    324     /** @throws std::bad_alloc */
    325     Utf8Str createProbableUserHomeDir(const xml::ElementNode *pCurElem);
    326     //////////////////New functions//////////////////////////////
    327 };
    328 #endif
    329 
    330 
    331 #endif // !____H_UNATTENDEDSCRIPT
    332 
     227#endif // !____H_TEXTSCRIPT
     228
  • trunk/src/VBox/Main/include/UnattendedScript.h

    r73826 r76167  
    11/* $Id$ */
    22/** @file
    3  * Implementeation of algorithms which read/parse/save scripts for unattended installation.
     3 * Classes for reading/parsing/saving scripts for unattended installation.
    44 */
    55
     
    1919#define ____H_UNATTENDEDSCRIPT
    2020
    21 #include "VirtualBoxBase.h"
    22 #include <iprt/cpp/utils.h>
    23 #include <vector>
     21#include "TextScript.h"
    2422
    2523using namespace xml;
    2624
    2725class Unattended;
    28 
    29 
    30 /**
    31  * Base class for all the script readers/editors.
    32  *
    33  * @todo get rid of this bugger
    34  */
    35 class AbstractScript : public RTCNonCopyable
    36 {
    37 protected:
    38     /** For setting errors.
    39      * Yeah, class isn't entirely abstract now.  */
    40     VirtualBoxBase *mpSetError;
    41 
    42 private: /* no default constructors for children. */
    43     AbstractScript() {}
    44 
    45 public:
    46     AbstractScript(VirtualBoxBase *pSetError) : mpSetError(pSetError) {}
    47     virtual ~AbstractScript() {}
    48 
    49     /**
    50      * Read a script from a file
    51      */
    52     virtual HRESULT read(const Utf8Str &rStrFilename) = 0;
    53 
    54     /**
    55      * Read a script from a VFS file handle.
    56      */
    57     virtual HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename) = 0;
    58 
    59     /**
    60      * Parse the script
    61      */
    62     virtual HRESULT parse() = 0;
    63 
    64     /**
    65      * Save a script to a string.
    66      *
    67      * This is used by save() and later others to deloy the script.
    68      */
    69     virtual HRESULT saveToString(Utf8Str &rStrDst) = 0;
    70 
    71     /**
    72      * Save a script to a file.
    73      * @param   rStrPath        Where to save the script.  This normally points to a
    74      *                          file, but in a number of child use cases it's
    75      *                          actually giving a directory to put the script in
    76      *                          using the default deloyment filename.  One day we
    77      *                          might make the caller do this path joining.
    78      * @param   fOverwrite      Whether to overwrite the file or not.
    79      */
    80     virtual HRESULT save(const Utf8Str &rStrPath, bool fOverwrite) = 0;
    81 
    82     /**
    83      * Path where an actual script with user's data is located
    84      */
    85     virtual const Utf8Str &getActualScriptPath() const = 0;
    86 };
    87 
    88 /**
    89  * Base class for text based script readers/editors.
    90  *
    91  * This deals with reading the file into a string data member, writing it back
    92  * out to a file, and remember the filenames.
    93  */
    94 class BaseTextScript : public AbstractScript
    95 {
    96 protected:
    97     const char * const mpszDefaultTemplateFilename; /**< The default template filename.  Can be empty. */
    98     const char * const mpszDefaultFilename;         /**< Filename to use when someone calls save() with a directory path.  Can be NULL. */
    99     RTCString   mStrScriptFullContent;  /**< Raw text file content.  Produced by read() and typically only used by parse(). */
    100     Utf8Str     mStrOriginalPath;       /**< Path where an original script is located (set by read()). */
    101     Utf8Str     mStrSavedPath;          /**< Path where an saved script with user's data is located (set by save()). */
    102 
    103 public:
    104     BaseTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename, const char *pszDefaultFilename)
    105         : AbstractScript(pSetError)
    106         , mpszDefaultTemplateFilename(pszDefaultTemplateFilename)
    107         , mpszDefaultFilename(pszDefaultFilename)
    108     { }
    109     virtual ~BaseTextScript() {}
    110 
    111     HRESULT read(const Utf8Str &rStrFilename);
    112     HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename);
    113     HRESULT save(const Utf8Str &rStrFilename, bool fOverwrite);
    114 
    115     /**
    116      * Gets the default filename for this class of scripts (empty if none).
    117      *
    118      * @note Just the filename, no path.
    119      */
    120     const char *getDefaultFilename() const
    121     {
    122         return mpszDefaultFilename;
    123     }
    124 
    125     /**
    126      * Gets the default template filename for this class of scripts (empty if none).
    127      *
    128      * @note Just the filename, no path.
    129      */
    130     const char *getDefaultTemplateFilename() const
    131     {
    132         return mpszDefaultTemplateFilename;
    133     }
    134 
    135     /**
    136      * Path to the file we last saved the script as.
    137      */
    138     const Utf8Str &getActualScriptPath() const
    139     {
    140         return mStrSavedPath;
    141     }
    142 
    143     /**
    144      * Path where an original script is located
    145      */
    146     const Utf8Str &getOriginalScriptPath() const
    147     {
    148         return mStrOriginalPath;
    149     }
    150 };
    15126
    15227
     
    21994};
    22095
    221 
    222 /**
    223  * Generic line based text script editor.
    224  *
    225  * This is used for editing isolinux configuratin files among other things.
    226  */
    227 class GeneralTextScript : public BaseTextScript
    228 {
    229 protected:
    230     RTCList<RTCString>  mScriptContentByLines; /**< Content index by line. This contains the edited version. */
    231     bool                mfDataParsed;          /**< Indicates whether the script has been parse() yet.  */
    232 
    233 public:
    234     GeneralTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename = NULL, const char *pszDefaultFilename = NULL)
    235         : BaseTextScript(pSetError, pszDefaultTemplateFilename, pszDefaultFilename), mfDataParsed(false)
    236     {}
    237     virtual ~GeneralTextScript() {}
    238 
    239     HRESULT parse();
    240     HRESULT saveToString(Utf8Str &rStrDst);
    241 
    242     //////////////////New functions//////////////////////////////
    243 
    244     bool isDataParsed() const
    245     {
    246         return mfDataParsed;
    247     }
    248 
    249     /**
    250      * Returns the actual size of script in lines
    251      */
    252     size_t getLineNumbersOfScript() const
    253     {
    254         return mScriptContentByLines.size();
    255     }
    256 
    257     /**
    258      * Gets a read-only reference to the given line, returning Utf8Str::Empty if
    259      * idxLine is out of range.
    260      *
    261      * @returns Line string reference or Utf8Str::Empty.
    262      * @param   idxLine     The line number.
    263      *
    264      * @todo    RTCList doesn't allow this method to be const.
    265      */
    266     RTCString const &getContentOfLine(size_t idxLine);
    267 
    268     /**
    269      * Set new content of line
    270      */
    271     HRESULT setContentOfLine(size_t idxLine, const Utf8Str &newContent);
    272 
    273     /**
    274      * Find a substring in the script
    275      * Returns a list with the found lines
    276      * @throws std::bad_alloc
    277      */
    278     std::vector<size_t> findTemplate(const Utf8Str &rStrNeedle, RTCString::CaseSensitivity enmCase = RTCString::CaseSensitive);
    279 
    280     /**
    281      * In line @a idxLine replace the first occurence of @a rStrNeedle with
    282      * @a rStrRelacement.
    283      */
    284     HRESULT findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement);
    285 
    286     /**
    287      * Append a string into the end of the given line.
    288      */
    289     HRESULT appendToLine(size_t idxLine, const Utf8Str &rStrToAppend);
    290 
    291     /**
    292      * Prepend a string in the beginning of the given line.
    293      */
    294     HRESULT prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend);
    295 
    296     //////////////////New functions//////////////////////////////
    297 };
    298 
    299 
    30096#if 0 /* convert when we fix SUSE */
    30197/**
  • trunk/src/VBox/Main/src-all/TextScript.cpp

    r76159 r76167  
    11/* $Id$ */
    22/** @file
    3  * Implementeation of algorithms which read/parse/save scripts for unattended installation.
     3 * Classes for reading/parsing/saving text scripts (unattended installation, ++).
    44 */
    55
     
    2222#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
    2323#include "LoggingNew.h"
    24 #include "VirtualBoxBase.h"
    25 #include "AutoCaller.h"
    26 #include <VBox/com/ErrorInfo.h>
    27 
    28 #include "UnattendedScript.h"
    29 #include "UnattendedImpl.h"
     24#include "TextScript.h"
    3025
    3126#include <VBox/err.h>
     
    3429#include <iprt/file.h>
    3530#include <iprt/vfs.h>
    36 #include <iprt/getopt.h>
    3731#include <iprt/path.h>
    3832
     
    4034
    4135
    42 //////////////////////////////////////////////////////////////////////////////////////////////////////
    43 /*
    44 *
    45 *
    46 *  Implementation BaseTextScript functions
    47 *
    48 */
    49 //////////////////////////////////////////////////////////////////////////////////////////////////////
     36/*********************************************************************************************************************************
     37*   BaseTextScript Implementation                                                                                                *
     38*********************************************************************************************************************************/
     39
    5040HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)
    5141{
     
    197187}
    198188
    199 #ifdef VBOX_WITH_UNATTENDED
    200 
    201 //////////////////////////////////////////////////////////////////////////////////////////////////////
    202 /*
    203 *
    204 *
    205 *  Implementation UnattendedScriptTemplate methods
    206 *
    207 */
    208 //////////////////////////////////////////////////////////////////////////////////////////////////////
    209 
    210 UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename,
    211                                                    const char *pszDefaultFilename)
    212     : BaseTextScript(pUnattended, pszDefaultTemplateFilename, pszDefaultFilename), mpUnattended(pUnattended)
    213 {
    214 }
    215 
    216 
    217 HRESULT UnattendedScriptTemplate::saveToString(Utf8Str &rStrDst)
    218 {
    219     static const char s_szPrefix[]         = "@@VBOX_";
    220     static const char s_szPrefixInsert[]   = "@@VBOX_INSERT_";
    221     static const char s_szPrefixCond[]     = "@@VBOX_COND_";
    222     static const char s_szPrefixCondEnd[]  = "@@VBOX_COND_END@@";
    223 
    224     struct
    225     {
    226         bool    fSavedOutputting;
    227     }           aConds[8];
    228     unsigned    cConds      = 0;
    229     bool        fOutputting = true;
    230     HRESULT     hrc         = E_FAIL;
    231     size_t      offTemplate = 0;
    232     size_t      cchTemplate = mStrScriptFullContent.length();
    233     rStrDst.setNull();
    234     for (;;)
    235     {
    236         /*
    237          * Find the next placeholder and add any text before it to the output.
    238          */
    239         size_t offPlaceholder = mStrScriptFullContent.find(s_szPrefix, offTemplate);
    240         size_t cchToCopy = offPlaceholder != RTCString::npos ? offPlaceholder - offTemplate : cchTemplate - offTemplate;
    241         if (cchToCopy > 0)
    242         {
    243             if (fOutputting)
    244             {
    245                 try
    246                 {
    247                     rStrDst.append(mStrScriptFullContent, offTemplate, cchToCopy);
    248                 }
    249                 catch (std::bad_alloc &)
    250                 {
    251                     hrc = E_OUTOFMEMORY;
    252                     break;
    253                 }
    254             }
    255             offTemplate += cchToCopy;
    256         }
    257 
    258         /*
    259          * Process placeholder.
    260          */
    261         if (offPlaceholder != RTCString::npos)
    262         {
    263             /*
    264              * First we must find the end of the placeholder string.
    265              */
    266             const char *pszPlaceholder = mStrScriptFullContent.c_str() + offPlaceholder;
    267             size_t      cchPlaceholder = sizeof(s_szPrefix) - 1;
    268             char        ch;
    269             while (   offPlaceholder + cchPlaceholder < cchTemplate
    270                    && (ch = pszPlaceholder[cchPlaceholder]) != '\0'
    271                    && (   ch == '_'
    272                        || RT_C_IS_UPPER(ch)
    273                        || RT_C_IS_DIGIT(ch)) )
    274                 cchPlaceholder++;
    275 
    276             if (   offPlaceholder + cchPlaceholder < cchTemplate
    277                 && pszPlaceholder[cchPlaceholder] == '@')
    278             {
    279                 cchPlaceholder++;
    280                 if (   offPlaceholder + cchPlaceholder < cchTemplate
    281                     && pszPlaceholder[cchPlaceholder] == '@')
    282                     cchPlaceholder++;
    283             }
    284 
    285             if (   pszPlaceholder[cchPlaceholder - 1] != '@'
    286                 || pszPlaceholder[cchPlaceholder - 2] != '@'
    287                 || (   strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) != 0
    288                     && strncmp(pszPlaceholder, s_szPrefixCond,   sizeof(s_szPrefixCond)   - 1) != 0) )
    289             {
    290                 hrc = mpSetError->setError(E_FAIL, mpSetError->tr("Malformed template placeholder '%.*s'"),
    291                                            cchPlaceholder, pszPlaceholder);
    292                 break;
    293             }
    294 
    295             offTemplate += cchPlaceholder;
    296 
    297             /*
    298              * @@VBOX_INSERT_XXX@@:
    299              */
    300             if (strncmp(pszPlaceholder, s_szPrefixInsert, sizeof(s_szPrefixInsert) - 1) == 0)
    301             {
    302                 /*
    303                  * Get the placeholder value and add it to the output.
    304                  */
    305                 RTCString strValue;
    306                 hrc = getReplacement(pszPlaceholder, cchPlaceholder, fOutputting, strValue);
    307                 if (SUCCEEDED(hrc))
    308                 {
    309                     if (fOutputting)
    310                     {
    311                         try
    312                         {
    313                             rStrDst.append(strValue);
    314                         }
    315                         catch (std::bad_alloc &)
    316                         {
    317                             hrc = E_OUTOFMEMORY;
    318                             break;
    319                         }
    320                     }
    321                 }
    322                 else
    323                     break;
    324             }
    325             /*
    326              * @@VBOX_COND_END@@: Pop one item of the conditional stack.
    327              */
    328             else if (   cchPlaceholder == sizeof(s_szPrefixCondEnd) - 1U
    329                      && strncmp(pszPlaceholder, s_szPrefixCondEnd, sizeof(s_szPrefixCondEnd) - 1U) == 0)
    330             {
    331                 if (cConds > 0)
    332                 {
    333                     cConds--;
    334                     fOutputting = aConds[cConds].fSavedOutputting;
    335                 }
    336                 else
    337                 {
    338                     hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    339                                                    mpSetError->tr("%s without @@VBOX_COND_XXX@@ at offset %zu (%#zx)"),
    340                                                    s_szPrefixCondEnd, offPlaceholder, offPlaceholder);
    341                     break;
    342                 }
    343             }
    344             /*
    345              * @@VBOX_COND_XXX@@: Push the previous outputting state and combine it with the
    346              *                    one from the condition.
    347              */
    348             else
    349             {
    350                 Assert(strncmp(pszPlaceholder, s_szPrefixCond, sizeof(s_szPrefixCond) - 1) == 0);
    351                 if (cConds + 1 < RT_ELEMENTS(aConds))
    352                 {
    353                     aConds[cConds].fSavedOutputting = fOutputting;
    354                     bool fNewOutputting = fOutputting;
    355                     hrc = getConditional(pszPlaceholder, cchPlaceholder, &fNewOutputting);
    356                     if (SUCCEEDED(hrc))
    357                         fOutputting = fOutputting && fNewOutputting;
    358                     else
    359                         break;
    360                     cConds++;
    361                 }
    362                 else
    363                 {
    364                     hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR,
    365                                                    mpSetError->tr("Too deep conditional nesting at offset %zu (%#zx)"),
    366                                                    offPlaceholder, offPlaceholder);
    367                     break;
    368                 }
    369             }
    370         }
    371 
    372         /*
    373          * Done?
    374          */
    375         if (offTemplate >= cchTemplate)
    376         {
    377             if (cConds == 0)
    378                 return S_OK;
    379             if (cConds == 1)
    380                 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, mpSetError->tr("Missing @@VBOX_COND_END@@"));
    381             else
    382                 hrc = mpSetError->setErrorBoth(E_FAIL, VERR_PARSE_ERROR, mpSetError->tr("Missing %u @@VBOX_COND_END@@"), cConds);
    383             break;
    384         }
    385     }
    386 
    387     /* failed */
    388     rStrDst.setNull();
    389     return hrc;
    390 }
    391 
    392 HRESULT UnattendedScriptTemplate::getReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
    393                                                  bool fOutputting, RTCString &rValue)
    394 {
    395     /*
    396      * Check for an escaping suffix.  Drop the '@@'.
    397      */
    398     size_t const cchFullPlaceholder = cchPlaceholder;
    399     enum
    400     {
    401         kValueEscaping_None,
    402         kValueEscaping_Bourne,
    403         kValueEscaping_XML_Element,
    404         kValueEscaping_XML_Attribute_Double_Quotes
    405     } enmEscaping;
    406 
    407 #define PLACEHOLDER_ENDS_WITH(a_szSuffix) \
    408         (   cchPlaceholder > sizeof(a_szSuffix) - 1U \
    409          && memcmp(&pachPlaceholder[cchPlaceholder - sizeof(a_szSuffix) + 1U], a_szSuffix, sizeof(a_szSuffix) - 1U) == 0)
    410     if (PLACEHOLDER_ENDS_WITH("_SH@@"))
    411     {
    412         cchPlaceholder -= 3 + 2;
    413         enmEscaping = kValueEscaping_Bourne;
    414     }
    415     else if (PLACEHOLDER_ENDS_WITH("_ELEMENT@@"))
    416     {
    417         cchPlaceholder -= 8 + 2;
    418         enmEscaping = kValueEscaping_XML_Element;
    419     }
    420     else if (PLACEHOLDER_ENDS_WITH("_ATTRIB_DQ@@"))
    421     {
    422         cchPlaceholder -= 10 + 2;
    423         enmEscaping = kValueEscaping_XML_Attribute_Double_Quotes;
    424     }
    425     else
    426     {
    427         Assert(PLACEHOLDER_ENDS_WITH("@@"));
    428         cchPlaceholder -= 2;
    429         enmEscaping = kValueEscaping_None;
    430     }
    431 
    432     /*
    433      * Resolve and escape the value.
    434      */
    435     HRESULT hrc;
    436     try
    437     {
    438         switch (enmEscaping)
    439         {
    440             case kValueEscaping_None:
    441                 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, rValue);
    442                 if (SUCCEEDED(hrc))
    443                     return hrc;
    444                 break;
    445 
    446             case kValueEscaping_Bourne:
    447             case kValueEscaping_XML_Element:
    448             case kValueEscaping_XML_Attribute_Double_Quotes:
    449             {
    450                 RTCString strUnescaped;
    451                 hrc = getUnescapedReplacement(pachPlaceholder, cchPlaceholder, cchFullPlaceholder, fOutputting, strUnescaped);
    452                 if (SUCCEEDED(hrc))
    453                 {
    454                     switch (enmEscaping)
    455                     {
    456                         case kValueEscaping_Bourne:
    457                         {
    458                             const char * const papszArgs[2] = { strUnescaped.c_str(), NULL };
    459                             char              *pszEscaped   = NULL;
    460                             int vrc = RTGetOptArgvToString(&pszEscaped, papszArgs, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
    461                             if (RT_SUCCESS(vrc))
    462                             {
    463                                 try
    464                                 {
    465                                     rValue = pszEscaped;
    466                                     RTStrFree(pszEscaped);
    467                                     return S_OK;
    468                                 }
    469                                 catch (std::bad_alloc &)
    470                                 {
    471                                     hrc = E_OUTOFMEMORY;
    472                                 }
    473                                 RTStrFree(pszEscaped);
    474                             }
    475                             break;
    476                         }
    477 
    478                         case kValueEscaping_XML_Element:
    479                             rValue.printf("%RMes", strUnescaped.c_str());
    480                             return S_OK;
    481 
    482                         case kValueEscaping_XML_Attribute_Double_Quotes:
    483                         {
    484                             RTCString strTmp;
    485                             strTmp.printf("%RMas", strUnescaped.c_str());
    486                             rValue = RTCString(strTmp, 1, strTmp.length() - 2);
    487                             return S_OK;
    488                         }
    489 
    490                         default:
    491                             hrc = E_FAIL;
    492                             break;
    493                     }
    494                 }
    495                 break;
    496             }
    497 
    498             default:
    499                 AssertFailedStmt(hrc = E_FAIL);
    500                 break;
    501         }
    502     }
    503     catch (std::bad_alloc &)
    504     {
    505         hrc = E_OUTOFMEMORY;
    506     }
    507     rValue.setNull();
    508     return hrc;
    509 }
    510 
    511 HRESULT UnattendedScriptTemplate::getUnescapedReplacement(const char *pachPlaceholder, size_t cchPlaceholder,
    512                                                           size_t cchFullPlaceholder, bool fOutputting, RTCString &rValue)
    513 {
    514     RT_NOREF(fOutputting);
    515 #define IS_PLACEHOLDER_MATCH(a_szMatch) \
    516         (   cchPlaceholder == sizeof("@@VBOX_INSERT_" a_szMatch) - 1U \
    517          && memcmp(pachPlaceholder, "@@VBOX_INSERT_" a_szMatch, sizeof("@@VBOX_INSERT_" a_szMatch) - 1U) == 0)
    518 
    519     if (IS_PLACEHOLDER_MATCH("USER_LOGIN"))
    520         rValue = mpUnattended->i_getUser();
    521     else if (IS_PLACEHOLDER_MATCH("USER_PASSWORD"))
    522         rValue = mpUnattended->i_getPassword();
    523     else if (IS_PLACEHOLDER_MATCH("ROOT_PASSWORD"))
    524         rValue = mpUnattended->i_getPassword();
    525     else if (IS_PLACEHOLDER_MATCH("USER_FULL_NAME"))
    526         rValue = mpUnattended->i_getFullUserName();
    527     else if (IS_PLACEHOLDER_MATCH("PRODUCT_KEY"))
    528         rValue = mpUnattended->i_getProductKey();
    529     else if (IS_PLACEHOLDER_MATCH("POST_INSTALL_COMMAND"))
    530         rValue = mpUnattended->i_getPostInstallCommand();
    531     else if (IS_PLACEHOLDER_MATCH("IMAGE_INDEX"))
    532         rValue.printf("%u", mpUnattended->i_getImageIndex());
    533     else if (IS_PLACEHOLDER_MATCH("OS_ARCH"))
    534         rValue = mpUnattended->i_isGuestOs64Bit() ? "amd64" : "x86";
    535     else if (IS_PLACEHOLDER_MATCH("OS_ARCH2"))
    536         rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "x86";
    537     else if (IS_PLACEHOLDER_MATCH("OS_ARCH3"))
    538         rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i386";
    539     else if (IS_PLACEHOLDER_MATCH("OS_ARCH4"))
    540         rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i486";
    541     else if (IS_PLACEHOLDER_MATCH("OS_ARCH6"))
    542         rValue = mpUnattended->i_isGuestOs64Bit() ? "x86_64" : "i686";
    543     else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_UX"))
    544         rValue = mpUnattended->i_getTimeZoneInfo()
    545                ? mpUnattended->i_getTimeZoneInfo()->pszUnixName : mpUnattended->i_getTimeZone();
    546     else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_NAME"))
    547     {
    548         PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
    549         if (pInfo)
    550             rValue = pInfo->pszWindowsName ? pInfo->pszWindowsName : "GMT";
    551         else
    552             rValue = mpUnattended->i_getTimeZone();
    553     }
    554     else if (IS_PLACEHOLDER_MATCH("TIME_ZONE_WIN_INDEX"))
    555     {
    556         PCRTTIMEZONEINFO pInfo = mpUnattended->i_getTimeZoneInfo();
    557         if (pInfo)
    558             rValue.printf("%u", pInfo->idxWindows ? pInfo->idxWindows : 85 /*GMT*/);
    559         else
    560             rValue = mpUnattended->i_getTimeZone();
    561     }
    562     else if (IS_PLACEHOLDER_MATCH("LOCALE"))
    563         rValue = mpUnattended->i_getLocale();
    564     else if (IS_PLACEHOLDER_MATCH("DASH_LOCALE"))
    565     {
    566         rValue = mpUnattended->i_getLocale();
    567         Assert(rValue[2] == '_');
    568         rValue.replace(2, 1, "-");
    569     }
    570     else if (IS_PLACEHOLDER_MATCH("LANGUAGE"))
    571         rValue = mpUnattended->i_getLanguage();
    572     else if (IS_PLACEHOLDER_MATCH("COUNTRY"))
    573         rValue = mpUnattended->i_getCountry();
    574     else if (IS_PLACEHOLDER_MATCH("HOSTNAME_FQDN"))
    575         rValue = mpUnattended->i_getHostname();
    576     else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN"))
    577         rValue.assign(mpUnattended->i_getHostname(), 0, mpUnattended->i_getHostname().find("."));
    578     else if (IS_PLACEHOLDER_MATCH("HOSTNAME_WITHOUT_DOMAIN_MAX_15"))
    579         rValue.assign(mpUnattended->i_getHostname(), 0, RT_MIN(mpUnattended->i_getHostname().find("."), 15));
    580     else if (IS_PLACEHOLDER_MATCH("HOSTNAME_DOMAIN"))
    581         rValue.assign(mpUnattended->i_getHostname(), mpUnattended->i_getHostname().find(".") + 1);
    582     else
    583     {
    584         rValue.setNull();
    585         return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, mpSetError->tr("Unknown template placeholder '%.*s'"),
    586                                         cchFullPlaceholder, pachPlaceholder);
    587     }
    588     return S_OK;
    589 #undef IS_PLACEHOLDER_MATCH
    590 }
    591 
    592 HRESULT UnattendedScriptTemplate::getConditional(const char *pachPlaceholder, size_t cchPlaceholder, bool *pfOutputting)
    593 {
    594 #define IS_PLACEHOLDER_MATCH(a_szMatch) \
    595         (   cchPlaceholder == sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U \
    596          && memcmp(pachPlaceholder, "@@VBOX_COND_" a_szMatch "@@", sizeof("@@VBOX_COND_" a_szMatch "@@") - 1U) == 0)
    597 
    598     /* Install guest additions: */
    599     if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_ADDITIONS"))
    600         *pfOutputting = mpUnattended->i_getInstallGuestAdditions();
    601     else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_ADDITIONS"))
    602         *pfOutputting = !mpUnattended->i_getInstallGuestAdditions();
    603     /* User == Administrator: */
    604     else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_ADMINISTRATOR"))
    605         *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) == 0;
    606     else if (IS_PLACEHOLDER_MATCH("IS_USER_LOGIN_NOT_ADMINISTRATOR"))
    607         *pfOutputting = mpUnattended->i_getUser().compare("Administrator", RTCString::CaseInsensitive) != 0;
    608     /* Install TXS: */
    609     else if (IS_PLACEHOLDER_MATCH("IS_INSTALLING_TEST_EXEC_SERVICE"))
    610         *pfOutputting = mpUnattended->i_getInstallTestExecService();
    611     else if (IS_PLACEHOLDER_MATCH("IS_NOT_INSTALLING_TEST_EXEC_SERVICE"))
    612         *pfOutputting = !mpUnattended->i_getInstallTestExecService();
    613     /* Post install command: */
    614     else if (IS_PLACEHOLDER_MATCH("HAS_POST_INSTALL_COMMAND"))
    615         *pfOutputting = mpUnattended->i_getPostInstallCommand().isNotEmpty();
    616     else if (IS_PLACEHOLDER_MATCH("HAS_NO_POST_INSTALL_COMMAND"))
    617         *pfOutputting = !mpUnattended->i_getPostInstallCommand().isNotEmpty();
    618     /* Product key: */
    619     else if (IS_PLACEHOLDER_MATCH("HAS_PRODUCT_KEY"))
    620         *pfOutputting = mpUnattended->i_getProductKey().isNotEmpty();
    621     else if (IS_PLACEHOLDER_MATCH("HAS_NO_PRODUCT_KEY"))
    622         *pfOutputting = !mpUnattended->i_getProductKey().isNotEmpty();
    623     /* Minimal installation: */
    624     else if (IS_PLACEHOLDER_MATCH("IS_MINIMAL_INSTALLATION"))
    625         *pfOutputting = mpUnattended->i_isMinimalInstallation();
    626     else if (IS_PLACEHOLDER_MATCH("IS_NOT_MINIMAL_INSTALLATION"))
    627         *pfOutputting = !mpUnattended->i_isMinimalInstallation();
    628     /* Is RTC using UTC (i.e. set to UTC time on startup): */
    629     else if (IS_PLACEHOLDER_MATCH("IS_RTC_USING_UTC"))
    630         *pfOutputting = mpUnattended->i_isRtcUsingUtc();
    631     else if (IS_PLACEHOLDER_MATCH("IS_NOT_RTC_USING_UTC"))
    632         *pfOutputting = !mpUnattended->i_isRtcUsingUtc();
    633     else
    634         return mpSetError->setErrorBoth(E_FAIL, VERR_NOT_FOUND, mpSetError->tr("Unknown conditional placeholder '%.*s'"),
    635                                         cchPlaceholder, pachPlaceholder);
    636     return S_OK;
    637 #undef IS_PLACEHOLDER_MATCH
    638 }
    639 
    640 #endif /* VBOX_WITH_UNATTENDED */
    641 
    642 
    643 //////////////////////////////////////////////////////////////////////////////////////////////////////
    644 /*
    645 *
    646 *
    647 *  Implementation GeneralTextScript functions
    648 *
    649 */
    650 //////////////////////////////////////////////////////////////////////////////////////////////////////
     189
     190
     191/*********************************************************************************************************************************
     192*   GeneralTextScript Implementation                                                                                             *
     193*********************************************************************************************************************************/
     194
    651195HRESULT GeneralTextScript::parse()
    652196{
     
    813357}
    814358
    815 #if 0 /* Keeping this a reference */
    816 //////////////////////////////////////////////////////////////////////////////////////////////////////
    817 /*
    818 *
    819 *
    820 *  Implementation UnattendedSUSEXMLScript functions
    821 *
    822 */
    823 /////////////////////////////////////////////////////////////////////////////////////////////////////
    824 HRESULT UnattendedSUSEXMLScript::parse()
    825 {
    826     HRESULT hrc = UnattendedXMLScript::parse();
    827     if (SUCCEEDED(hrc))
    828     {
    829         /*
    830          * Check that we've got the right root element type.
    831          */
    832         const xml::ElementNode *pelmRoot = mDoc.getRootElement();
    833         if (   pelmRoot
    834             && strcmp(pelmRoot->getName(), "profile") == 0)
    835         {
    836             /*
    837              * Work thought the sections.
    838              */
    839             try
    840             {
    841                 LoopThruSections(pelmRoot);
    842                 hrc = S_OK;
    843             }
    844             catch (std::bad_alloc &)
    845             {
    846                 hrc = E_OUTOFMEMORY;
    847             }
    848         }
    849         else if (pelmRoot)
    850             hrc = mpSetError->setError(E_FAIL, mpSetError->tr("XML document root element is '%s' instead of 'profile'"),
    851                                        pelmRoot->getName());
    852         else
    853             hrc = mpSetError->setError(E_FAIL, mpSetError->tr("Missing XML root element"));
    854     }
    855     return hrc;
    856 }
    857 
    858 HRESULT UnattendedSUSEXMLScript::setFieldInElement(xml::ElementNode *pElement, const DataId enmDataId, const Utf8Str &rStrValue)
    859 {
    860     /*
    861      * Don't set empty values.
    862      */
    863     if (rStrValue.isEmpty())
    864     {
    865         Utf8Str strProbableValue;
    866         try
    867         {
    868             strProbableValue = createProbableValue(enmDataId, pElement);
    869         }
    870         catch (std::bad_alloc &)
    871         {
    872             return E_OUTOFMEMORY;
    873         }
    874         return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, strProbableValue);
    875     }
    876     return UnattendedXMLScript::setFieldInElement(pElement, enmDataId, rStrValue);
    877 }
    878 
    879 HRESULT UnattendedSUSEXMLScript::LoopThruSections(const xml::ElementNode *pelmRoot)
    880 {
    881     xml::NodesLoop loopChildren(*pelmRoot);
    882     const xml::ElementNode *pelmOuterLoop;
    883     while ((pelmOuterLoop = loopChildren.forAllNodes()) != NULL)
    884     {
    885         const char *pcszElemName = pelmOuterLoop->getName();
    886         if (!strcmp(pcszElemName, "users"))
    887         {
    888             xml::NodesLoop loopUsers(*pelmOuterLoop);
    889             const xml::ElementNode *pelmUser;
    890             while ((pelmUser = loopUsers.forAllNodes()) != NULL)
    891             {
    892                 HRESULT hrc = HandleUserAccountsSection(pelmUser);
    893                 if (FAILED(hrc))
    894                     return hrc;
    895             }
    896         }
    897     }
    898     return S_OK;
    899 }
    900 
    901 HRESULT UnattendedSUSEXMLScript::HandleUserAccountsSection(const xml::ElementNode *pelmSection)
    902 {
    903     xml::NodesLoop loopUser(*pelmSection);
    904 
    905     const xml::ElementNode *pelmCur;
    906     while ((pelmCur = loopUser.forAllNodes()) != NULL)
    907     {
    908         const char *pszValue = pelmCur->getValue();
    909 #ifdef LOG_ENABLED
    910         if (!RTStrCmp(pelmCur->getName(), "uid"))
    911             LogRelFunc(("UnattendedSUSEXMLScript::HandleUserAccountsSection profile/users/%s/%s = %s\n",
    912                         pelmSection->getName(), pelmCur->getName(), pszValue));
    913 #endif
    914 
    915         if (!RTStrCmp(pszValue, "$homedir"))
    916             mNodesForCorrectionMap.insert(make_pair(USERHOMEDIR_ID, pelmCur));
    917 
    918         if (!RTStrCmp(pszValue, "$user"))
    919             mNodesForCorrectionMap.insert(make_pair(USERNAME_ID, pelmCur));
    920 
    921         if (!RTStrCmp(pszValue, "$password"))
    922             mNodesForCorrectionMap.insert(make_pair(USERPASSWORD_ID, pelmCur));
    923     }
    924     return S_OK;
    925 }
    926 
    927 Utf8Str UnattendedSUSEXMLScript::createProbableValue(const DataId enmDataId, const xml::ElementNode *pCurElem)
    928 {
    929     const xml::ElementNode *pElem = pCurElem;
    930 
    931     switch (enmDataId)
    932     {
    933         case USERHOMEDIR_ID:
    934 //          if ((pElem = pElem->findChildElement("home")))
    935 //          {
    936                 return createProbableUserHomeDir(pElem);
    937 //          }
    938             break;
    939         default:
    940             break;
    941     }
    942 
    943     return Utf8Str::Empty;
    944 }
    945 
    946 Utf8Str UnattendedSUSEXMLScript::createProbableUserHomeDir(const xml::ElementNode *pCurElem)
    947 {
    948     Utf8Str strCalcValue;
    949     const xml::ElementNode *pElem = pCurElem->findNextSibilingElement("username");
    950     if (pElem)
    951     {
    952         const char *pszValue = pElem->getValue();
    953         strCalcValue = "/home/";
    954         strCalcValue.append(pszValue);
    955     }
    956 
    957     return strCalcValue;
    958 }
    959 #endif /* just for reference */
    960 
  • trunk/src/VBox/Main/src-server/UnattendedScript.cpp

    r74936 r76167  
    11/* $Id$ */
    22/** @file
    3  * Implementeation of algorithms which read/parse/save scripts for unattended installation.
     3 * Classes for reading/parsing/saving scripts for unattended installation.
    44 */
    55
     
    4040
    4141
    42 //////////////////////////////////////////////////////////////////////////////////////////////////////
    43 /*
    44 *
    45 *
    46 *  Implementation BaseTextScript functions
    47 *
    48 */
    49 //////////////////////////////////////////////////////////////////////////////////////////////////////
    50 HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)
    51 {
    52     /*
    53      * Open the file for reading and figure it's size.  Capping the size
    54      * at 16MB so we don't exaust the heap on bad input.
    55      */
    56     HRESULT   hrc;
    57     RTVFSFILE hVfsFile;
    58     int vrc = RTVfsFileOpenNormal(rStrFilename.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
    59     if (RT_SUCCESS(vrc))
    60     {
    61         hrc = readFromHandle(hVfsFile, rStrFilename.c_str());
    62         RTVfsFileRelease(hVfsFile);
    63     }
    64     else
    65         hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
    66     return hrc;
    67 }
    68 
    69 HRESULT BaseTextScript::readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename)
    70 {
    71     /*
    72      * Open the file for reading and figure it's size.  Capping the size
    73      * at 16MB so we don't exaust the heap on bad input.
    74      */
    75     HRESULT  hrc;
    76     uint64_t cbFile = 0;
    77     int vrc = RTVfsFileGetSize(hVfsFile, &cbFile);
    78     if (   RT_SUCCESS(vrc)
    79         && cbFile < _16M)
    80     {
    81         /*
    82          * Exploint the jolt() feature of RTCString and read the content directly into
    83          * its storage buffer.
    84          */
    85         vrc = mStrScriptFullContent.reserveNoThrow((size_t)cbFile + 1);
    86         if (RT_SUCCESS(vrc))
    87         {
    88             char *pszDst = mStrScriptFullContent.mutableRaw();
    89             vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, pszDst, (size_t)cbFile, NULL);
    90             pszDst[(size_t)cbFile] = '\0';
    91             if (RT_SUCCESS(vrc))
    92             {
    93                 /*
    94                  * We must validate the encoding or we'll be subject to potential security trouble.
    95                  * If this turns out to be problematic, we will need to implement codeset
    96                  * conversion coping mechanisms.
    97                  */
    98                 vrc = RTStrValidateEncodingEx(pszDst, (size_t)cbFile + 1,
    99                                               RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
    100                 if (RT_SUCCESS(vrc))
    101                 {
    102                     mStrScriptFullContent.jolt();
    103                     return S_OK;
    104                 }
    105 
    106                 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
    107             }
    108             else
    109                 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);
    110             mStrScriptFullContent.setNull();
    111         }
    112         else
    113             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
    114                                           cbFile, pszFilename);
    115     }
    116     else if (RT_SUCCESS(vrc))
    117         hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG,
    118                                       mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
    119     else
    120         hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileGetSize failed (%Rrc)"), vrc);
    121     return hrc;
    122 }
    123 
    124 HRESULT BaseTextScript::save(const Utf8Str &rStrFilename, bool fOverwrite)
    125 {
    126     /*
    127      * We may have to append the default filename to the
    128      */
    129     const char *pszFilename = rStrFilename.c_str();
    130     Utf8Str     strWithDefaultFilename;
    131     if (   getDefaultFilename() != NULL
    132         && *getDefaultFilename() != '\0'
    133         && RTDirExists(rStrFilename.c_str()) )
    134     {
    135         try
    136         {
    137             strWithDefaultFilename = rStrFilename;
    138             strWithDefaultFilename.append(RTPATH_SLASH);
    139             strWithDefaultFilename.append(getDefaultFilename());
    140         }
    141         catch (std::bad_alloc &)
    142         {
    143             return E_OUTOFMEMORY;
    144         }
    145         pszFilename = strWithDefaultFilename.c_str();
    146     }
    147 
    148     /*
    149      * Save the filename for later use.
    150      */
    151     try
    152     {
    153         mStrSavedPath = pszFilename;
    154     }
    155     catch (std::bad_alloc &)
    156     {
    157         return E_OUTOFMEMORY;
    158     }
    159 
    160     /*
    161      * Use the saveToString method to produce the content.
    162      */
    163     Utf8Str strDst;
    164     HRESULT hrc = saveToString(strDst);
    165     if (SUCCEEDED(hrc))
    166     {
    167         /*
    168          * Write the content.
    169          */
    170         RTFILE   hFile;
    171         uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
    172         if (fOverwrite)
    173             fOpen |= RTFILE_O_CREATE_REPLACE;
    174         else
    175             fOpen |= RTFILE_O_CREATE;
    176         int vrc = RTFileOpen(&hFile, pszFilename, fOpen);
    177         if (RT_SUCCESS(vrc))
    178         {
    179             vrc = RTFileWrite(hFile, strDst.c_str(), strDst.length(), NULL);
    180             if (RT_SUCCESS(vrc))
    181             {
    182                 vrc = RTFileClose(hFile);
    183                 if (RT_SUCCESS(vrc))
    184                 {
    185                     LogRelFlow(("GeneralTextScript::save(): saved %zu bytes to '%s'\n", strDst.length(), pszFilename));
    186                     return S_OK;
    187                 }
    188             }
    189             RTFileClose(hFile);
    190             RTFileDelete(pszFilename);
    191             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
    192         }
    193         else
    194             hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
    195     }
    196     return hrc;
    197 }
    198 
    19942#ifdef VBOX_WITH_UNATTENDED
    20043
    201 //////////////////////////////////////////////////////////////////////////////////////////////////////
    202 /*
    203 *
    204 *
    205 *  Implementation UnattendedScriptTemplate methods
    206 *
    207 */
    208 //////////////////////////////////////////////////////////////////////////////////////////////////////
     44/*********************************************************************************************************************************
     45*   UnattendedScriptTemplate Implementation                                                                                      *
     46*********************************************************************************************************************************/
    20947
    21048UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename,
     
    641479
    642480
    643 //////////////////////////////////////////////////////////////////////////////////////////////////////
    644 /*
    645 *
    646 *
    647 *  Implementation GeneralTextScript functions
    648 *
    649 */
    650 //////////////////////////////////////////////////////////////////////////////////////////////////////
    651 HRESULT GeneralTextScript::parse()
    652 {
    653 //  AssertReturn(!mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "parse called more than once"));
    654 
    655     /*
    656      * Split the raw context into an array of lines.
    657      */
    658     try
    659     {
    660         mScriptContentByLines = mStrScriptFullContent.split("\n");
    661     }
    662     catch (std::bad_alloc &)
    663     {
    664         mScriptContentByLines.clear();
    665         return E_OUTOFMEMORY;
    666     }
    667 
    668     mfDataParsed = true;
    669     return S_OK;
    670 }
    671 
    672 HRESULT GeneralTextScript::saveToString(Utf8Str &rStrDst)
    673 {
    674     AssertReturn(mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "saveToString() called before parse()"));
    675 
    676     /*
    677      * Calc the required size first.
    678      */
    679     size_t const cLines = mScriptContentByLines.size();
    680     size_t       cbTotal = 1;
    681     for (size_t iLine = 0; iLine < cLines; iLine++)
    682         cbTotal = mScriptContentByLines[iLine].length() + 1;
    683 
    684     /*
    685      * Clear the output and try reserve sufficient space.
    686      */
    687     rStrDst.setNull();
    688 
    689     int vrc = rStrDst.reserveNoThrow(cbTotal);
    690     if (RT_FAILURE(vrc))
    691         return E_OUTOFMEMORY;
    692 
    693     /*
    694      * Assemble the output.
    695      */
    696     for (size_t iLine = 0; iLine < cLines; iLine++)
    697     {
    698         try
    699         {
    700             rStrDst.append(mScriptContentByLines[iLine]);
    701             rStrDst.append('\n');
    702         }
    703         catch (std::bad_alloc &)
    704         {
    705             return E_OUTOFMEMORY;
    706         }
    707     }
    708 
    709     return S_OK;
    710 }
    711 
    712 const RTCString &GeneralTextScript::getContentOfLine(size_t idxLine)
    713 {
    714     if (idxLine < mScriptContentByLines.size())
    715         return mScriptContentByLines[idxLine];
    716     return Utf8Str::Empty;
    717 }
    718 
    719 
    720 HRESULT GeneralTextScript::setContentOfLine(size_t idxLine, const Utf8Str &rStrNewLine)
    721 {
    722     AssertReturn(idxLine < mScriptContentByLines.size(),
    723                  mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "attempting to set line %zu when there are only %zu lines",
    724                                           idxLine, mScriptContentByLines.size()));
    725     try
    726     {
    727         mScriptContentByLines[idxLine] = rStrNewLine;
    728     }
    729     catch (std::bad_alloc &)
    730     {
    731         return E_OUTOFMEMORY;
    732     }
    733     return S_OK;
    734 }
    735 
    736 vector<size_t> GeneralTextScript::findTemplate(const Utf8Str &rStrNeedle,
    737                                                RTCString::CaseSensitivity enmCase /*= RTCString::CaseSensitive*/)
    738 {
    739     vector<size_t> vecHitLineNumbers;
    740     size_t const   cLines = mScriptContentByLines.size();
    741     for (size_t iLine = 0; iLine < cLines; iLine++)
    742         if (mScriptContentByLines[iLine].contains(rStrNeedle, enmCase))
    743             vecHitLineNumbers.push_back(iLine);
    744 
    745     return vecHitLineNumbers;
    746 }
    747 
    748 HRESULT GeneralTextScript::findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement)
    749 {
    750     AssertReturn(idxLine < mScriptContentByLines.size(),
    751                  mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE,
    752                                           "attempting search&replace in line %zu when there are only %zu lines",
    753                                           idxLine, mScriptContentByLines.size()));
    754 
    755     RTCString &rDstString = mScriptContentByLines[idxLine];
    756     size_t const offNeedle = rDstString.find(&rStrNeedle);
    757     if (offNeedle != RTCString::npos)
    758     {
    759         try
    760         {
    761             RTCString strBefore(rDstString, 0, offNeedle);
    762             RTCString strAfter(rDstString, offNeedle + rStrNeedle.length());
    763             rDstString = strBefore;
    764             strBefore.setNull();
    765             rDstString.append(rStrReplacement);
    766             rDstString.append(strAfter);
    767         }
    768         catch (std::bad_alloc &)
    769         {
    770             return E_OUTOFMEMORY;
    771         }
    772     }
    773     return S_OK;
    774 }
    775 
    776 HRESULT GeneralTextScript::appendToLine(size_t idxLine, const Utf8Str &rStrToAppend)
    777 {
    778     AssertReturn(idxLine < mScriptContentByLines.size(),
    779                  mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "appending to line %zu when there are only %zu lines",
    780                                           idxLine, mScriptContentByLines.size()));
    781 
    782     try
    783     {
    784         mScriptContentByLines[idxLine].append(rStrToAppend);
    785     }
    786     catch (std::bad_alloc &)
    787     {
    788         return E_OUTOFMEMORY;
    789     }
    790     return S_OK;
    791 }
    792 
    793 HRESULT GeneralTextScript::prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend)
    794 {
    795     AssertReturn(idxLine < mScriptContentByLines.size(),
    796                  mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "prepending to line %zu when there are only %zu lines",
    797                                           idxLine, mScriptContentByLines.size()));
    798 
    799     RTCString &rDstString = mScriptContentByLines[idxLine];
    800     try
    801     {
    802         RTCString strCopy;
    803         rDstString.swap(strCopy);
    804         rDstString.reserve(strCopy.length() + rStrToPrepend.length() + 1);
    805         rDstString = rStrToPrepend;
    806         rDstString.append(strCopy);
    807     }
    808     catch (std::bad_alloc &)
    809     {
    810         return E_OUTOFMEMORY;
    811     }
    812     return S_OK;
    813 }
    814481
    815482#if 0 /* Keeping this a reference */
    816 //////////////////////////////////////////////////////////////////////////////////////////////////////
    817 /*
    818 *
    819 *
    820 *  Implementation UnattendedSUSEXMLScript functions
    821 *
    822 */
    823 /////////////////////////////////////////////////////////////////////////////////////////////////////
     483/*********************************************************************************************************************************
     484*   UnattendedSUSEXMLScript Implementation                                                                                       *
     485*********************************************************************************************************************************/
     486
    824487HRESULT UnattendedSUSEXMLScript::parse()
    825488{
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette