[Helix-client-dev] CR/CN: Introduced differentiated program return codes for simpler errors [GMPMetaEditor branch]

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

Synopsis:
Introduced differentiated program return codes for simpler errors
[GMPMetaEditor branch]

Details:
Added program return codes for each error condition that the main
executable can easily detect:
RC_SUCCESS
RC_ERROR_GENERIC
RC_ERROR_BAD_COMMAND_LINE
RC_ERROR_CANNOT_OPEN_LOG_FILE
RC_ERROR_MISSING_ENV_VAR
RC_ERROR_CANNOT_LOAD_DLL
RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT
RC_ERROR_CANNOT_OPEN_INPUT_XML_FILE
RC_ERROR_BAD_INPUT_XML_FILE
RC_ERROR_INPUT_MEDIA_FILE_NOT_SPECIFIED
RC_ERROR_CANNOT_OPEN_INPUT_MEDIA_FILE
RC_ERROR_OUTPUT_MEDIA_FILE_EXISTS
RC_ERROR_SAME_INPUT_OUTPUT_MEDIA_FILE
RC_ERROR_CANNOT_OPEN_INPUT_PICTURE_FILE
RC_ERROR_UNSUPPORTED_INPUT_PICTURE_TYPE
RC_ERROR_CANNOT_OPEN_INPUT_UITS_FILE
RC_ERROR_UNSUPPORTED_INPUT_UITS_ENCODING
RC_ERROR_OUTPUT_PICTURE_FILE_EXISTS
RC_ERROR_CANNOT_OUTPUT_PICTURE_FILE
RC_ERROR_OUTPUT_UITS_FILE_EXISTS
RC_ERROR_CANNOT_OUTPUT_UITS_FILE
RC_ERROR_OUTPUT_XML_FILE_EXISTS
RC_ERROR_CANNOT_OUTPUT_XML_FILE
RC_ERROR_PROCESSING_MEDIA_FILE

Deep Helix errors are all reported as RC_ERROR_PROCESSING_MEDIA_FILE.

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, 47.7 KB)
Index: main.cpp
===================================================================
RCS file: /cvsroot/datatype/tools/dtdriver/apps/meta3gp/main.cpp,v
retrieving revision 1.7.2.3
diff -d -H -w -U30 -r1.7.2.3 main.cpp
--- main.cpp	16 Jan 2010 22:34:35 -0000	1.7.2.3
+++ main.cpp	17 Jan 2010 17:32:08 -0000
@@ -209,60 +209,93 @@
 #define OPTION_STRING_TRACKSTOTAL  "trackstotal"
 #define OPTION_STRING_DISKNUMBER   "disk"
 #define OPTION_STRING_DISKSTOTAL   "diskstotal"
 
 // 3GPP specific metadata
 #define OPTION_STRING_LANGUAGE_CODE  "lang"
 #define OPTION_STRING_COPYRIGHT      "copyright"
 
 #define OPTION_STRING_RATING_ENTITY     "rtngent"
 #define OPTION_STRING_RATING_CRITERIA   "rtngcrit"
 #define OPTION_STRING_RATING_INFO       "rtnginfo"
 
 #define OPTION_STRING_CLASSIFICATION_ENTITY  "clsent"
 #define OPTION_STRING_CLASSIFICATION_TABLE   "clstbl"
 #define OPTION_STRING_CLASSIFICATION_INFO    "clsinfo"
 
 #define OPTION_STRING_KEYWORD_ADD      "addkwd"
 #define OPTION_STRING_KEYWORD_REMOVE   "remkwd"
 #define OPTION_STRING_KEYWORD_CLEAR    "clrkwd"
 
 #define OPTION_STRING_LOCATION_NAME               "locname"
 #define OPTION_STRING_LOCATION_ASTRONOMICAL_BODY  "locastro"
 #define OPTION_STRING_LOCATION_ADDITIONAL_NOTES   "locnotes"
 #define OPTION_STRING_LOCATION_ROLE               "locrole"
 #define OPTION_STRING_LOCATION_LONGITUDE          "loclong"
 #define OPTION_STRING_LOCATION_LATITUDE           "loclat"
 #define OPTION_STRING_LOCATION_ALTITUDE           "localt"
 
 
 /****************************************************************************
+*  Program return codes
+*/
+#define RC_SUCCESS                                 0
+
+#define RC_ERROR_GENERIC                           10
+#define RC_ERROR_BAD_COMMAND_LINE                  11
+#define RC_ERROR_CANNOT_OPEN_LOG_FILE              12
+
+#define RC_ERROR_MISSING_ENV_VAR                   21
+#define RC_ERROR_CANNOT_LOAD_DLL                   22
+#define RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT        23
+
+#define RC_ERROR_CANNOT_OPEN_INPUT_XML_FILE        31
+#define RC_ERROR_BAD_INPUT_XML_FILE                32
+#define RC_ERROR_INPUT_MEDIA_FILE_NOT_SPECIFIED    33
+#define RC_ERROR_CANNOT_OPEN_INPUT_MEDIA_FILE      34
+#define RC_ERROR_OUTPUT_MEDIA_FILE_EXISTS          35
+#define RC_ERROR_SAME_INPUT_OUTPUT_MEDIA_FILE      36
+#define RC_ERROR_CANNOT_OPEN_INPUT_PICTURE_FILE    37
+#define RC_ERROR_UNSUPPORTED_INPUT_PICTURE_TYPE    38
+#define RC_ERROR_CANNOT_OPEN_INPUT_UITS_FILE       39
+#define RC_ERROR_UNSUPPORTED_INPUT_UITS_ENCODING   40
+#define RC_ERROR_OUTPUT_PICTURE_FILE_EXISTS        41
+#define RC_ERROR_CANNOT_OUTPUT_PICTURE_FILE        42
+#define RC_ERROR_OUTPUT_UITS_FILE_EXISTS           43
+#define RC_ERROR_CANNOT_OUTPUT_UITS_FILE           44
+#define RC_ERROR_OUTPUT_XML_FILE_EXISTS            45
+#define RC_ERROR_CANNOT_OUTPUT_XML_FILE            46
+
+#define RC_ERROR_PROCESSING_MEDIA_FILE             100
+
+
+/****************************************************************************
 *  Help display utilities
 */
 class OptionDesc
 {
 public:
     OptionDesc(const char* option_ = 0, const char* option_args_ = 0, const char* desc_ = 0, 
         int arg_count_ = 0, const char* xpath_ = 0)
     {
         option = option_;
         option_args = option_args_;
         desc = desc_;
         arg_count = arg_count_;
         xpath = xpath_;
     }
 
     UINT32 GetLeftColumnWidth()
     {
         UINT32 len = 0;
         if(option)
         {
             len += 2 + strlen(option); //leading whitespace and option prefix
             if(option_args)
             {
                 len += 1 + strlen(option_args); //whitespace separator and option args
             }
         }
         return len;
     }
 
     CHXString BuildLine(UINT32 leftColumnWidth)
@@ -969,175 +1002,191 @@
         return HXR_OK;
     }
 
     if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Keywords, metaFlavorFlags))
     {
         EncodedString* pEncStr = new EncodedString(option->OptionValueUTF8);
 
         if(pEncStr && MetaInfo::IsKeywordValidForFlavors(*pEncStr, metaFlavorFlags))
         {
             aKeywords.Add(pEncStr);
             return HXR_OK;
         }
 
         delete pEncStr;
 
         ReportInvalidValueForOption(option->OptionName, option->OptionValueUTF8);
         return HXR_PARSE_ERROR;
     }
 
     ReportUnsupportedMetaStyleOption(option->OptionName);
     return HXR_PARSE_ERROR;
 }
 
 inline HX_RESULT ProcessDependentKeywordStringOption(eCommandLineProcessorPhase phase, InputOption* option,
                                     CHXPtrArray& aKeywords, UINT32 metaFlavorFlags)
 {
     return ProcessKeywordStringOption((phase != CLPP_DependentOptions),
                 option, aKeywords, metaFlavorFlags);
 }
 
-HX_RESULT ProcessXMLFileStringOption(bool bSkipArgOnly, InputOption* option, MetaInfo& metainfo,
+HX_RESULT ProcessXMLFileStringOption(int& progRetCode, bool bSkipArgOnly, InputOption* option, MetaInfo& metainfo,
                                     MetaInfo::eStringMetaItem itemName, UINT32 metaFlavorFlags)
 {
     if(option->OptionValueUTF8.IsEmpty())
     {
         return HXR_PARSE_ERROR;
     }
 
     if(bSkipArgOnly)
     {
         return HXR_OK;
     }
 
     if(MetaInfo::IsItemSupportedByAnyFlavor(itemName, metaFlavorFlags))
     {
         // read-in the file contents
         CHXString sFileName = option->GetEffectiveOptionValueCCP();
-        if(!sFileName.IsEmpty())
+        if(!sFileName.IsEmpty() && CHXFileSpecUtils::FileExists(CHXFileSpecifier(sFileName)))
         {
             EncodedString sXML;
             HX_RESULT retVal = MetaInfo::LoadXMLStringFromFile((const char*)sFileName, sXML);
 
+            if(FAILED(retVal))
+            {
+                printf("Unsupported encoding in UITS file: %s\n", (const char*)sFileName);
+                progRetCode = RC_ERROR_UNSUPPORTED_INPUT_UITS_ENCODING;
+                return HXR_FAILED;
+            }
+
             if(SUCCEEDED(retVal) &&
                MetaInfo::IsItemValueValidForFlavors(itemName, sXML, metaFlavorFlags) &&
                SUCCEEDED(metainfo.SetStringItem(itemName, sXML)))
             {
                 return HXR_OK;
             }
         }
+        else
+        {
+            printf("Failed to open UITS file: %s\n", (const char*)sFileName);
+            progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_UITS_FILE;
+            return HXR_FAILED;
+        }
 
         ReportInvalidValueForOption(option->OptionName, option->OptionValueUTF8);
         return HXR_PARSE_ERROR;
     }
 
     ReportUnsupportedMetaStyleOption(option->OptionName);
     return HXR_PARSE_ERROR;
 }
 
 HX_RESULT ProcessRemovePictureOption(bool bSkipArgOnly, InputOption* option,
                                 CHXPtrArray& aRemovedPictureTypes, UINT32 metaFlavorFlags)
 {
     if(option->OptionValueUTF8.IsEmpty())
     {
         return HXR_PARSE_ERROR;
     }
 
     if(bSkipArgOnly)
     {
         return HXR_OK;
     }
 
     if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Pictures, metaFlavorFlags))
     {
         EncodedString sVal = option->OptionValueUTF8;
 
         UINT32 uVal = 0;
         if(PropTools::ExtractUInt32(uVal, sVal) &&
            MetaInfo::IsAPICPictureTypeValidForFlavors(uVal, metaFlavorFlags))
         {
             aRemovedPictureTypes.AddIfUnique((void*)uVal);
             return HXR_OK;
         }
 
         ReportInvalidValueForOption(option->OptionName, option->OptionValueUTF8);
         return HXR_PARSE_ERROR;
     }
 
     ReportUnsupportedMetaStyleOption(option->OptionName);
     return HXR_PARSE_ERROR;
 }
 
-HX_RESULT ProcessAddPictureOption(bool bSkipArgOnly, InputOption* option,
+HX_RESULT ProcessAddPictureOption(int& progRetCode, bool bSkipArgOnly, InputOption* option,
                                 CHXPtrArray& aAddedAPICFrames, UINT32 metaFlavorFlags)
 {
     if(option->OptionValueUTF8.IsEmpty())
     {
         return HXR_PARSE_ERROR;
     }
 
     if(bSkipArgOnly)
     {
         return HXR_OK;
     }
 
     if(MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Pictures, metaFlavorFlags))
     {
         ID3Tools::APICFrame* pFrame = new ID3Tools::APICFrame;
         if(!pFrame)
         {
+            progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
             return HXR_OUTOFMEMORY;
         }
 
         // process image file
         HX_RESULT retVal = HXR_FAILED;
 
         CHXString sFileName = option->GetEffectiveOptionValueCCP();
-        if(!sFileName.IsEmpty())
+        if(!sFileName.IsEmpty() && CHXFileSpecUtils::FileExists(CHXFileSpecifier(sFileName)))
         {
             // load image, accept only known MIME types
             retVal = pFrame->LoadPictureDataFromImageFile((const char*)sFileName, TRUE);
 
             // check if frame is acceptable
-            if(SUCCEEDED(retVal))
-            {
-                if(!MetaInfo::IsAPICFrameValidForFlavors(*pFrame, metaFlavorFlags))
+            if(SUCCEEDED(retVal) && !MetaInfo::IsAPICFrameValidForFlavors(*pFrame, metaFlavorFlags))
                 {
                     retVal = HXR_FAILED;
                 }
-            }
-        }
 
         if(FAILED(retVal))
         {
-            printf("Invalid image file for option %s: %s\n",
-                    (const char*)option->OptionName, (const char*)sFileName);
+                printf("Unsupported picture type in file: %s\n", (const char*)sFileName);
+                progRetCode = RC_ERROR_UNSUPPORTED_INPUT_PICTURE_TYPE;
+            }
+        }
+        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 = FALSE)
 {
     sOut.Clear();
 
     const TCHAR* pVal = argVars.CurrentArg(1, bOptional, TRUE);
@@ -1291,71 +1340,71 @@
             case 1:
             {
                 // one argument
                 retVal = CopyOptionArgumentString(argVars, 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, 
-                               InputOption* option, CParsedXmlPairs* parsedXmlResults)
+                               const CHXString& strInputXMLFilename, CParsedXmlPairs* parsedXmlResults)
 {
-    if(option->OptionValueUTF8.IsEmpty())
+    if(strInputXMLFilename.IsEmpty())
     {
         return HXR_FAIL;
     }
 
-    FILE* fp = fopen((const char*)option->GetEffectiveOptionValueCCP(), "r");
+    FILE* fp = fopen((const char*)strInputXMLFilename, "r");
     if(fp == NULL)
     {
-        printf("Unable to open file: %s\n", (const char*)option->GetEffectiveOptionValueCCP());
+        printf("Unable to open file: %s\n", (const char*)strInputXMLFilename);
         return HXR_FAIL;
     }
 
     HX_RESULT retVal = HXR_OK;
     retVal = pInputParser->Start(parsedXmlResults);
 
     ULONG32 uParserBufferSize = 64 * 1024;
 
     if(SUCCEEDED(retVal))
     {
         // create temporary buffer for manifest chunks
         IHXBuffer* pBuffer = NULL;
         retVal = CreateBufferCCF(pBuffer, pCommonClassFactory);
         if(SUCCEEDED(retVal))
         {
             pBuffer->SetSize(uParserBufferSize);
 
             // read manifest, chunk by chunk
             while(true)
             {
                 size_t nItemsRead = fread(pBuffer->GetBuffer(), 1, uParserBufferSize, fp);
                 if(nItemsRead != 0)
                 {
                     if(uParserBufferSize != nItemsRead)
                     {
                         pBuffer->SetSize(nItemsRead);
                     }
 
                     // parse chunk
                     HXBOOL bIsFinal = uParserBufferSize != nItemsRead;
@@ -1569,65 +1618,65 @@
     }
 
     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[])
 {
     // initialize variables
     HX_RESULT retVal = HXR_OK;
+    int progRetCode = RC_SUCCESS;
 
     UINT32 startTime = 0;
     CHXFileSpecifier exeFileSpec;
     HXBOOL bUsingLog = FALSE;
-    HXBOOL bFailedToOpenLog = 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 strPictureFileNamePrefix;
     CHXString strUITSDataOutputFileName;
     CHXString strMetaStyleName;
 
     HXBOOL bDisplayHelp = FALSE;
     HXBOOL bOverwriteFile = FALSE;
     HXBOOL bPrintMetaData = FALSE;
     HXBOOL bExtractPicturesToFiles = FALSE;
     HXBOOL bUTF16Output = FALSE;
     UINT32 ulMetaDataID3VersionOutput = METADATAID3VERSION_240;
@@ -1710,289 +1759,321 @@
     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);
 
     // 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
             {
-                bFailedToOpenLog = TRUE;
+                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();
     }
 
     // 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);
 
-    if(bFailedToOpenLog)
+    // 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);
     snprintf(pDllFile, _MAX_PATH, "%s\\%s", pDllPath, "hxmedpltfm.dll");
 
 #else
     pszHelixPluginPath = getenv(PLUGIN_PATH_ENV_VAR_NAME);
     if(pszHelixPluginPath && (strlen(pszHelixPluginPath) > 0))
     {
         strncpy(pDllPath, pszHelixPluginPath, _MAX_PATH);
         snprintf(pDllFile, _MAX_PATH, "%s/%s", pDllPath, "hxmedpltfm.so");
     }
     else
     {
         printf("Missing environment variable %s.\n", PLUGIN_PATH_ENV_VAR_NAME);
+
+        retVal = HXR_FAILED;
+        progRetCode = RC_ERROR_MISSING_ENV_VAR;
         goto cleanup;
     }
 #endif
 
     pDllPath[_MAX_PATH - 1] = '\0';
     pDllFile[_MAX_PATH - 1] = '\0';
     
     if(pDLLAccess->open(pDllFile) != DLLAccess::DLL_OK)
     {
         printf("Failed to access Helix DNA client media-platform library file: %s\n", pDllFile);
 
         const char* szError = pDLLAccess->getErrorString();
         if(szError)
         {
             printf("Error description: %s\n", szError);
         }
 
+        retVal = HXR_FAILED;
+        progRetCode = RC_ERROR_CANNOT_LOAD_DLL;
         goto cleanup;
     }
 
     // initialize Helix media-platform
     fpHXMediaPlatformOpen = (FPHXMEDIAPLATFORMOPEN) pDLLAccess->getSymbol("HXMediaPlatformOpen");
     fpHXCreateMediaPlatform = (FPHXCREATEMEDIAPLATFORM) pDLLAccess->getSymbol("HXCreateMediaPlatform");
     fpHXMediaPlatformClose = (FPHXMEDIAPLATFORMCLOSE) pDLLAccess->getSymbol("HXMediaPlatformClose");
 
     if(!fpHXMediaPlatformOpen || !fpHXCreateMediaPlatform || !fpHXMediaPlatformClose)
     {
         retVal = HXR_FAILED;
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = fpHXMediaPlatformOpen();
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = fpHXCreateMediaPlatform((IHXMediaPlatform**)&pMediaPlatform);
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = pMediaPlatform->AddPluginPath("Meta3GP", pDllPath);
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = pMediaPlatform->Init(0);
     }
 
     if(SUCCEEDED(retVal))
     {
        retVal = pMediaPlatform->QueryInterface(IID_IHXCommonClassFactory, (void**)&pCommonClassFactory);
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix DNA client media-platform.\n");
+
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // initialize meta-data editor response object
     pResponse = new CResponse();
     HX_ADDREF(pResponse);
     if(!pResponse)
     {
         retVal = HXR_OUTOFMEMORY;
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data editor response object.\n");
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // initialize meta-data processor object
     pProcessor = new CProcessor(metaProcessorVars);
     HX_ADDREF(pProcessor);
     if(!pProcessor)
     {
         retVal = HXR_OUTOFMEMORY;
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data processor object.\n");
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // initialize meta-data editor plugin
     retVal = CreateInstanceCCF_QI(CLSID_IHXMetaDataEditor, IID_IHXMetaDataEditor,
                                         (void**)&pEditor, pCommonClassFactory);
     if(SUCCEEDED(retVal))
     {
         retVal = pEditor->InitMetaDataEditor(pCommonClassFactory);
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize Helix meta-data editor plugin.\n");
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // initialize xml parser
     if(SUCCEEDED(retVal))
     {
         retVal = HXR_OUTOFMEMORY;
         pInputParser = new CHXXmlInputParser();
 
         if(pInputParser)
         {
             pInputParser->AddRef();
             retVal = HXR_OK;
         }
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = pInputParser->Init(pCommonClassFactory);
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize XML parser.\n");
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // parse XML input file
     if(SUCCEEDED(retVal))
     {
-        InputOption* optionXmlIn = inputOptions.GetOption(CHXString(OPTION_STRING_XMLINPUTFILE));
-        if(optionXmlIn && !optionXmlIn->OptionValueUTF8.IsEmpty())
+        InputOption* pOptionXmlIn = inputOptions.GetOption(CHXString(OPTION_STRING_XMLINPUTFILE));
+        CHXString strInputXMLFilename = pOptionXmlIn ? pOptionXmlIn->GetEffectiveOptionValueCCP() : CHXString();
+
+        if(!strInputXMLFilename.IsEmpty() && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(strInputXMLFilename)))
         {
-            printf("Processing XML input file:\n");
+            printf("XML input file [%s] not found.\n", (const char*)strInputXMLFilename);
+            retVal = HXR_FAIL;
+            progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_XML_FILE;
+        }
+
+        if(SUCCEEDED(retVal) && !strInputXMLFilename.IsEmpty())
+        {
+            printf("Processing XML input file [%s].\n", (const char*)strInputXMLFilename);
 
             CParsedXmlPairs parsedXmlResults;
             optionReg.InitializeXmlPairs(&parsedXmlResults);
 
-            retVal = ParseXMLInputOptions(pCommonClassFactory, pInputParser, optionXmlIn, &parsedXmlResults);
+            retVal = ParseXMLInputOptions(pCommonClassFactory, pInputParser, strInputXMLFilename, &parsedXmlResults);
 
             if(SUCCEEDED(retVal))
             {
                 // merge parsed results into inputOptions
                 CHXPtrArray *xmlPairs = parsedXmlResults.GetAllPairs();
                 for(int i = 0; i < xmlPairs->GetSize(); i++)
                 {
                     XmlPair *pair = (XmlPair*)xmlPairs->GetAt(i);
                     OptionDesc* optDesc = optionReg.GetOptionDescWithPath(pair->xmlPath);
 
                     // Add only results of XML file parsing which have non-empty value.
                     if((optDesc != NULL) && !pair->xmlValueUTF8.IsEmpty())
                     {
                         CHXString strName = optDesc->GetOptionString();
                         InputOption* inOpt = inputOptions.GetOption(strName);
 
                         if(inOpt == NULL)
                         {
                             inputOptions.Add(new InputOption(strName, EncodedString(), pair->xmlValueUTF8));
                         }
                         else
                         {
                             inOpt->XmlOptionValueUTF8 = pair->xmlValueUTF8;
                         }
 
                         printf("-%s taken from location [%s], value=[", (const char*)strName, (const char*)pair->xmlPath);
                         EncStrUtils::PrintTextUTF8(pair->xmlValueUTF8.GetData());
                         printf("]\n");
                     }
                 }
 
                 printf("\n");
             }
+            else
+            {
+                printf("Error parsing XML input file.\n");
+                progRetCode = RC_ERROR_BAD_INPUT_XML_FILE;
+            }
         }
     }
 
     // Process final combination of command-line and XML file input.
     // The first phase seeks for independent arguments, the second phase seeks for dependent arguments.
     eCommandLineProcessorPhase clpp = CLPP_IndependentOptions;
 
     while(SUCCEEDED(retVal) && (clpp != CLPP_Done))
     {
         for(inputOptions.ResetPosition(0); SUCCEEDED(retVal) && !inputOptions.ReachedEndPosition(); 
                 inputOptions.MovePosition(1))
         {
             InputOption* option = inputOptions.CurrentOption();
             CHXString strOption = option->OptionName;
 
             if(strOption == OPTION_STRING_HELP)
             {
                 bDisplayHelp = TRUE;
             }
 
 #ifdef _WINDOWS
             else if(strOption == OPTION_STRING_ASYNCMODE)
             {
                 g_bUseDTDriverSynchronousMode = FALSE;
             }
 #endif //_WINDOWS
 
             else if(strOption == OPTION_STRING_DEFMETAPROC)
             {
                 g_bUseDefaultMetaEditorProcessor = TRUE;
@@ -2021,60 +2102,61 @@
             {
                 bPrintMetaData = TRUE;
             }
             else if(strOption == OPTION_STRING_GENERATEHASH)
             {
                 metaProcessorVars.GenerateHash = TRUE;
             }
             else if(strOption == OPTION_STRING_XMLINPUTFILE)
             {
                 // do nothing, already processed
             }
             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_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);
@@ -2089,87 +2171,87 @@
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Genre);
             }
             else if(strOption == OPTION_STRING_COMPOSER)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Composer);
             }
             else if(strOption == OPTION_STRING_COMMENT)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Description);
             }
             else if(strOption == OPTION_STRING_COPYRIGHT)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Copyright);
             }
             else if(strOption == OPTION_STRING_TRACKNUMBER)
             {
                 retVal = ProcessDependentUIntOption(clpp, option,
                                     metaProcessorVars, MetaInfo::UIntMetaItem_TrackNumber);
             }
             else if(strOption == OPTION_STRING_YEAR)
             {
                 retVal = ProcessDependentUIntOption(clpp, option,
                                     metaProcessorVars, MetaInfo::UIntMetaItem_RecordingYear);
             }
             else if(strOption == OPTION_STRING_PICTURE_ADD)
             {
-                retVal = ProcessAddPictureOption((clpp != CLPP_DependentOptions),
+                retVal = ProcessAddPictureOption(progRetCode, (clpp != CLPP_DependentOptions),
                                     option, metaProcessorVars.AddedPictures, metaProcessorVars.InjectedMetaFlavors);
             }
             else if(strOption == OPTION_STRING_PICTURE_REMOVE)
             {
                 retVal = ProcessRemovePictureOption((clpp != CLPP_DependentOptions),
                                     option, metaProcessorVars.RemovedPictures, metaProcessorVars.InjectedMetaFlavors);
             }
             else if(strOption == OPTION_STRING_PICTURE_CLEAR)
             {
                 metaProcessorVars.ClearPictures = TRUE;
 
                 if((clpp == CLPP_DependentOptions) &&
                     !MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Pictures, metaProcessorVars.InjectedMetaFlavors))
                 {
                     ReportUnsupportedMetaStyleOption(OPTION_STRING_PICTURE_CLEAR);
                     retVal = HXR_PARSE_ERROR;
                 }
             }
             else if(strOption == OPTION_STRING_PICTURE_EXTRACT)
             {
                 bExtractPicturesToFiles = TRUE;
                 strPictureFileNamePrefix = option->GetEffectiveOptionValueCCP();
             }
             else if(strOption == OPTION_STRING_UITS_INSERT)
             {
-                retVal = ProcessXMLFileStringOption((clpp != CLPP_DependentOptions),
+                retVal = ProcessXMLFileStringOption(progRetCode, (clpp != CLPP_DependentOptions),
                                 option, metaProcessorVars.InjectedMetaInfo, MetaInfo::StringMetaItem_UITSData,
                                 metaProcessorVars.InjectedMetaFlavors);
             }
             else if(strOption == OPTION_STRING_UITS_EXTRACT)
             {
                 strUITSDataOutputFileName = option->GetEffectiveOptionValueCCP();
             }
             else if(strOption == OPTION_STRING_SOFTWARE)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_GeneratorTool);
             }
             else if(strOption == OPTION_STRING_ENCODEDBY)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_EncodedBy);
             }
             else if(strOption == OPTION_STRING_GROUPING)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_Grouping);
             }
             else if(strOption == OPTION_STRING_ALBUMARTIST)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_AlbumArtist);
             }
             else if(strOption == OPTION_STRING_LYRICS)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
@@ -2278,144 +2360,150 @@
             else if(strOption == OPTION_STRING_LOCATION_ALTITUDE)
             {
                 retVal = ProcessDependentStringOption(clpp, option,
                                     metaProcessorVars, MetaInfo::StringMetaItem_LocationAltitude);
             }
             else if(strOption == OPTION_STRING_KEYWORD_ADD)
             {
                 retVal = ProcessDependentKeywordStringOption(clpp, option,
                                     metaProcessorVars.AddedKeywords, metaProcessorVars.InjectedMetaFlavors);
             }
             else if(strOption == OPTION_STRING_KEYWORD_REMOVE)
             {
                 retVal = ProcessDependentKeywordStringOption(clpp, option,
                                     metaProcessorVars.RemovedKeywords, metaProcessorVars.InjectedMetaFlavors);
             }
             else if(strOption == OPTION_STRING_KEYWORD_CLEAR)
             {
                 metaProcessorVars.ClearKeywords = TRUE;
 
                 if((clpp == CLPP_DependentOptions) &&
                     !MetaInfo::IsItemSupportedByAnyFlavor(MetaInfo::ArrayMetaItem_Keywords, metaProcessorVars.InjectedMetaFlavors))
                 {
                     ReportUnsupportedMetaStyleOption(OPTION_STRING_KEYWORD_CLEAR);
                     retVal = HXR_PARSE_ERROR;
                 }
             }
             else
             {
                 printf("Unrecognized option: -%s\n", (const char*)strOption);
                 retVal = HXR_PARSE_ERROR;
+                progRetCode = RC_ERROR_BAD_COMMAND_LINE;
             }
         }
 
         // update metastyles
         if(clpp == CLPP_IndependentOptions)
         {
             // unless metastyles are explicitly specified, assume defaults according to file extension
             if((metaProcessorVars.InjectedMetaFlavors == 0) && !strOutputFileName.IsEmpty())
             {
                 CHXString sFileExt = "";
                 INT32 dotPos = strOutputFileName.ReverseFind('.');
 
                 if(dotPos >= 0)
                 {
                     UINT32 extLen = strOutputFileName.GetLength() - dotPos - 1;
                     if(extLen > 0)
                     {
                         sFileExt = strOutputFileName.Right(extLen);
                     }
                 }
 
                 if(!sFileExt.CompareNoCase("3gp"))
                 {
                     metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_3GPP;
                 }
                 else if(!sFileExt.CompareNoCase("m4a"))
                 {
                     metaProcessorVars.InjectedMetaFlavors |= METADATA_FLAVOR_ITUNES;
                 }
             }
         }
 
         // next phase
         clpp = (eCommandLineProcessorPhase)(int(clpp) + 1);
     }
 
     // display usage
     if(argc == 1)
     {
         // auto help display if started without options
         bDisplayHelp = TRUE;
     }
 
     if(bDisplayHelp)
     {
         DisplayUsage(argv[0], optionReg);
         goto cleanup;
     }
 
-    // check for semantic errors
-    if(SUCCEEDED(retVal) && !bDisplayHelp)
+    // cleanup on command-line errors
+    if(FAILED(retVal))
     {
-        if(strInputFileName.IsEmpty())
+        if(retVal == HXR_PARSE_ERROR)
         {
-            printf("Input file not specified.\n");
-            retVal = HXR_PARSE_ERROR;
+            progRetCode = RC_ERROR_BAD_COMMAND_LINE;
         }
+        goto cleanup;
     }
 
-    // cleanup on command-line errors
-    if(FAILED(retVal))
+    // check for semantic errors
+    if(SUCCEEDED(retVal) && strInputFileName.IsEmpty())
     {
-        goto cleanup;
+        printf("Input file not specified.\n");
+        retVal = HXR_PARSE_ERROR;
+        progRetCode = RC_ERROR_INPUT_MEDIA_FILE_NOT_SPECIFIED;
     }
 
     // input file must exist
     if(SUCCEEDED(retVal) && !CHXFileSpecUtils::FileExists(CHXFileSpecifier(strInputFileName)))
     {
         printf("Input file [%s] not found.\n", (const char*)strInputFileName);
         retVal = HXR_FAIL;
+        progRetCode = RC_ERROR_CANNOT_OPEN_INPUT_MEDIA_FILE;
     }
 
     if(SUCCEEDED(retVal) && !strOutputFileName.IsEmpty())
     {
         // writing to input file is not allowed
         if(SUCCEEDED(retVal) && (strInputFileName == strOutputFileName))
         {
             printf("File [%s] cannot be used for both input and output.\n", (const char*)strOutputFileName);
             retVal = HXR_FAIL;
+            progRetCode = RC_ERROR_SAME_INPUT_OUTPUT_MEDIA_FILE;
         }
         // output file must not exist or overwrite must be specified
         if(SUCCEEDED(retVal) && NeedOverwriteConfirmation((const char*)strOutputFileName, bOverwriteFile))
         {
             retVal = HXR_FAIL;
+            progRetCode = RC_ERROR_OUTPUT_MEDIA_FILE_EXISTS;
         }
     }
 
     if(FAILED(retVal))
     {
         goto cleanup;
     }
 
     // initialize options
     retVal = CreateInstanceCCF_QI(CLSID_IHXValues, IID_IHXValues,
                                     (void**)&pOptions, pCommonClassFactory);
     if(SUCCEEDED(retVal))
     {
         retVal = pOptions->SetPropertyULONG32(SYNCHRONOUS_OPTION_NAME, g_bUseDTDriverSynchronousMode ? 1 : 0);
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = pOptions->SetPropertyULONG32(BLASTFILE_OPTION_NAME, bOverwriteFile ? 1 : 0);
     }
 
     if(SUCCEEDED(retVal))
     {
         retVal = pOptions->SetPropertyULONG32(UTF16OUTPUT_OPTION_NAME, bUTF16Output ? 1 : 0);
     }
 
     if(SUCCEEDED(retVal))
     {
         // Notify writer about the version of ID3 tag it should output.
         retVal = pOptions->SetPropertyULONG32(METADATAID3VERSION_OPTION_NAME, ulMetaDataID3VersionOutput);
@@ -2424,60 +2512,61 @@
     if(SUCCEEDED(retVal))
     {
         // Notify meta-editor about the flavor of meta-data it should process.
         retVal = pOptions->SetPropertyULONG32(METADATAFLAVOR_OPTION_NAME, metaProcessorVars.InjectedMetaFlavors);
     }
 
     if(SUCCEEDED(retVal))
     {
         // Legacy ID32_BLOB property must not get in the way of newly defined properties.
         // Tell file-writer to ignore it.
         retVal = pOptions->SetPropertyULONG32(METADATAIGNORE_OPTION_NAME, METADATAIGNORE_ID32BLOB);
     }
 
     if(SUCCEEDED(retVal))
     {
         if(g_bUseDefaultMetaEditorProcessor)
         {
             retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, metaProcessorVars.ClearMetaData ? 1 : 0);
         }
         else
         {
             // Notify meta-editor that we do not want it to perform any default internal meta-data merging.
             // Custom processor in this application performs special merging of extracted and injected meta-data.
             retVal = pOptions->SetPropertyULONG32(BLASTMETADATA_OPTION_NAME, 1);
         }
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to initialize options.\n");
+        progRetCode = RC_ERROR_CANNOT_INIT_PROGRAM_OBJECT;
         goto cleanup;
     }
 
     // display operation info
     {
         CHXString sStyles = MetaInfo::GetFlavorNames(metaProcessorVars.InjectedMetaFlavors);
         if(!strOutputFileName.IsEmpty())
         {
             printf("Injecting %s style metadata: [%s] => [%s].\n\n",
                     sStyles.IsEmpty() ? "unspecified" : (const char*)sStyles,
                     (const char*)strInputFileName, (const char*)strOutputFileName);
         }
         else
         {
             printf("Extracting metadata from [%s].\n\n", (const char*)strInputFileName);
         }
     }
 
     // start file processing
     startTime = HX_GET_BETTERTICKCOUNT();
 
     if(g_bUseDefaultMetaEditorProcessor)
     {
         printf("WARNING: Using default meta-data processor.\n"
                "Some features will not work correctly: %s, %s, %s, %s.\n\n",
                OPTION_STRING_KEYWORD_REMOVE, OPTION_STRING_KEYWORD_CLEAR,
                OPTION_STRING_PICTURE_REMOVE, OPTION_STRING_PICTURE_CLEAR);
 
         // read meta-info by using meta-editor's default meta-data processor
         IHXValues* pExtractedMetaData = 0;
@@ -2530,157 +2619,176 @@
 
             HX_RELEASE(pInjectedMetaData);
 
             if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
             {
                 WaitAsyncDriveEnd();
                 retVal = pResponse->GetTerminationStatus();
             }
         }
     }
     else
     {
         // drive meta-info through meta-editor by using custom meta-data processor
         if(SUCCEEDED(retVal))
         {
             retVal = pEditor->Drive((const char*)strInputFileName, (const char*)strOutputFileName,
                                     (IHXMetaDataProcessor*)pProcessor,
                                     pOptions, (IHXMetaDataEditorResponse*)pResponse);
 
             if(SUCCEEDED(retVal) && !g_bUseDTDriverSynchronousMode)
             {
                 WaitAsyncDriveEnd();
                 retVal = pResponse->GetTerminationStatus();
             }
         }
     }
 
     if(FAILED(retVal))
     {
         printf("Failed to process input file [%s].\n", (const char*)strInputFileName);
+        progRetCode = RC_ERROR_PROCESSING_MEDIA_FILE;
+        goto cleanup;
     }
 
 #ifdef HELIX_FEATURE_METAEDIT_AUDIO_HASH
     if(metaProcessorVars.GenerateHash)
     {
         printf("--- Generated hash ---\n");
         for (int i=0; i<32; i++)
         {
             printf("%x", metaProcessorVars.SHAHash[i]);
         }
         printf("\n");
     }
 #endif
 
     // auto dump meta-data if extracting only
-    if(strOutputFileName.IsEmpty())
+    if(strOutputFileName.IsEmpty() && !metaProcessorVars.GenerateHash)
     {
         bPrintMetaData = TRUE;
     }
 
     if(SUCCEEDED(retVal) && bPrintMetaData)
     {
         // dump extracted
         printf("--- Extracted meta-data ---\n");
         metaProcessorVars.ExtractedMetaInfo.Dump();
         printf("\n");
 
         // dump injected
         if(!g_bUseDefaultMetaEditorProcessor && !strOutputFileName.IsEmpty())
         {
             printf("--- Injected meta-data ---\n");
             metaProcessorVars.OutboundMetaInfo.Dump();
             printf("\n");
         }
     }
 
     // extract UITS data to file
     if(SUCCEEDED(retVal) && !strUITSDataOutputFileName.IsEmpty())
     {
         EncodedString sUITSData;
         if(SUCCEEDED(metaProcessorVars.ExtractedMetaInfo.GetStringItem(MetaInfo::StringMetaItem_UITSData, sUITSData))
             && !sUITSData.IsEmpty())
         {
             printf("--- Extracting UITSData to file ---\n");
             printf("Saving UITSData to [%s].\n", (const char*)strUITSDataOutputFileName);
 
-            if(!NeedOverwriteConfirmation((const char*)strUITSDataOutputFileName, bOverwriteFile))
+            if(NeedOverwriteConfirmation((const char*)strUITSDataOutputFileName, bOverwriteFile))
             {
-                if(FAILED(MetaInfo::SaveXMLStringToFile((const char*)strUITSDataOutputFileName, sUITSData)))
+                // report error but continue saving other data
+                progRetCode = RC_ERROR_OUTPUT_UITS_FILE_EXISTS;
+            }
+            else if(FAILED(MetaInfo::SaveXMLStringToFile((const char*)strUITSDataOutputFileName, sUITSData)))
                 {
+                // report error but continue saving other data
                     printf("Failed to save UITSData.\n");
-                }
+                progRetCode = RC_ERROR_CANNOT_OUTPUT_UITS_FILE;
             }
             printf("\n");
         }
     }
 
     // extract pictures to files
     if(SUCCEEDED(retVal) && bExtractPicturesToFiles && metaProcessorVars.ExtractedMetaInfo.GetPictureCount())
     {
         printf("--- Extracting pictures to files ---\n");
         for(UINT32 iPic = 0; iPic < metaProcessorVars.ExtractedMetaInfo.GetPictureCount(); iPic++)
         {
             ID3Tools::APICFrame* pFrame = metaProcessorVars.ExtractedMetaInfo.GetPictureByIndex(iPic);
             if(pFrame)
             {
                 CHXString filename = strPictureFileNamePrefix.IsEmpty() ? "picture" : strPictureFileNamePrefix;
                 filename.AppendULONG(iPic);
                 filename += "_type";
                 filename.AppendULONG(pFrame->GetPictureType());
 
                 if(pFrame->GetMimeType() == "image/jpeg")
                 {
                     filename += ".jpg";
                 }
                 else if(pFrame->GetMimeType() == "image/png")
                 {
                     filename += ".png";
                 }
                 else
                 {
                     filename += ".bin";
                 }
 
                 printf("Saving picture %d to [%s].\n", iPic, (const char*)filename);
 
-                if(!NeedOverwriteConfirmation((const char*)filename, bOverwriteFile))
+                if(NeedOverwriteConfirmation((const char*)filename, bOverwriteFile))
+                {
+                    // report error but continue saving other data
+                    progRetCode = RC_ERROR_OUTPUT_PICTURE_FILE_EXISTS;
+                }
+                else
                 {
                     if(FAILED(pFrame->SavePictureDataToImageFile((const char*)filename)))
                     {
+                        // report error but continue saving other data
                         printf("Failed to save picture %d.\n", iPic);
+                        progRetCode = RC_ERROR_CANNOT_OUTPUT_PICTURE_FILE;
                     }
                 }
             }
         }
         printf("\n");
     }
 
     if(SUCCEEDED(retVal))
     {
         UINT32 endTime = HX_GET_BETTERTICKCOUNT();
         printf("Done. Processing time: %f seconds.\n", (endTime - startTime) / 1000.0);
     }
 
     // cleanup objects
 cleanup:
     HX_RELEASE(pEditor);
     HX_RELEASE(pInputParser);
     HX_RELEASE(pProcessor);
     HX_RELEASE(pResponse);
     HX_RELEASE(pOptions);
     HX_RELEASE(pCommonClassFactory);
 
     if(pMediaPlatform)
     {
         pMediaPlatform->Close();
     }
     HX_RELEASE(pMediaPlatform);
 
     if(fpHXMediaPlatformClose)
     {
         fpHXMediaPlatformClose();
     }
     HX_DELETE(pDLLAccess);
 
-    return retVal;
+    // if return value was not mapped to program return code, report generic error
+    if(FAILED(retVal) && (progRetCode == RC_SUCCESS))
+    {
+        progRetCode = RC_ERROR_GENERIC;
+    }
+
+    return progRetCode;
 }