[Helix-client-dev] CR/CN: Accepting UTF8 command line arguments instead of wide chars. [GMPMetaEditor branch]

Petar Basic <[email protected]> Wed, 20 Jan 2010 20:18:01 +0100
Newsgroups gmane.comp.multimedia.helix.devel
Message-ID <[email protected]>
Modified by: pbasic at real.com
Date: 2010/01/20
Project: GMPMetaEditor (meta3gp.exe)

Synopsis:
Accepting UTF8 command line arguments instead of wide chars.
[GMPMetaEditor branch]

Details:
Although wide character program arguments are passed correctly from
the Windows console, this is not the case when the program gets called
from a batch script or from a WSH script.  To be able to pass
international characters to the program, -utf8in program option has
been implemented instead of using wmain main entry prototype.  -utf8in
tells the program to treat command line arguments as UTF8 formatted
strings.

Tested on Windows and Solaris from console and from batch scripts.

Files Modified:
datatype/tools/dtdriver/apps/meta3gp/main.cpp

Platforms and Profiles Affected:
All

Image Size and Heap Use impact:
None

Platforms and Profiles Build Verified:
system id: win32-i386-vc7, sunos-5.10-sparc-studio11
profile: helix-client-all-defines

Platforms and Profiles Functionality Verified:
x86 Windows XP SP2
Sparc SunOS 5.10

Branch:
GMPMetaEditor

Copyright assignment:
I am a RealNetworks employee or contractor.

_______________________________________________
Helix-client-dev mailing list
[email protected]
http://lists.helixcommunity.org/mailman/listinfo/helix-client-dev
datatype_tools_dtdriver_apps_meta3gp.diff (application/octet-stream, 34.3 KB)
Index: main.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/main.cpp,v
retrieving revision 1.7.2.5
diff -d -H -w -U30 -r1.7.2.5 main.cpp
--- main.cpp	18 Jan 2010 21:34:33 -0000	1.7.2.5
+++ main.cpp	20 Jan 2010 19:11:04 -0000
@@ -46,157 +46,98 @@
 #include "hxtypes.h"
 #include "hlxosstr.h"
 #include "ffdriver.h"
 #include "cstrmsrt.h"
 #include "hxmemprb.h"
 #include "hxtick.h"
 #include "chxpckts.h"
 #include "pckunpck.h"
 #include "dllpath.h"
 #include "filespecutils.h"
 #include "metainfokeys.h"
 #include "uniconv.h"
 #include "proptools.h"
 #include "dllacces.h"
 #include "ihxmetaeditor.h"
 #include "HXXmlInputParser.h"
 #include "metautil.h"
 
 #include "meta3gp.ver"
 
 #ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
 #include "mycrypt.h"
 #endif
 
 
 /****************************************************************************
  *  Meta-data command line editor.
  *  Build-time configuration options.
  */
 
-// uncomment to force usage of legacy strings on Windows
-// (only relevant for command-line argument transfer)
-//#define FORCE_LEGACY_CHAR_COMMAND_LINE 1
-
 // environment variable name
 #define PLUGIN_PATH_ENV_VAR_NAME "META3GP_PLUGIN_PATH"
 
 
 /****************************************************************************
  *  Component operational modes
  */
 HXBOOL g_bUseDefaultMetaEditorProcessor = FALSE;
 HXBOOL g_bUseDTDriverSynchronousMode = TRUE;
 
 
 /****************************************************************************
- *  System character type macros
- */
-#ifdef USE_WIDE_CHAR_COMMAND_LINE
-#undef USE_WIDE_CHAR_COMMAND_LINE
-#endif
-
-#if !defined(FORCE_LEGACY_CHAR_COMMAND_LINE) && defined(_WINDOWS)
-#define USE_WIDE_CHAR_COMMAND_LINE 1
-#endif
-
-
-#ifdef _T
-#undef _T
-#endif
-#ifdef TCHAR
-#undef TCHAR
-#endif
-#ifdef TMAIN
-#undef TMAIN
-#endif
-
-
-#ifdef USE_WIDE_CHAR_COMMAND_LINE
-
-#define _T(Val) L##Val
-#define TCHAR wchar_t
-#define TMAIN wmain
-#define TCHXStringCtor(Val) CHXString((const char*)CCPFromWCharT(Val))
-#define TUTF8EncodedStringCtor(Val) EncodedString((const char*)::UTF8FromWCharT(Val), HX_TEXT_ENCODING_TYPE_UTF8)
-
-#else
-
-#define _T(Val) Val
-#define TCHAR char
-#define TMAIN main
-#define TCHXStringCtor(Val) CHXString(Val)
-#define TUTF8EncodedStringCtor(Val) EncodedString((const char*)::UTF8FromCCP(Val), HX_TEXT_ENCODING_TYPE_UTF8)
-
-#endif //USE_WIDE_CHAR_COMMAND_LINE
-
-
-/****************************************************************************
- *  Build-time messages
- */
-#ifdef _WINDOWS
-
-#ifdef USE_WIDE_CHAR_COMMAND_LINE
-#   pragma message("Using wide-string command-line arguments")
-#else
-#   pragma message("Using legacy-string command-line arguments")
-#endif
-
-#endif //_WINDOWS
-
-
-/****************************************************************************
  *  DLLAccessPath Variable
  */
 ENABLE_DLLACCESS_PATHS(g_Meta3GPAccessPath);
 
 
 /****************************************************************************
  *  Defines
  */
 #define PROGRAM_VENDOR_STRING       "RealNetworks"
 #define PROGRAM_NAME_STRING         PROGRAM_VENDOR_STRING" meta-data editor"
 #define PROGRAM_COPYRIGHT_STRING    "Copyright (c) "PROGRAM_VENDOR_STRING" 2010"
 
 // input/output control
 #ifdef _WINDOWS
 #define OPTION_STRING_ASYNCMODE      "dev-asyncmode"
 #endif //_WINDOWS
 
 #define OPTION_STRING_DEFMETAPROC    "dev-defmetaproc"
 #define OPTION_STRING_INPUTFILE      "if"
 #define OPTION_STRING_OUTPUTFILE     "of"
 #define OPTION_STRING_XMLINPUTFILE   "xmlin"
 #define OPTION_STRING_XMLOUTPUTFILE  "xmlout"
 #define OPTION_STRING_CLEARMETADATA  "metaclear"
 #define OPTION_STRING_METASTYLE      "metastyle"
-#define OPTION_STRING_UTF16OUTPUT    "utf16"
+#define OPTION_STRING_UTF16OUTPUT    "utf16out"
+#define OPTION_STRING_UTF8INPUT      "utf8in"
 #define OPTION_STRING_ID3V240OUTPUT  "id3v240"
 #define OPTION_STRING_ID3V230OUTPUT  "id3v230"
 #define OPTION_STRING_ID3V2NOOUTPUT  "id3v2no"
 #define OPTION_STRING_OVERWRITEFILE  "overwrite"
 #define OPTION_STRING_PRINTMETADATA  "print"
 #define OPTION_STRING_HELP           "help"
 #define OPTION_STRING_GENERATEHASH   "audiohash"
 #define OPTION_STRING_LOGFILE        "log"
 
 // common metadata
 #define OPTION_STRING_TITLE            "title"
 #define OPTION_STRING_ARTIST           "artist"
 #define OPTION_STRING_ALBUM            "album"
 #define OPTION_STRING_GENRE            "genre"
 #define OPTION_STRING_COMPOSER         "composer"
 #define OPTION_STRING_COMMENT          "comment"
 #define OPTION_STRING_TRACKNUMBER      "track"
 #define OPTION_STRING_YEAR             "year"
 
 #define OPTION_STRING_PICTURE_ADD      "addpic"
 #define OPTION_STRING_PICTURE_REMOVE   "rempic"
 #define OPTION_STRING_PICTURE_CLEAR    "clrpic"
 #define OPTION_STRING_PICTURE_EXTRACT  "savepic"
 
 #define OPTION_STRING_UITS_INSERT      "insertsignature"
 #define OPTION_STRING_UITS_EXTRACT     "extractsignature"
 
 // iTunes specific metadata
 #define OPTION_STRING_SOFTWARE     "software"
 #define OPTION_STRING_ENCODEDBY    "encodedby"
@@ -415,73 +356,73 @@
     {
         int leftColumnWidth = 0;
 
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* od = (OptionDesc*)descs.GetAt(i);
             int width = od->GetLeftColumnWidth();
             if(width > leftColumnWidth)
             {
                 leftColumnWidth = width;
             }
         }
         return leftColumnWidth;
     }
 
     void PrintColumns(int columnSpacing = 1)
     {
         int leftColumnWidth = CalcLeftColumnWidth() + columnSpacing;
 
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* od = (OptionDesc*)descs.GetAt(i);
             CHXString line = od->BuildLine(leftColumnWidth);
             if(!line.IsEmpty())
             {
                 printf("%s\n", (const char*)line);
             }
         }
     }
 
-    HXBOOL IsOption(const TCHAR* pArg)
+    HXBOOL IsOption(const char* pArg)
     {
         if(!pArg)
         {
             return FALSE;
         }
 
-        if(pArg[0] != _T('-'))
+        if(pArg[0] != '-')
         {
             return FALSE;
         }
 
-        CHXString arg = TCHXStringCtor(pArg + 1);
+        CHXString arg(pArg + 1);
 
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* od = (OptionDesc*)descs.GetAt(i);
             if(arg == od->GetOptionString())
             {
                 return TRUE;
             }
         }
         return FALSE;
     }
 
     OptionDesc* GetOptionDesc(CHXString& strArg) const
     {
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* od = (OptionDesc*)descs.GetAt(i);
             if(strArg == od->GetOptionString())
             {
                 return od;
             }
         }
         return NULL;
     }
 
     OptionDesc* GetOptionDescWithPath(CHXString& strArg) const
     {
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* od = (OptionDesc*)descs.GetAt(i);
@@ -498,61 +439,61 @@
         for(int i = 0; i < descs.GetSize(); i++)
         {
             OptionDesc* desc = (OptionDesc*)descs.GetAt(i);
 
             for(int iPath = 0; iPath < desc->GetNumXPaths(); iPath++)
             {
                 CHXString xpath = desc->GetXPath(iPath);
                 if(!xpath.IsEmpty())
                 {
                     xmlPathDescs.Add(new XmlPathDesc(xpath));
                 }
             }
         }
     }
 
 private:
     CHXPtrArray descs;
 };
 
 void DisplayProgramInfo()
 {
     const char* pszDbg = "";
 #if defined(DEBUG) || defined(_DEBUG)
     pszDbg = ".debug";
 #endif
 
     printf("\n--- %s ---\n    %s\n    Version %s%s\n\n",
             PROGRAM_NAME_STRING, PROGRAM_COPYRIGHT_STRING, TARVER_STRING_VERSION, pszDbg);
 }
 
-void DisplayUsage(const TCHAR* argv0, OptionRegistry& optionReg)
+void DisplayUsage(const char* argv0, OptionRegistry& optionReg)
 {
     CHXString exeName = CHXFileSpecUtils::GetCurrentApplication().GetName();
 
     printf("usage: %s [ -option [value]... ]...\n", (const char*)exeName);
     printf("with options:\n");
 
     optionReg.PrintColumns(2);
 }
 
 CHXString GetUTCTimeString()
 {
     time_t currTime = time(0);
     tm* pUTCTime = gmtime(&currTime);
 
     const UINT32 bufSize = 64;
     char buffer[bufSize];
     strftime(buffer, bufSize, "%Y-%m-%dT%H:%M:%SZ", pUTCTime);
 
     return CHXString(buffer);
 }
 
 
 /****************************************************************************
 *  Asynchronous mode helpers
 */
 void SignalAsyncDriveEnd()
 {
 #ifdef _WINDOWS
     ::PostMessage(0, (WM_USER + 202), 0, 0);
 #else
@@ -773,145 +714,164 @@
     const EncodedString& GetEffectiveOptionValueUTF8() const
     {
         return XmlOptionValueUTF8.IsEmpty() ? OptionValueUTF8 : XmlOptionValueUTF8;
     }
 
     // XML value has precedence over command-line value
     CHXString GetEffectiveOptionValueCCP() const
     {
         const EncodedString& val = GetEffectiveOptionValueUTF8();
         return CHXString((const char*)CCPFromUTF8(val.GetData()));
     }
 
     CHXString OptionName;
     EncodedString OptionValueUTF8;
     EncodedString XmlOptionValueUTF8;
 };
 
 /****************************************************************************
 *  Param extractors
 */
 enum eCommandLineProcessorPhase
 {
     CLPP_IndependentOptions = 0,
     CLPP_DependentOptions,
     CLPP_Done
 };
 
 class ArgVars
 {
 public:
-    ArgVars(int argc_, TCHAR* argv_[], OptionRegistry& optionReg_)
+    ArgVars(int argc_, char* argv_[], OptionRegistry& optionReg_)
         : argc(argc_)
         , argv(argv_)
         , argPosition(0)
         , optionReg(optionReg_)
     { }
 
     void ResetPosition(int pos = 1)
     {
         argPosition = pos;
     }
 
     HXBOOL ReachedEndPosition()
     {
         return (argPosition >= argc);
     }
 
     void MovePosition(int step = 1)
     {
         argPosition += step;
         if(argPosition < 0)
         {
             argPosition = 0;
         }
     }
 
-    const TCHAR* CurrentRawArg()
+    const char* CurrentRawArg()
     {
         if(argPosition < argc)
         {
             return argv[argPosition];
         }
         return 0;
     }
 
     // Returns pointer to option name
-    const TCHAR* CurrentOption(HXBOOL bWithPrefix)
+    const char* CurrentOption(HXBOOL bWithPrefix)
     {
         if(argPosition < argc)
         {
-            const TCHAR* pVal = argv[argPosition];
-            if(pVal && (pVal[0] == _T('-')))
+            const char* pVal = argv[argPosition];
+            if(pVal && (pVal[0] == '-'))
             {
                 return bWithPrefix ? pVal : (pVal + 1);
             }
         }
         return 0;
     }
 
-    const TCHAR* CurrentArg(UINT32 offset, HXBOOL bOptional, HXBOOL bPrintError)
+    const char* CurrentArg(UINT32 offset, HXBOOL bOptional, HXBOOL bPrintError)
     {
         int argIndex = argPosition + (int)offset;
         if(argIndex < argc)
         {
-            const TCHAR* pVal = argv[argIndex];
+            const char* pVal = argv[argIndex];
             if(pVal && !optionReg.IsOption(pVal))
             {
                 return pVal;
             }
         }
 
         if(!bOptional && bPrintError)
         {
-            CHXString strOption = TCHXStringCtor(CurrentOption(TRUE));
-            printf("Missing argument for option: %s\n", (const char*)strOption);
+            printf("Missing argument for option: %s\n", CurrentOption(TRUE));
         }
         return 0;
     }
 
-    void DumpCommandLine()
+    void DumpCommandLine(HXBOOL bInterpretAsUTF8)
     {
+#ifdef _WINDOWS
+        printf(::GetCommandLineA());
+#else
         for(int i = 0; i < argc; i++)
         {
-#ifdef USE_WIDE_CHAR_COMMAND_LINE
-            wprintf(L"%ls ", argv[i]);
-#else
+            HXBOOL bFoundWhitespace = 0;
+            if(strchr(argv[i], ' '))
+            {
+                bFoundWhitespace = TRUE;
+                printf("\"");
+            }
+
+            if(bInterpretAsUTF8)
+            {
+                EncStrUtils::PrintText(argv[i], HX_TEXT_ENCODING_TYPE_UTF8);
+            }
+            else
+            {
             printf("%s ", argv[i]);
-#endif
         }
+
+            if(bFoundWhitespace)
+            {
+                printf("\"");
+            }
+            printf(" ");
+        }
+#endif
         printf("\n");
     }
 
 private:
     int argc;
-    TCHAR** argv;
+    char** argv;
     int argPosition;
     OptionRegistry& optionReg;
 };
 
 void ReportUnsupportedMetaStyleOption(const char* optionName)
 {
     printf("Option -%s not supported in combination with specified metastyle(s)\n", optionName);
 }
 
 void ReportInvalidValueForOption(const char* optionName, const EncodedString& optionValueUTF8)
 {
     printf("Invalid value for option -%s: ", optionName);
     EncStrUtils::PrintTextUTF8(optionValueUTF8.GetData());
     printf("\n");
 }
 
 HX_RESULT ProcessStringOption(bool bSkipArgOnly, InputOption* option, MetaInfo& metainfo,
                              MetaInfo::eStringMetaItem itemName, UINT32 metaFlavorFlags)
 {
     if(option->OptionValueUTF8.IsEmpty() && option->XmlOptionValueUTF8.IsEmpty())
     {
         return HXR_PARSE_ERROR;
     }
 
     if(bSkipArgOnly)
     {
         return HXR_OK;
     }
 
     if(option->XmlOptionValueUTF8.IsEmpty())
@@ -1218,71 +1178,80 @@
         }
         else
         {
             printf("Failed to open picture file: %s\n", (const char*)sFileName);
             progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_PICTURE_FILE;
         }
 
         // export frame
         if(SUCCEEDED(retVal) && pFrame)
         {
             if(!aAddedAPICFrames.AddIfUnique(pFrame))
             {
                 retVal = HXR_FAILED;
             }
         }
 
         if(FAILED(retVal))
         {
             // cleanup
             HX_DELETE(pFrame);
         }
 
         return retVal;
     }
 
     ReportUnsupportedMetaStyleOption(option->OptionName);
     return HXR_PARSE_ERROR;
 }
 
 // Only moves argVars position if successful
-HX_RESULT CopyOptionArgumentString(ArgVars& argVars, EncodedString& sOut, HXBOOL bOptional)
+HX_RESULT CopyOptionArgumentString(ArgVars& argVars, HXBOOL bInterpretAsUTF8,
+                                   EncodedString& sOut, HXBOOL bOptional)
 {
     sOut.Clear();
 
-    const TCHAR* pVal = argVars.CurrentArg(1, bOptional, TRUE);
+    const char* pVal = argVars.CurrentArg(1, bOptional, TRUE);
     if(!pVal)
     {
         return bOptional ? HXR_OK : HXR_PARSE_ERROR;
     }
 
-    sOut = TUTF8EncodedStringCtor(pVal);
+    if(bInterpretAsUTF8)
+    {
+        sOut.Set(pVal, HX_TEXT_ENCODING_TYPE_UTF8);
+    }
+    else
+    {
+        sOut.Set((const char*)::UTF8FromCCP(pVal), HX_TEXT_ENCODING_TYPE_UTF8);
+    }
+
     argVars.MovePosition(1);
 
     return HXR_OK;
 }
 
 class InputOptions
 {
 public:
     InputOptions() 
         : position(0)
     {
     }
 
     ~InputOptions()
     {
         Clear();
     }
 
     void Clear()
     {
         for(int i = 0; i < options.GetSize(); i++)
         {
             delete (InputOption*)options.GetAt(i);
         }
 
         options.RemoveAll();
         position = 0;
     }
 
     void Add(InputOption* inputOpt)
@@ -1339,120 +1308,119 @@
         for(int i = 0; i < options.GetSize(); i++)
         {
             InputOption* option = (InputOption*)options.GetAt(i);
 
             if(option->OptionName == optionName)
             {
                 return option;
             }
         }
 
         return 0;
     }
 
     // Returns pointer to option
     InputOption* CurrentOption() const
     {
         if(position < options.GetSize())
         {
             return (InputOption*)options.GetAt(position);
         }
 
         return 0;
     }
 
 private:
     CHXPtrArray options;
     int position;
 };
 
 HX_RESULT ParseCommandLineInputOptions(ArgVars& argVars, OptionRegistry& optionReg, InputOptions& inputOptions,
-                                       HXBOOL bStrictMode, HXBOOL bPrintErrors)
+                                       HXBOOL bInterpretAsUTF8, HXBOOL bStrictMode, HXBOOL bPrintErrors)
 {
     HX_RESULT retVal = HXR_OK;
 
     for(argVars.ResetPosition(1); SUCCEEDED(retVal) && !argVars.ReachedEndPosition(); argVars.MovePosition(1))
     {
         // accept option format only
-        CHXString strOption = TCHXStringCtor(argVars.CurrentOption(FALSE));
+        CHXString strOption(argVars.CurrentOption(FALSE));
 
         if(strOption.IsEmpty())
         {
             if(bPrintErrors)
             {
-                printf("Found non-option command-line argument: %s\n",
-                                (const char*)TCHXStringCtor(argVars.CurrentRawArg()));
+                printf("Found non-option command-line argument: %s\n", argVars.CurrentRawArg());
             }
             if(bStrictMode)
             {
                 retVal = HXR_PARSE_ERROR;
             }
             continue;
         }
 
         // check if we're looking at known option
         OptionDesc* od = optionReg.GetOptionDesc(strOption);
         if(od == NULL)
         {
             if(bPrintErrors)
             {
                 printf("Unrecognized option: -%s\n", (const char*)strOption);
             }
             if(bStrictMode)
             {
                 retVal = HXR_PARSE_ERROR;
             }
             continue;
         }
 
         EncodedString optionArgument;
 
         // retrieve argument values and store them into inputOptions
         UINT32 numArgs = od->GetNumberOfArguments();
         switch(numArgs)
         {
             case -1:
             {
                 // zero or one argument
                 numArgs = 1;
-                retVal = CopyOptionArgumentString(argVars, optionArgument, TRUE);
+                retVal = CopyOptionArgumentString(argVars, bInterpretAsUTF8, optionArgument, TRUE);
                 break;
             }
 
             case 0:
                 // no arguments
                 break;
 
             case 1:
             {
                 // one argument
-                retVal = CopyOptionArgumentString(argVars, optionArgument, FALSE);
+                retVal = CopyOptionArgumentString(argVars, bInterpretAsUTF8, optionArgument, FALSE);
                 break;
             }
 
             default:
                 // unsupported number of option arguments
                 retVal = HXR_PARSE_ERROR;
                 continue;
         }
 
         if(FAILED(retVal) && !bStrictMode)
         {
             retVal = HXR_OK;
             argVars.MovePosition(numArgs);
             continue;
         }
 
         if(SUCCEEDED(retVal))
         {
             inputOptions.Add(new InputOption(strOption, optionArgument, EncodedString()));
         }
     }
 
     return retVal;
 }
 
 HX_RESULT ParseXMLInputOptions(IHXCommonClassFactory* pCommonClassFactory, CHXXmlInputParser* pInputParser, 
                                const CHXString& strInputXMLFileName, CParsedXmlPairs& parsedXmlResults,
                                CXmlPathDescs& xmlPathDescs)
 {
     if(strInputXMLFileName.IsEmpty())
@@ -1747,115 +1715,117 @@
              m_bHashGenerated = FALSE;
         }
 #endif
         return HXR_OK;
     }
 
     STDMETHOD(OnStreamDone)(UINT16 unStreamNumber)
     {
 #ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
         if(m_vars.GenerateHash && !m_bHashGenerated)
         {
              sha256_done(&m_vars.HashState, m_vars.SHAHash);
              // make sure, that even if there is more than one call to OnStreamDone, we execute sha finalizer just one time 
              m_bHashGenerated = TRUE;
         }
 #endif
         return HXR_OK;
     }
 
 private:
     LONG32 m_lRefCount;
     MetaProcessorVars& m_vars;
     IUnknown* m_pContext;
     HXBOOL m_bHashGenerated;
 };
 
 
 /****************************************************************************
 *  Main entry point
 */
-int TMAIN(int argc, TCHAR* argv[])
+int main(int argc, char* argv[])
 {
     // initialize variables
     HX_RESULT retVal = HXR_OK;
     int progRetCode = RC_SUCCESS;
 
     UINT32 startTime = 0;
     CHXFileSpecifier exeFileSpec;
     HXBOOL bUsingLog = FALSE;
 
     DLLAccess* pDLLAccess = 0;
     FPHXMEDIAPLATFORMOPEN fpHXMediaPlatformOpen = 0;
     FPHXCREATEMEDIAPLATFORM fpHXCreateMediaPlatform = 0;
     FPHXMEDIAPLATFORMCLOSE fpHXMediaPlatformClose = 0;
 
     IHXMediaPlatform* pMediaPlatform = 0;
     IHXCommonClassFactory* pCommonClassFactory = 0;
     CHXXmlInputParser* pInputParser = 0;
     IHXMetaDataEditor* pEditor = 0;
     CResponse* pResponse = 0;
     CProcessor* pProcessor = 0;
     IHXValues* pOptions = 0;
 
     char pDllPath[_MAX_PATH] = {0};
     char pDllFile[_MAX_PATH] = {0};
     const char* pszHelixPluginPath = 0;
 
     CHXString strInputFileName;
     CHXString strOutputFileName;
     CHXString strOutputXMLFileName;
     CHXString strPictureFileNamePrefix;
     CHXString strUITSDataOutputFileName;
     CHXString strMetaStyleName;
 
     HXBOOL bDisplayHelp = FALSE;
     HXBOOL bOverwriteFile = FALSE;
     HXBOOL bPrintMetaData = FALSE;
     HXBOOL bExtractPicturesToFiles = FALSE;
     HXBOOL bUTF16Output = FALSE;
+    HXBOOL bUTF8Input = FALSE;
     UINT32 ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
 
     MetaProcessorVars metaProcessorVars;
 
     // construct option registry
     OptionRegistry optionReg;
 
     optionReg.Add(new OptionDesc(OPTION_STRING_LOGFILE, "<filename>", "redirect console output to log file", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_INPUTFILE, "<filename>", "input file", 1, "/albums/album/track/mediaFile/fileName"));
     optionReg.Add(new OptionDesc(OPTION_STRING_OUTPUTFILE, "<filename>", "output file", 1, "/albums/album/track/outputFileName"));
     optionReg.Add(new OptionDesc(OPTION_STRING_XMLINPUTFILE, "<filename>", "XML file with input parameters", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_XMLOUTPUTFILE, "<filename>", "metadata output XML file", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_OVERWRITEFILE, 0, "overwrite output file if it exists", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_CLEARMETADATA, 0, "clear all extracted metadata before injection", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_METASTYLE, "<3GPP | iTunes>", "flavor of injected metadata", 1));
-    optionReg.Add(new OptionDesc(OPTION_STRING_UTF16OUTPUT, 0, "inject metadata strings in UTF16 format", 0));
+    optionReg.Add(new OptionDesc(OPTION_STRING_UTF16OUTPUT, 0, "use UTF16 format to store strings in output file", 0));
+    optionReg.Add(new OptionDesc(OPTION_STRING_UTF8INPUT, 0, "parse command line as UTF8 strings", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_ID3V240OUTPUT, 0, "inject ID3v2 version 2.4.0, default", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_ID3V230OUTPUT, 0, "inject ID3v2 version 2.3.0", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_ID3V2NOOUTPUT, 0, "skip injecting ID3v2 tag", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_PRINTMETADATA, 0, "print updated metadata", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_EXTRACT, "[filename prefix]", "save extracted pictures", -1));
     optionReg.Add(new OptionDesc(OPTION_STRING_GENERATEHASH, 0, "generate hash", 0));
     optionReg.Add(new OptionDesc());
     optionReg.Add(new OptionDesc(OPTION_STRING_TITLE, "<string>", "update title", 1, "/albums/album/track/name"));
     optionReg.Add(new OptionDesc(OPTION_STRING_ARTIST, "<string>", "update 3GPP performer, iTunes artist", 1, "/albums/album/track/artist/name"));
     optionReg.Add(new OptionDesc(OPTION_STRING_ALBUM, "<string>", "update album", 1, "/albums/album/name"));
     optionReg.Add(new OptionDesc(OPTION_STRING_GENRE, "<string>", "update genre", 1, "/albums/album/track/style/name"));
     optionReg.Add(new OptionDesc(OPTION_STRING_COMPOSER, "<string>", "update 3GPP author, iTunes composer", 1, "/albums/album/track/artist/composer"));
     optionReg.Add(new OptionDesc(OPTION_STRING_COMMENT, "<string>", "update 3GPP description, iTunes comment", 1, "/albums/album/pline"));
     optionReg.Add(new OptionDesc(OPTION_STRING_COPYRIGHT, "<string>", "update copyright", 1, "/albums/album/cline"));
     optionReg.Add(new OptionDesc(OPTION_STRING_TRACKNUMBER, "<integer 0..255>", "update track number", 1, "/albums/album/track/sequence"));
     optionReg.Add(new OptionDesc(OPTION_STRING_YEAR, "<integer 0..65536>", "update 3GPP recording year, iTunes release date", 1, "/albums/album/OrigReleaseYear"));
     {
         // Add picture
         CHXPtrArray* pPictureAddXPaths = new CHXPtrArray;
         pPictureAddXPaths->Add(new CHXString("/albums/album/image/fileName"));
         pPictureAddXPaths->Add(new CHXString("/albums/album/image/fileName2"));
 
         optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_ADD, "<filename>", "add picture", 1, 0, pPictureAddXPaths));
     }
     optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_REMOVE, "<APIC picture type>", "remove picture", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_PICTURE_CLEAR, 0, "clear all extracted pictures", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_UITS_INSERT, "<filename>", "insert UITS signature from file", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_UITS_EXTRACT, "<filename>", "extract UITS signature into file", 1));
     optionReg.Add(new OptionDesc());
     optionReg.Add(new OptionDesc(OPTION_STRING_SOFTWARE, "<string>", "update iTunes generator tool", 1));
@@ -1874,109 +1844,115 @@
     optionReg.Add(new OptionDesc(OPTION_STRING_RATING_ENTITY, "<4 character code>", "update 3GPP rating entity", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_RATING_CRITERIA, "<4 character code>", "update 3GPP rating criteria", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_RATING_INFO, "<string>", "update 3GPP rating info", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_ENTITY, "<4 character code>", "update 3GPP classification entity", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_TABLE, "<integer 0..65535>", "update 3GPP classification table", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_CLASSIFICATION_INFO, "<string>", "update 3GPP classification info", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_ADD, "<string>", "add 3GPP keyword", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_REMOVE, "<string>", "remove 3GPP keyword", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_KEYWORD_CLEAR, 0, "clear all extracted 3GPP keywords", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_NAME, "<string>", "update 3GPP location name", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ASTRONOMICAL_BODY, "<string>", "update 3GPP location astronomical body", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ADDITIONAL_NOTES, "<string>", "update 3GPP location notes", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ROLE, "<integer 0..255>", "update 3GPP location role", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_LONGITUDE, "<decimal number>", "update 3GPP location longitude", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_LATITUDE, "<decimal number>", "update 3GPP location latitude", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LOCATION_ALTITUDE, "<decimal number>", "update 3GPP location altitude", 1));
     optionReg.Add(new OptionDesc(OPTION_STRING_LANGUAGE_CODE, "<3 character code>", "ISO639.2/T language code of 3GPP metadata text", 1));
     optionReg.Add(new OptionDesc());
     
 #ifdef _WINDOWS
     optionReg.Add(new OptionDesc(OPTION_STRING_ASYNCMODE, 0, "dtdriver asynchronous mode (developer option)", 0));
 #endif //_WINDOWS
 
     optionReg.Add(new OptionDesc(OPTION_STRING_DEFMETAPROC, 0, "default meta processor (developer option)", 0));
     optionReg.Add(new OptionDesc(OPTION_STRING_HELP, 0, "display help text", 0));
 
     // parse the command line
     ArgVars argVars(argc, argv, optionReg);
     InputOptions inputOptions;
 
-    // scan for log option, but do not print syntax errors yet
-    retVal = ParseCommandLineInputOptions(argVars, optionReg, inputOptions, FALSE, FALSE);
+    // scan for utf8in and log options, but do not print syntax errors yet
+    retVal = ParseCommandLineInputOptions(argVars, optionReg, inputOptions, FALSE, FALSE, FALSE);
+
+    // scan for UTF8 input option before rescan
+    if(inputOptions.GetOption(OPTION_STRING_UTF8INPUT))
+    {
+        bUTF8Input = TRUE;
+    }
 
     // see if we should redirect output to a log file
     CHXString sLogFilename;
     InputOption* pOptionLogfile = inputOptions.GetOption(OPTION_STRING_LOGFILE);
     if(pOptionLogfile)
     {
         sLogFilename = pOptionLogfile->GetEffectiveOptionValueCCP();
         if(!sLogFilename.IsEmpty())
         {
             // see if we can actually open the log file before disconnecting from console
             FILE* fpLog = fopen((const char*)sLogFilename, "a");
             if(fpLog)
             {
                 bUsingLog = TRUE;
 
                 // reopen standard output and standard error in append mode
                 freopen((const char*)sLogFilename, "a", stdout);
                 freopen((const char*)sLogFilename, "a", stderr);
 
                 // we can close our local pointer now
                 fclose(fpLog);
                 fpLog = 0;
             }
             else
             {
                 progRetCode = RC_ERROR_CANNOT_OPEN_LOG_FILE;
             }
         }
     }
 
     if(bUsingLog)
     {
         // echo current time to log
         printf("\n========== %s ==========\n\n", (const char*)GetUTCTimeString());
 
         // echo command line to log
-        argVars.DumpCommandLine();
+        argVars.DumpCommandLine(bUTF8Input);
     }
 
     // echo program startup header
     DisplayProgramInfo();
 
     // clear results of previous parsing
     inputOptions.Clear();
 
-    // parse the command line again, this time print errors
-    retVal = ParseCommandLineInputOptions(argVars, optionReg, inputOptions, TRUE, TRUE);
+    // parse the command line again with correct encoding, this time print errors
+    retVal = ParseCommandLineInputOptions(argVars, optionReg, inputOptions, bUTF8Input, TRUE, TRUE);
 
     // reporting command line error has precedence over reporting log file problem
     if(FAILED(retVal))
     {
         progRetCode = RC_ERROR_BAD_COMMAND_LINE;
     }
     else if(progRetCode == RC_ERROR_CANNOT_OPEN_LOG_FILE)
     {
         printf("Failed to open log file: [%s]\n\n", (const char*)sLogFilename);
         retVal = HXR_FAILED;
     }
 
     if(FAILED(retVal))
     {
         goto cleanup;
     }
 
     // initialize Helix DNA client media-platform
     pDLLAccess = new DLLAccess();
     if(!pDLLAccess)
     {
         retVal = HXR_OUTOFMEMORY;
         progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // extract plugin directory
 #ifdef _WINDOWS
     exeFileSpec = CHXFileSpecUtils::GetCurrentApplication();
     strncpy(pDllPath, (const char*)exeFileSpec.GetParentDirectory().GetPathName(), _MAX_PATH);
@@ -2282,60 +2258,64 @@
             }
             else if(strOption == OPTION_STRING_METASTYLE)
             {
                 strMetaStyleName = option->GetEffectiveOptionValueCCP();
 
                 if(clpp == CLPP_IndependentOptions)
                 {
                     if(SUCCEEDED(retVal) && !strMetaStyleName.IsEmpty())
                     {
                         if(!strMetaStyleName.CompareNoCase("3gpp"))
                         {
                             metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
                         }
                         else if(!strMetaStyleName.CompareNoCase("itunes"))
                         {
                             metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
                         }
                         else
                         {
                             retVal = HXR_PARSE_ERROR;
                             progRetCode = RC_ERROR_BAD_COMMAND_LINE;
                             ReportInvalidValueForOption(OPTION_STRING_METASTYLE, option->GetEffectiveOptionValueUTF8());
                         }
                     }
                 }
             }
             else if(strOption == OPTION_STRING_UTF16OUTPUT)
             {
                 bUTF16Output = TRUE;
             }
+            else if(strOption == OPTION_STRING_UTF8INPUT)
+            {
+                bUTF8Input = TRUE;
+            }
             else if(strOption == OPTION_STRING_ID3V240OUTPUT)
             {
                 ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
             }
             else if(strOption == OPTION_STRING_ID3V230OUTPUT)
             {
                 ulMetaDataID3VersionOutput = METADATAID3VERSION_230;
             }
             else if(strOption == OPTION_STRING_ID3V2NOOUTPUT)
             {
                 ulMetaDataID3VersionOutput = METADATAID3VERSION_NONE;
             }
             else if(strOption == OPTION_STRING_TITLE)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Title);
             }
             else if(strOption == OPTION_STRING_ARTIST)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Artist);
             }
             else if(strOption == OPTION_STRING_ALBUM)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Album);
             }
             else if(strOption == OPTION_STRING_GENRE)
             {
                 retVal = ProcessDependentStringOption(clpp, option,