Changeset 76167 in vbox for trunk/src/VBox
- Timestamp:
- Dec 11, 2018 5:03:05 PM (6 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r76165 r76167 485 485 src-server/UnattendedInstaller.cpp \ 486 486 src-server/UnattendedScript.cpp \ 487 src-all/TextScript.cpp \ 487 488 ,) \ 488 489 src-server/USBControllerImpl.cpp \ -
trunk/src/VBox/Main/include/TextScript.h
r76159 r76167 1 1 /* $Id$ */ 2 2 /** @file 3 * Implementeation of algorithms which read/parse/save scripts for unattended installation.3 * Classes for reading/parsing/saving text scripts (unattended installation, ++). 4 4 */ 5 5 … … 16 16 */ 17 17 18 #ifndef ____H_ UNATTENDEDSCRIPT19 #define ____H_ UNATTENDEDSCRIPT18 #ifndef ____H_TEXTSCRIPT 19 #define ____H_TEXTSCRIPT 20 20 21 21 #include "VirtualBoxBase.h" … … 23 23 #include <vector> 24 24 25 using namespace xml;26 27 class Unattended;28 29 25 30 26 /** 31 27 * Base class for all the script readers/editors. 32 28 * 33 * @todo get rid of this bugger29 * @todo get rid of this silly bugger. 34 30 */ 35 31 class AbstractScript : public RTCNonCopyable … … 152 148 153 149 /** 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 BaseTextScript161 {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 value181 * 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 suffixes193 * indicating how it should be escaped (for error194 * messages).195 * @param fOutputting Indicates whether we actually need the correct196 * value or is just syntax checking excluded197 * template parts. Intended for voiding triggering198 * sanity checks regarding which replacements199 * should be used and not (e.g. no guest additions200 * path when installing GAs aren't enabled).201 * @param rValue Where to return the value.202 * @throws std::bad_alloc203 */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 input216 * 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 /**223 150 * Generic line based text script editor. 224 151 * … … 298 225 299 226 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 1 1 /* $Id$ */ 2 2 /** @file 3 * Implementeation of algorithms which read/parse/savescripts for unattended installation.3 * Classes for reading/parsing/saving scripts for unattended installation. 4 4 */ 5 5 … … 19 19 #define ____H_UNATTENDEDSCRIPT 20 20 21 #include "VirtualBoxBase.h" 22 #include <iprt/cpp/utils.h> 23 #include <vector> 21 #include "TextScript.h" 24 22 25 23 using namespace xml; 26 24 27 25 class Unattended; 28 29 30 /**31 * Base class for all the script readers/editors.32 *33 * @todo get rid of this bugger34 */35 class AbstractScript : public RTCNonCopyable36 {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 file51 */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 script61 */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 a74 * file, but in a number of child use cases it's75 * actually giving a directory to put the script in76 * using the default deloyment filename. One day we77 * 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 located84 */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 back92 * out to a file, and remember the filenames.93 */94 class BaseTextScript : public AbstractScript95 {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() const121 {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() const131 {132 return mpszDefaultTemplateFilename;133 }134 135 /**136 * Path to the file we last saved the script as.137 */138 const Utf8Str &getActualScriptPath() const139 {140 return mStrSavedPath;141 }142 143 /**144 * Path where an original script is located145 */146 const Utf8Str &getOriginalScriptPath() const147 {148 return mStrOriginalPath;149 }150 };151 26 152 27 … … 219 94 }; 220 95 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 BaseTextScript228 {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() const245 {246 return mfDataParsed;247 }248 249 /**250 * Returns the actual size of script in lines251 */252 size_t getLineNumbersOfScript() const253 {254 return mScriptContentByLines.size();255 }256 257 /**258 * Gets a read-only reference to the given line, returning Utf8Str::Empty if259 * 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 line270 */271 HRESULT setContentOfLine(size_t idxLine, const Utf8Str &newContent);272 273 /**274 * Find a substring in the script275 * Returns a list with the found lines276 * @throws std::bad_alloc277 */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 with282 * @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 300 96 #if 0 /* convert when we fix SUSE */ 301 97 /** -
trunk/src/VBox/Main/src-all/TextScript.cpp
r76159 r76167 1 1 /* $Id$ */ 2 2 /** @file 3 * Implementeation of algorithms which read/parse/save scripts for unattended installation.3 * Classes for reading/parsing/saving text scripts (unattended installation, ++). 4 4 */ 5 5 … … 22 22 #define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED 23 23 #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" 30 25 31 26 #include <VBox/err.h> … … 34 29 #include <iprt/file.h> 35 30 #include <iprt/vfs.h> 36 #include <iprt/getopt.h>37 31 #include <iprt/path.h> 38 32 … … 40 34 41 35 42 ////////////////////////////////////////////////////////////////////////////////////////////////////// 43 /* 44 * 45 * 46 * Implementation BaseTextScript functions 47 * 48 */ 49 ////////////////////////////////////////////////////////////////////////////////////////////////////// 36 /********************************************************************************************************************************* 37 * BaseTextScript Implementation * 38 *********************************************************************************************************************************/ 39 50 40 HRESULT BaseTextScript::read(const Utf8Str &rStrFilename) 51 41 { … … 197 187 } 198 188 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 651 195 HRESULT GeneralTextScript::parse() 652 196 { … … 813 357 } 814 358 815 #if 0 /* Keeping this a reference */816 //////////////////////////////////////////////////////////////////////////////////////////////////////817 /*818 *819 *820 * Implementation UnattendedSUSEXMLScript functions821 *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 ( pelmRoot834 && strcmp(pelmRoot->getName(), "profile") == 0)835 {836 /*837 * Work thought the sections.838 */839 try840 {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 else853 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 try867 {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_ENABLED910 if (!RTStrCmp(pelmCur->getName(), "uid"))911 LogRelFunc(("UnattendedSUSEXMLScript::HandleUserAccountsSection profile/users/%s/%s = %s\n",912 pelmSection->getName(), pelmCur->getName(), pszValue));913 #endif914 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 1 1 /* $Id$ */ 2 2 /** @file 3 * Implementeation of algorithms which read/parse/savescripts for unattended installation.3 * Classes for reading/parsing/saving scripts for unattended installation. 4 4 */ 5 5 … … 40 40 41 41 42 //////////////////////////////////////////////////////////////////////////////////////////////////////43 /*44 *45 *46 * Implementation BaseTextScript functions47 *48 */49 //////////////////////////////////////////////////////////////////////////////////////////////////////50 HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)51 {52 /*53 * Open the file for reading and figure it's size. Capping the size54 * 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 else65 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 size73 * 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 into83 * 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 codeset96 * 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 else109 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);110 mStrScriptFullContent.setNull();111 }112 else113 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 else120 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 the128 */129 const char *pszFilename = rStrFilename.c_str();130 Utf8Str strWithDefaultFilename;131 if ( getDefaultFilename() != NULL132 && *getDefaultFilename() != '\0'133 && RTDirExists(rStrFilename.c_str()) )134 {135 try136 {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 try152 {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 else175 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 else194 hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);195 }196 return hrc;197 }198 199 42 #ifdef VBOX_WITH_UNATTENDED 200 43 201 ////////////////////////////////////////////////////////////////////////////////////////////////////// 202 /* 203 * 204 * 205 * Implementation UnattendedScriptTemplate methods 206 * 207 */ 208 ////////////////////////////////////////////////////////////////////////////////////////////////////// 44 /********************************************************************************************************************************* 45 * UnattendedScriptTemplate Implementation * 46 *********************************************************************************************************************************/ 209 47 210 48 UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename, … … 641 479 642 480 643 //////////////////////////////////////////////////////////////////////////////////////////////////////644 /*645 *646 *647 * Implementation GeneralTextScript functions648 *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 try659 {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 try699 {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 try726 {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 try760 {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 try783 {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 try801 {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 }814 481 815 482 #if 0 /* Keeping this a reference */ 816 ////////////////////////////////////////////////////////////////////////////////////////////////////// 817 /* 818 * 819 * 820 * Implementation UnattendedSUSEXMLScript functions 821 * 822 */ 823 ///////////////////////////////////////////////////////////////////////////////////////////////////// 483 /********************************************************************************************************************************* 484 * UnattendedSUSEXMLScript Implementation * 485 *********************************************************************************************************************************/ 486 824 487 HRESULT UnattendedSUSEXMLScript::parse() 825 488 {
Note:
See TracChangeset
for help on using the changeset viewer.