Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 76166)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 76167)
@@ -485,4 +485,5 @@
 	src-server/UnattendedInstaller.cpp \
 	src-server/UnattendedScript.cpp \
+	src-all/TextScript.cpp \
 	,) \
 	src-server/USBControllerImpl.cpp \
Index: /trunk/src/VBox/Main/include/TextScript.h
===================================================================
--- /trunk/src/VBox/Main/include/TextScript.h	(revision 76167)
+++ /trunk/src/VBox/Main/include/TextScript.h	(revision 76167)
@@ -0,0 +1,228 @@
+/* $Id$ */
+/** @file
+ * Classes for reading/parsing/saving text scripts (unattended installation, ++).
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ____H_TEXTSCRIPT
+#define ____H_TEXTSCRIPT
+
+#include "VirtualBoxBase.h"
+#include <iprt/cpp/utils.h>
+#include <vector>
+
+
+/**
+ * Base class for all the script readers/editors.
+ *
+ * @todo get rid of this silly bugger.
+ */
+class AbstractScript : public RTCNonCopyable
+{
+protected:
+    /** For setting errors.
+     * Yeah, class isn't entirely abstract now.  */
+    VirtualBoxBase *mpSetError;
+
+private: /* no default constructors for children. */
+    AbstractScript() {}
+
+public:
+    AbstractScript(VirtualBoxBase *pSetError) : mpSetError(pSetError) {}
+    virtual ~AbstractScript() {}
+
+    /**
+     * Read a script from a file
+     */
+    virtual HRESULT read(const Utf8Str &rStrFilename) = 0;
+
+    /**
+     * Read a script from a VFS file handle.
+     */
+    virtual HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename) = 0;
+
+    /**
+     * Parse the script
+     */
+    virtual HRESULT parse() = 0;
+
+    /**
+     * Save a script to a string.
+     *
+     * This is used by save() and later others to deloy the script.
+     */
+    virtual HRESULT saveToString(Utf8Str &rStrDst) = 0;
+
+    /**
+     * Save a script to a file.
+     * @param   rStrPath        Where to save the script.  This normally points to a
+     *                          file, but in a number of child use cases it's
+     *                          actually giving a directory to put the script in
+     *                          using the default deloyment filename.  One day we
+     *                          might make the caller do this path joining.
+     * @param   fOverwrite      Whether to overwrite the file or not.
+     */
+    virtual HRESULT save(const Utf8Str &rStrPath, bool fOverwrite) = 0;
+
+    /**
+     * Path where an actual script with user's data is located
+     */
+    virtual const Utf8Str &getActualScriptPath() const = 0;
+};
+
+/**
+ * Base class for text based script readers/editors.
+ *
+ * This deals with reading the file into a string data member, writing it back
+ * out to a file, and remember the filenames.
+ */
+class BaseTextScript : public AbstractScript
+{
+protected:
+    const char * const mpszDefaultTemplateFilename; /**< The default template filename.  Can be empty. */
+    const char * const mpszDefaultFilename;         /**< Filename to use when someone calls save() with a directory path.  Can be NULL. */
+    RTCString   mStrScriptFullContent;  /**< Raw text file content.  Produced by read() and typically only used by parse(). */
+    Utf8Str     mStrOriginalPath;       /**< Path where an original script is located (set by read()). */
+    Utf8Str     mStrSavedPath;          /**< Path where an saved script with user's data is located (set by save()). */
+
+public:
+    BaseTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename, const char *pszDefaultFilename)
+        : AbstractScript(pSetError)
+        , mpszDefaultTemplateFilename(pszDefaultTemplateFilename)
+        , mpszDefaultFilename(pszDefaultFilename)
+    { }
+    virtual ~BaseTextScript() {}
+
+    HRESULT read(const Utf8Str &rStrFilename);
+    HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename);
+    HRESULT save(const Utf8Str &rStrFilename, bool fOverwrite);
+
+    /**
+     * Gets the default filename for this class of scripts (empty if none).
+     *
+     * @note Just the filename, no path.
+     */
+    const char *getDefaultFilename() const
+    {
+        return mpszDefaultFilename;
+    }
+
+    /**
+     * Gets the default template filename for this class of scripts (empty if none).
+     *
+     * @note Just the filename, no path.
+     */
+    const char *getDefaultTemplateFilename() const
+    {
+        return mpszDefaultTemplateFilename;
+    }
+
+    /**
+     * Path to the file we last saved the script as.
+     */
+    const Utf8Str &getActualScriptPath() const
+    {
+        return mStrSavedPath;
+    }
+
+    /**
+     * Path where an original script is located
+     */
+    const Utf8Str &getOriginalScriptPath() const
+    {
+        return mStrOriginalPath;
+    }
+};
+
+
+/**
+ * Generic line based text script editor.
+ *
+ * This is used for editing isolinux configuratin files among other things.
+ */
+class GeneralTextScript : public BaseTextScript
+{
+protected:
+    RTCList<RTCString>  mScriptContentByLines; /**< Content index by line. This contains the edited version. */
+    bool                mfDataParsed;          /**< Indicates whether the script has been parse() yet.  */
+
+public:
+    GeneralTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename = NULL, const char *pszDefaultFilename = NULL)
+        : BaseTextScript(pSetError, pszDefaultTemplateFilename, pszDefaultFilename), mfDataParsed(false)
+    {}
+    virtual ~GeneralTextScript() {}
+
+    HRESULT parse();
+    HRESULT saveToString(Utf8Str &rStrDst);
+
+    //////////////////New functions//////////////////////////////
+
+    bool isDataParsed() const
+    {
+        return mfDataParsed;
+    }
+
+    /**
+     * Returns the actual size of script in lines
+     */
+    size_t getLineNumbersOfScript() const
+    {
+        return mScriptContentByLines.size();
+    }
+
+    /**
+     * Gets a read-only reference to the given line, returning Utf8Str::Empty if
+     * idxLine is out of range.
+     *
+     * @returns Line string reference or Utf8Str::Empty.
+     * @param   idxLine     The line number.
+     *
+     * @todo    RTCList doesn't allow this method to be const.
+     */
+    RTCString const &getContentOfLine(size_t idxLine);
+
+    /**
+     * Set new content of line
+     */
+    HRESULT setContentOfLine(size_t idxLine, const Utf8Str &newContent);
+
+    /**
+     * Find a substring in the script
+     * Returns a list with the found lines
+     * @throws std::bad_alloc
+     */
+    std::vector<size_t> findTemplate(const Utf8Str &rStrNeedle, RTCString::CaseSensitivity enmCase = RTCString::CaseSensitive);
+
+    /**
+     * In line @a idxLine replace the first occurence of @a rStrNeedle with
+     * @a rStrRelacement.
+     */
+    HRESULT findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement);
+
+    /**
+     * Append a string into the end of the given line.
+     */
+    HRESULT appendToLine(size_t idxLine, const Utf8Str &rStrToAppend);
+
+    /**
+     * Prepend a string in the beginning of the given line.
+     */
+    HRESULT prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend);
+
+    //////////////////New functions//////////////////////////////
+};
+
+
+#endif // !____H_TEXTSCRIPT
+
Index: /trunk/src/VBox/Main/include/UnattendedScript.h
===================================================================
--- /trunk/src/VBox/Main/include/UnattendedScript.h	(revision 76166)
+++ /trunk/src/VBox/Main/include/UnattendedScript.h	(revision 76167)
@@ -1,5 +1,5 @@
 /* $Id$ */
 /** @file
- * Implementeation of algorithms which read/parse/save scripts for unattended installation.
+ * Classes for reading/parsing/saving scripts for unattended installation.
  */
 
@@ -19,134 +19,9 @@
 #define ____H_UNATTENDEDSCRIPT
 
-#include "VirtualBoxBase.h"
-#include <iprt/cpp/utils.h>
-#include <vector>
+#include "TextScript.h"
 
 using namespace xml;
 
 class Unattended;
-
-
-/**
- * Base class for all the script readers/editors.
- *
- * @todo get rid of this bugger
- */
-class AbstractScript : public RTCNonCopyable
-{
-protected:
-    /** For setting errors.
-     * Yeah, class isn't entirely abstract now.  */
-    VirtualBoxBase *mpSetError;
-
-private: /* no default constructors for children. */
-    AbstractScript() {}
-
-public:
-    AbstractScript(VirtualBoxBase *pSetError) : mpSetError(pSetError) {}
-    virtual ~AbstractScript() {}
-
-    /**
-     * Read a script from a file
-     */
-    virtual HRESULT read(const Utf8Str &rStrFilename) = 0;
-
-    /**
-     * Read a script from a VFS file handle.
-     */
-    virtual HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename) = 0;
-
-    /**
-     * Parse the script
-     */
-    virtual HRESULT parse() = 0;
-
-    /**
-     * Save a script to a string.
-     *
-     * This is used by save() and later others to deloy the script.
-     */
-    virtual HRESULT saveToString(Utf8Str &rStrDst) = 0;
-
-    /**
-     * Save a script to a file.
-     * @param   rStrPath        Where to save the script.  This normally points to a
-     *                          file, but in a number of child use cases it's
-     *                          actually giving a directory to put the script in
-     *                          using the default deloyment filename.  One day we
-     *                          might make the caller do this path joining.
-     * @param   fOverwrite      Whether to overwrite the file or not.
-     */
-    virtual HRESULT save(const Utf8Str &rStrPath, bool fOverwrite) = 0;
-
-    /**
-     * Path where an actual script with user's data is located
-     */
-    virtual const Utf8Str &getActualScriptPath() const = 0;
-};
-
-/**
- * Base class for text based script readers/editors.
- *
- * This deals with reading the file into a string data member, writing it back
- * out to a file, and remember the filenames.
- */
-class BaseTextScript : public AbstractScript
-{
-protected:
-    const char * const mpszDefaultTemplateFilename; /**< The default template filename.  Can be empty. */
-    const char * const mpszDefaultFilename;         /**< Filename to use when someone calls save() with a directory path.  Can be NULL. */
-    RTCString   mStrScriptFullContent;  /**< Raw text file content.  Produced by read() and typically only used by parse(). */
-    Utf8Str     mStrOriginalPath;       /**< Path where an original script is located (set by read()). */
-    Utf8Str     mStrSavedPath;          /**< Path where an saved script with user's data is located (set by save()). */
-
-public:
-    BaseTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename, const char *pszDefaultFilename)
-        : AbstractScript(pSetError)
-        , mpszDefaultTemplateFilename(pszDefaultTemplateFilename)
-        , mpszDefaultFilename(pszDefaultFilename)
-    { }
-    virtual ~BaseTextScript() {}
-
-    HRESULT read(const Utf8Str &rStrFilename);
-    HRESULT readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename);
-    HRESULT save(const Utf8Str &rStrFilename, bool fOverwrite);
-
-    /**
-     * Gets the default filename for this class of scripts (empty if none).
-     *
-     * @note Just the filename, no path.
-     */
-    const char *getDefaultFilename() const
-    {
-        return mpszDefaultFilename;
-    }
-
-    /**
-     * Gets the default template filename for this class of scripts (empty if none).
-     *
-     * @note Just the filename, no path.
-     */
-    const char *getDefaultTemplateFilename() const
-    {
-        return mpszDefaultTemplateFilename;
-    }
-
-    /**
-     * Path to the file we last saved the script as.
-     */
-    const Utf8Str &getActualScriptPath() const
-    {
-        return mStrSavedPath;
-    }
-
-    /**
-     * Path where an original script is located
-     */
-    const Utf8Str &getOriginalScriptPath() const
-    {
-        return mStrOriginalPath;
-    }
-};
 
 
@@ -219,83 +94,4 @@
 };
 
-
-/**
- * Generic line based text script editor.
- *
- * This is used for editing isolinux configuratin files among other things.
- */
-class GeneralTextScript : public BaseTextScript
-{
-protected:
-    RTCList<RTCString>  mScriptContentByLines; /**< Content index by line. This contains the edited version. */
-    bool                mfDataParsed;          /**< Indicates whether the script has been parse() yet.  */
-
-public:
-    GeneralTextScript(VirtualBoxBase *pSetError, const char *pszDefaultTemplateFilename = NULL, const char *pszDefaultFilename = NULL)
-        : BaseTextScript(pSetError, pszDefaultTemplateFilename, pszDefaultFilename), mfDataParsed(false)
-    {}
-    virtual ~GeneralTextScript() {}
-
-    HRESULT parse();
-    HRESULT saveToString(Utf8Str &rStrDst);
-
-    //////////////////New functions//////////////////////////////
-
-    bool isDataParsed() const
-    {
-        return mfDataParsed;
-    }
-
-    /**
-     * Returns the actual size of script in lines
-     */
-    size_t getLineNumbersOfScript() const
-    {
-        return mScriptContentByLines.size();
-    }
-
-    /**
-     * Gets a read-only reference to the given line, returning Utf8Str::Empty if
-     * idxLine is out of range.
-     *
-     * @returns Line string reference or Utf8Str::Empty.
-     * @param   idxLine     The line number.
-     *
-     * @todo    RTCList doesn't allow this method to be const.
-     */
-    RTCString const &getContentOfLine(size_t idxLine);
-
-    /**
-     * Set new content of line
-     */
-    HRESULT setContentOfLine(size_t idxLine, const Utf8Str &newContent);
-
-    /**
-     * Find a substring in the script
-     * Returns a list with the found lines
-     * @throws std::bad_alloc
-     */
-    std::vector<size_t> findTemplate(const Utf8Str &rStrNeedle, RTCString::CaseSensitivity enmCase = RTCString::CaseSensitive);
-
-    /**
-     * In line @a idxLine replace the first occurence of @a rStrNeedle with
-     * @a rStrRelacement.
-     */
-    HRESULT findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement);
-
-    /**
-     * Append a string into the end of the given line.
-     */
-    HRESULT appendToLine(size_t idxLine, const Utf8Str &rStrToAppend);
-
-    /**
-     * Prepend a string in the beginning of the given line.
-     */
-    HRESULT prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend);
-
-    //////////////////New functions//////////////////////////////
-};
-
-
 #if 0 /* convert when we fix SUSE */
 /**
Index: /trunk/src/VBox/Main/src-all/TextScript.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/TextScript.cpp	(revision 76167)
+++ /trunk/src/VBox/Main/src-all/TextScript.cpp	(revision 76167)
@@ -0,0 +1,358 @@
+/* $Id$ */
+/** @file
+ * Classes for reading/parsing/saving text scripts (unattended installation, ++).
+ */
+
+/*
+ * Copyright (C) 2006-2017 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_MAIN_UNATTENDED
+#include "LoggingNew.h"
+#include "TextScript.h"
+
+#include <VBox/err.h>
+
+#include <iprt/ctype.h>
+#include <iprt/file.h>
+#include <iprt/vfs.h>
+#include <iprt/path.h>
+
+using namespace std;
+
+
+/*********************************************************************************************************************************
+*   BaseTextScript Implementation                                                                                                *
+*********************************************************************************************************************************/
+
+HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)
+{
+    /*
+     * Open the file for reading and figure it's size.  Capping the size
+     * at 16MB so we don't exaust the heap on bad input.
+     */
+    HRESULT   hrc;
+    RTVFSFILE hVfsFile;
+    int vrc = RTVfsFileOpenNormal(rStrFilename.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
+    if (RT_SUCCESS(vrc))
+    {
+        hrc = readFromHandle(hVfsFile, rStrFilename.c_str());
+        RTVfsFileRelease(hVfsFile);
+    }
+    else
+        hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
+    return hrc;
+}
+
+HRESULT BaseTextScript::readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename)
+{
+    /*
+     * Open the file for reading and figure it's size.  Capping the size
+     * at 16MB so we don't exaust the heap on bad input.
+     */
+    HRESULT  hrc;
+    uint64_t cbFile = 0;
+    int vrc = RTVfsFileGetSize(hVfsFile, &cbFile);
+    if (   RT_SUCCESS(vrc)
+        && cbFile < _16M)
+    {
+        /*
+         * Exploint the jolt() feature of RTCString and read the content directly into
+         * its storage buffer.
+         */
+        vrc = mStrScriptFullContent.reserveNoThrow((size_t)cbFile + 1);
+        if (RT_SUCCESS(vrc))
+        {
+            char *pszDst = mStrScriptFullContent.mutableRaw();
+            vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, pszDst, (size_t)cbFile, NULL);
+            pszDst[(size_t)cbFile] = '\0';
+            if (RT_SUCCESS(vrc))
+            {
+                /*
+                 * We must validate the encoding or we'll be subject to potential security trouble.
+                 * If this turns out to be problematic, we will need to implement codeset
+                 * conversion coping mechanisms.
+                 */
+                vrc = RTStrValidateEncodingEx(pszDst, (size_t)cbFile + 1,
+                                              RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
+                if (RT_SUCCESS(vrc))
+                {
+                    mStrScriptFullContent.jolt();
+                    return S_OK;
+                }
+
+                hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
+            }
+            else
+                hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);
+            mStrScriptFullContent.setNull();
+        }
+        else
+            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
+                                          cbFile, pszFilename);
+    }
+    else if (RT_SUCCESS(vrc))
+        hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG,
+                                      mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
+    else
+        hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileGetSize failed (%Rrc)"), vrc);
+    return hrc;
+}
+
+HRESULT BaseTextScript::save(const Utf8Str &rStrFilename, bool fOverwrite)
+{
+    /*
+     * We may have to append the default filename to the
+     */
+    const char *pszFilename = rStrFilename.c_str();
+    Utf8Str     strWithDefaultFilename;
+    if (   getDefaultFilename() != NULL
+        && *getDefaultFilename() != '\0'
+        && RTDirExists(rStrFilename.c_str()) )
+    {
+        try
+        {
+            strWithDefaultFilename = rStrFilename;
+            strWithDefaultFilename.append(RTPATH_SLASH);
+            strWithDefaultFilename.append(getDefaultFilename());
+        }
+        catch (std::bad_alloc &)
+        {
+            return E_OUTOFMEMORY;
+        }
+        pszFilename = strWithDefaultFilename.c_str();
+    }
+
+    /*
+     * Save the filename for later use.
+     */
+    try
+    {
+        mStrSavedPath = pszFilename;
+    }
+    catch (std::bad_alloc &)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    /*
+     * Use the saveToString method to produce the content.
+     */
+    Utf8Str strDst;
+    HRESULT hrc = saveToString(strDst);
+    if (SUCCEEDED(hrc))
+    {
+        /*
+         * Write the content.
+         */
+        RTFILE   hFile;
+        uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
+        if (fOverwrite)
+            fOpen |= RTFILE_O_CREATE_REPLACE;
+        else
+            fOpen |= RTFILE_O_CREATE;
+        int vrc = RTFileOpen(&hFile, pszFilename, fOpen);
+        if (RT_SUCCESS(vrc))
+        {
+            vrc = RTFileWrite(hFile, strDst.c_str(), strDst.length(), NULL);
+            if (RT_SUCCESS(vrc))
+            {
+                vrc = RTFileClose(hFile);
+                if (RT_SUCCESS(vrc))
+                {
+                    LogRelFlow(("GeneralTextScript::save(): saved %zu bytes to '%s'\n", strDst.length(), pszFilename));
+                    return S_OK;
+                }
+            }
+            RTFileClose(hFile);
+            RTFileDelete(pszFilename);
+            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
+        }
+        else
+            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
+    }
+    return hrc;
+}
+
+
+
+/*********************************************************************************************************************************
+*   GeneralTextScript Implementation                                                                                             *
+*********************************************************************************************************************************/
+
+HRESULT GeneralTextScript::parse()
+{
+//  AssertReturn(!mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "parse called more than once"));
+
+    /*
+     * Split the raw context into an array of lines.
+     */
+    try
+    {
+        mScriptContentByLines = mStrScriptFullContent.split("\n");
+    }
+    catch (std::bad_alloc &)
+    {
+        mScriptContentByLines.clear();
+        return E_OUTOFMEMORY;
+    }
+
+    mfDataParsed = true;
+    return S_OK;
+}
+
+HRESULT GeneralTextScript::saveToString(Utf8Str &rStrDst)
+{
+    AssertReturn(mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "saveToString() called before parse()"));
+
+    /*
+     * Calc the required size first.
+     */
+    size_t const cLines = mScriptContentByLines.size();
+    size_t       cbTotal = 1;
+    for (size_t iLine = 0; iLine < cLines; iLine++)
+        cbTotal = mScriptContentByLines[iLine].length() + 1;
+
+    /*
+     * Clear the output and try reserve sufficient space.
+     */
+    rStrDst.setNull();
+
+    int vrc = rStrDst.reserveNoThrow(cbTotal);
+    if (RT_FAILURE(vrc))
+        return E_OUTOFMEMORY;
+
+    /*
+     * Assemble the output.
+     */
+    for (size_t iLine = 0; iLine < cLines; iLine++)
+    {
+        try
+        {
+            rStrDst.append(mScriptContentByLines[iLine]);
+            rStrDst.append('\n');
+        }
+        catch (std::bad_alloc &)
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    return S_OK;
+}
+
+const RTCString &GeneralTextScript::getContentOfLine(size_t idxLine)
+{
+    if (idxLine < mScriptContentByLines.size())
+        return mScriptContentByLines[idxLine];
+    return Utf8Str::Empty;
+}
+
+
+HRESULT GeneralTextScript::setContentOfLine(size_t idxLine, const Utf8Str &rStrNewLine)
+{
+    AssertReturn(idxLine < mScriptContentByLines.size(),
+                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "attempting to set line %zu when there are only %zu lines",
+                                          idxLine, mScriptContentByLines.size()));
+    try
+    {
+        mScriptContentByLines[idxLine] = rStrNewLine;
+    }
+    catch (std::bad_alloc &)
+    {
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+vector<size_t> GeneralTextScript::findTemplate(const Utf8Str &rStrNeedle,
+                                               RTCString::CaseSensitivity enmCase /*= RTCString::CaseSensitive*/)
+{
+    vector<size_t> vecHitLineNumbers;
+    size_t const   cLines = mScriptContentByLines.size();
+    for (size_t iLine = 0; iLine < cLines; iLine++)
+        if (mScriptContentByLines[iLine].contains(rStrNeedle, enmCase))
+            vecHitLineNumbers.push_back(iLine);
+
+    return vecHitLineNumbers;
+}
+
+HRESULT GeneralTextScript::findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement)
+{
+    AssertReturn(idxLine < mScriptContentByLines.size(),
+                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE,
+                                          "attempting search&replace in line %zu when there are only %zu lines",
+                                          idxLine, mScriptContentByLines.size()));
+
+    RTCString &rDstString = mScriptContentByLines[idxLine];
+    size_t const offNeedle = rDstString.find(&rStrNeedle);
+    if (offNeedle != RTCString::npos)
+    {
+        try
+        {
+            RTCString strBefore(rDstString, 0, offNeedle);
+            RTCString strAfter(rDstString, offNeedle + rStrNeedle.length());
+            rDstString = strBefore;
+            strBefore.setNull();
+            rDstString.append(rStrReplacement);
+            rDstString.append(strAfter);
+        }
+        catch (std::bad_alloc &)
+        {
+            return E_OUTOFMEMORY;
+        }
+    }
+    return S_OK;
+}
+
+HRESULT GeneralTextScript::appendToLine(size_t idxLine, const Utf8Str &rStrToAppend)
+{
+    AssertReturn(idxLine < mScriptContentByLines.size(),
+                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "appending to line %zu when there are only %zu lines",
+                                          idxLine, mScriptContentByLines.size()));
+
+    try
+    {
+        mScriptContentByLines[idxLine].append(rStrToAppend);
+    }
+    catch (std::bad_alloc &)
+    {
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+HRESULT GeneralTextScript::prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend)
+{
+    AssertReturn(idxLine < mScriptContentByLines.size(),
+                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "prepending to line %zu when there are only %zu lines",
+                                          idxLine, mScriptContentByLines.size()));
+
+    RTCString &rDstString = mScriptContentByLines[idxLine];
+    try
+    {
+        RTCString strCopy;
+        rDstString.swap(strCopy);
+        rDstString.reserve(strCopy.length() + rStrToPrepend.length() + 1);
+        rDstString = rStrToPrepend;
+        rDstString.append(strCopy);
+    }
+    catch (std::bad_alloc &)
+    {
+        return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
Index: /trunk/src/VBox/Main/src-server/UnattendedScript.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/UnattendedScript.cpp	(revision 76166)
+++ /trunk/src/VBox/Main/src-server/UnattendedScript.cpp	(revision 76167)
@@ -1,5 +1,5 @@
 /* $Id$ */
 /** @file
- * Implementeation of algorithms which read/parse/save scripts for unattended installation.
+ * Classes for reading/parsing/saving scripts for unattended installation.
  */
 
@@ -40,171 +40,9 @@
 
 
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-/*
-*
-*
-*  Implementation BaseTextScript functions
-*
-*/
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-HRESULT BaseTextScript::read(const Utf8Str &rStrFilename)
-{
-    /*
-     * Open the file for reading and figure it's size.  Capping the size
-     * at 16MB so we don't exaust the heap on bad input.
-     */
-    HRESULT   hrc;
-    RTVFSFILE hVfsFile;
-    int vrc = RTVfsFileOpenNormal(rStrFilename.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, &hVfsFile);
-    if (RT_SUCCESS(vrc))
-    {
-        hrc = readFromHandle(hVfsFile, rStrFilename.c_str());
-        RTVfsFileRelease(hVfsFile);
-    }
-    else
-        hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to open '%s' (%Rrc)"), rStrFilename.c_str(), vrc);
-    return hrc;
-}
-
-HRESULT BaseTextScript::readFromHandle(RTVFSFILE hVfsFile, const char *pszFilename)
-{
-    /*
-     * Open the file for reading and figure it's size.  Capping the size
-     * at 16MB so we don't exaust the heap on bad input.
-     */
-    HRESULT  hrc;
-    uint64_t cbFile = 0;
-    int vrc = RTVfsFileGetSize(hVfsFile, &cbFile);
-    if (   RT_SUCCESS(vrc)
-        && cbFile < _16M)
-    {
-        /*
-         * Exploint the jolt() feature of RTCString and read the content directly into
-         * its storage buffer.
-         */
-        vrc = mStrScriptFullContent.reserveNoThrow((size_t)cbFile + 1);
-        if (RT_SUCCESS(vrc))
-        {
-            char *pszDst = mStrScriptFullContent.mutableRaw();
-            vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, pszDst, (size_t)cbFile, NULL);
-            pszDst[(size_t)cbFile] = '\0';
-            if (RT_SUCCESS(vrc))
-            {
-                /*
-                 * We must validate the encoding or we'll be subject to potential security trouble.
-                 * If this turns out to be problematic, we will need to implement codeset
-                 * conversion coping mechanisms.
-                 */
-                vrc = RTStrValidateEncodingEx(pszDst, (size_t)cbFile + 1,
-                                              RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
-                if (RT_SUCCESS(vrc))
-                {
-                    mStrScriptFullContent.jolt();
-                    return S_OK;
-                }
-
-                hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("'%s' isn't valid UTF-8: %Rrc"), pszFilename, vrc);
-            }
-            else
-                hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error reading '%s': %Rrc"), pszFilename, vrc);
-            mStrScriptFullContent.setNull();
-        }
-        else
-            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Failed to allocate memory (%'RU64 bytes) for '%s'"),
-                                          cbFile, pszFilename);
-    }
-    else if (RT_SUCCESS(vrc))
-        hrc = mpSetError->setErrorVrc(VERR_FILE_TOO_BIG,
-                                      mpSetError->tr("'%s' is too big (max 16MB): %'RU64"), pszFilename, cbFile);
-    else
-        hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("RTVfsFileGetSize failed (%Rrc)"), vrc);
-    return hrc;
-}
-
-HRESULT BaseTextScript::save(const Utf8Str &rStrFilename, bool fOverwrite)
-{
-    /*
-     * We may have to append the default filename to the
-     */
-    const char *pszFilename = rStrFilename.c_str();
-    Utf8Str     strWithDefaultFilename;
-    if (   getDefaultFilename() != NULL
-        && *getDefaultFilename() != '\0'
-        && RTDirExists(rStrFilename.c_str()) )
-    {
-        try
-        {
-            strWithDefaultFilename = rStrFilename;
-            strWithDefaultFilename.append(RTPATH_SLASH);
-            strWithDefaultFilename.append(getDefaultFilename());
-        }
-        catch (std::bad_alloc &)
-        {
-            return E_OUTOFMEMORY;
-        }
-        pszFilename = strWithDefaultFilename.c_str();
-    }
-
-    /*
-     * Save the filename for later use.
-     */
-    try
-    {
-        mStrSavedPath = pszFilename;
-    }
-    catch (std::bad_alloc &)
-    {
-        return E_OUTOFMEMORY;
-    }
-
-    /*
-     * Use the saveToString method to produce the content.
-     */
-    Utf8Str strDst;
-    HRESULT hrc = saveToString(strDst);
-    if (SUCCEEDED(hrc))
-    {
-        /*
-         * Write the content.
-         */
-        RTFILE   hFile;
-        uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_ALL;
-        if (fOverwrite)
-            fOpen |= RTFILE_O_CREATE_REPLACE;
-        else
-            fOpen |= RTFILE_O_CREATE;
-        int vrc = RTFileOpen(&hFile, pszFilename, fOpen);
-        if (RT_SUCCESS(vrc))
-        {
-            vrc = RTFileWrite(hFile, strDst.c_str(), strDst.length(), NULL);
-            if (RT_SUCCESS(vrc))
-            {
-                vrc = RTFileClose(hFile);
-                if (RT_SUCCESS(vrc))
-                {
-                    LogRelFlow(("GeneralTextScript::save(): saved %zu bytes to '%s'\n", strDst.length(), pszFilename));
-                    return S_OK;
-                }
-            }
-            RTFileClose(hFile);
-            RTFileDelete(pszFilename);
-            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error writing to '%s' (%Rrc)"), pszFilename, vrc);
-        }
-        else
-            hrc = mpSetError->setErrorVrc(vrc, mpSetError->tr("Error creating/replacing '%s' (%Rrc)"), pszFilename, vrc);
-    }
-    return hrc;
-}
-
 #ifdef VBOX_WITH_UNATTENDED
 
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-/*
-*
-*
-*  Implementation UnattendedScriptTemplate methods
-*
-*/
-//////////////////////////////////////////////////////////////////////////////////////////////////////
+/*********************************************************************************************************************************
+*   UnattendedScriptTemplate Implementation                                                                                      *
+*********************************************************************************************************************************/
 
 UnattendedScriptTemplate::UnattendedScriptTemplate(Unattended *pUnattended, const char *pszDefaultTemplateFilename,
@@ -641,185 +479,10 @@
 
 
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-/*
-*
-*
-*  Implementation GeneralTextScript functions
-*
-*/
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-HRESULT GeneralTextScript::parse()
-{
-//  AssertReturn(!mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "parse called more than once"));
-
-    /*
-     * Split the raw context into an array of lines.
-     */
-    try
-    {
-        mScriptContentByLines = mStrScriptFullContent.split("\n");
-    }
-    catch (std::bad_alloc &)
-    {
-        mScriptContentByLines.clear();
-        return E_OUTOFMEMORY;
-    }
-
-    mfDataParsed = true;
-    return S_OK;
-}
-
-HRESULT GeneralTextScript::saveToString(Utf8Str &rStrDst)
-{
-    AssertReturn(mfDataParsed, mpSetError->setErrorBoth(E_FAIL, VERR_WRONG_ORDER, "saveToString() called before parse()"));
-
-    /*
-     * Calc the required size first.
-     */
-    size_t const cLines = mScriptContentByLines.size();
-    size_t       cbTotal = 1;
-    for (size_t iLine = 0; iLine < cLines; iLine++)
-        cbTotal = mScriptContentByLines[iLine].length() + 1;
-
-    /*
-     * Clear the output and try reserve sufficient space.
-     */
-    rStrDst.setNull();
-
-    int vrc = rStrDst.reserveNoThrow(cbTotal);
-    if (RT_FAILURE(vrc))
-        return E_OUTOFMEMORY;
-
-    /*
-     * Assemble the output.
-     */
-    for (size_t iLine = 0; iLine < cLines; iLine++)
-    {
-        try
-        {
-            rStrDst.append(mScriptContentByLines[iLine]);
-            rStrDst.append('\n');
-        }
-        catch (std::bad_alloc &)
-        {
-            return E_OUTOFMEMORY;
-        }
-    }
-
-    return S_OK;
-}
-
-const RTCString &GeneralTextScript::getContentOfLine(size_t idxLine)
-{
-    if (idxLine < mScriptContentByLines.size())
-        return mScriptContentByLines[idxLine];
-    return Utf8Str::Empty;
-}
-
-
-HRESULT GeneralTextScript::setContentOfLine(size_t idxLine, const Utf8Str &rStrNewLine)
-{
-    AssertReturn(idxLine < mScriptContentByLines.size(),
-                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "attempting to set line %zu when there are only %zu lines",
-                                          idxLine, mScriptContentByLines.size()));
-    try
-    {
-        mScriptContentByLines[idxLine] = rStrNewLine;
-    }
-    catch (std::bad_alloc &)
-    {
-        return E_OUTOFMEMORY;
-    }
-    return S_OK;
-}
-
-vector<size_t> GeneralTextScript::findTemplate(const Utf8Str &rStrNeedle,
-                                               RTCString::CaseSensitivity enmCase /*= RTCString::CaseSensitive*/)
-{
-    vector<size_t> vecHitLineNumbers;
-    size_t const   cLines = mScriptContentByLines.size();
-    for (size_t iLine = 0; iLine < cLines; iLine++)
-        if (mScriptContentByLines[iLine].contains(rStrNeedle, enmCase))
-            vecHitLineNumbers.push_back(iLine);
-
-    return vecHitLineNumbers;
-}
-
-HRESULT GeneralTextScript::findAndReplace(size_t idxLine, const Utf8Str &rStrNeedle, const Utf8Str &rStrReplacement)
-{
-    AssertReturn(idxLine < mScriptContentByLines.size(),
-                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE,
-                                          "attempting search&replace in line %zu when there are only %zu lines",
-                                          idxLine, mScriptContentByLines.size()));
-
-    RTCString &rDstString = mScriptContentByLines[idxLine];
-    size_t const offNeedle = rDstString.find(&rStrNeedle);
-    if (offNeedle != RTCString::npos)
-    {
-        try
-        {
-            RTCString strBefore(rDstString, 0, offNeedle);
-            RTCString strAfter(rDstString, offNeedle + rStrNeedle.length());
-            rDstString = strBefore;
-            strBefore.setNull();
-            rDstString.append(rStrReplacement);
-            rDstString.append(strAfter);
-        }
-        catch (std::bad_alloc &)
-        {
-            return E_OUTOFMEMORY;
-        }
-    }
-    return S_OK;
-}
-
-HRESULT GeneralTextScript::appendToLine(size_t idxLine, const Utf8Str &rStrToAppend)
-{
-    AssertReturn(idxLine < mScriptContentByLines.size(),
-                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "appending to line %zu when there are only %zu lines",
-                                          idxLine, mScriptContentByLines.size()));
-
-    try
-    {
-        mScriptContentByLines[idxLine].append(rStrToAppend);
-    }
-    catch (std::bad_alloc &)
-    {
-        return E_OUTOFMEMORY;
-    }
-    return S_OK;
-}
-
-HRESULT GeneralTextScript::prependToLine(size_t idxLine, const Utf8Str &rStrToPrepend)
-{
-    AssertReturn(idxLine < mScriptContentByLines.size(),
-                 mpSetError->setErrorBoth(E_FAIL, VERR_OUT_OF_RANGE, "prepending to line %zu when there are only %zu lines",
-                                          idxLine, mScriptContentByLines.size()));
-
-    RTCString &rDstString = mScriptContentByLines[idxLine];
-    try
-    {
-        RTCString strCopy;
-        rDstString.swap(strCopy);
-        rDstString.reserve(strCopy.length() + rStrToPrepend.length() + 1);
-        rDstString = rStrToPrepend;
-        rDstString.append(strCopy);
-    }
-    catch (std::bad_alloc &)
-    {
-        return E_OUTOFMEMORY;
-    }
-    return S_OK;
-}
 
 #if 0 /* Keeping this a reference */
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-/*
-*
-*
-*  Implementation UnattendedSUSEXMLScript functions
-*
-*/
-/////////////////////////////////////////////////////////////////////////////////////////////////////
+/*********************************************************************************************************************************
+*   UnattendedSUSEXMLScript Implementation                                                                                       *
+*********************************************************************************************************************************/
+
 HRESULT UnattendedSUSEXMLScript::parse()
 {
