private static void GetErrorMessageFromMetadata(FReportData ReportData, FGenericCrashContext CrashContext)
		{
			if (string.IsNullOrEmpty(CrashContext.PrimaryCrashProperties.ErrorMessage))
			{
				CrashContext.PrimaryCrashProperties.ErrorMessage = string.Join("\n", ReportData.ErrorMessage);
			}
		}
		// From CrashUpload.cpp
		/*
		struct FCompressedCrashFile : FNoncopyable
		{
			int32 CurrentFileIndex; // 4 bytes for file index
			FString Filename; // 4 bytes for length + 260 bytes for char data
			TArray<uint8> Filedata; // 4 bytes for length + N bytes for data
		}
		*/

		/// <summary> Enqueues a new crash. </summary>
		private bool EnqueueNewReport(string NewReportPath)
		{
			string ReportName = Path.GetFileName(NewReportPath);

			string CompressedReportPath = Path.Combine(NewReportPath, ReportName + ".ue4crash");
			string MetadataPath = Path.Combine(NewReportPath, ReportName + ".xml");
			bool bIsCompressed = File.Exists(CompressedReportPath) && File.Exists(MetadataPath);
			if (bIsCompressed)
			{
				FCompressedCrashInformation CompressedCrashInformation = XmlHandler.ReadXml<FCompressedCrashInformation>(MetadataPath);
				bool bResult = DecompressReport(CompressedReportPath, CompressedCrashInformation);
				if (!bResult)
				{
					ReportProcessor.MoveReportToInvalid(NewReportPath, "DECOMPRESSION_FAIL_" + DateTime.Now.Ticks + "_" + ReportName);
					return false;
				}
				else
				{
					// Rename metadata file to not interfere with the WERReportMetadata.
					File.Move(MetadataPath, Path.ChangeExtension(MetadataPath, "processed_xml"));
				}
			}

			// Unified crash reporting
			FGenericCrashContext GenericContext = FindCrashContext(NewReportPath);
			FGenericCrashContext Context = GenericContext;

			bool bContextDirty = false;
			WERReportMetadata MetaData = FindMetadata(NewReportPath);
			if (MetaData != null)
			{
				if (Context == null)
				{
					// Missing crash context
					FReportData ReportData = new FReportData(MetaData, NewReportPath);
					ConvertMetadataToCrashContext(ReportData, NewReportPath, ref Context);
					bContextDirty = true;
				}
				else if (!Context.HasProcessedData())
				{
					// Missing data - try to get from WER metadata
					FReportData ReportData = new FReportData(MetaData, NewReportPath);
					GetErrorMessageFromMetadata(ReportData, Context);
					bContextDirty = true;
				}
			}

			if (Context == null)
			{
				CrashReporterProcessServicer.WriteFailure("! NoCntx  : Path=" + NewReportPath);
				ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath));
				return false;
			}

			Context.CrashDirectory = NewReportPath;
			Context.PrimaryCrashProperties.SetPlatformFullName();

			// Added data from WER, save to the crash context file.
			if (bContextDirty)
			{
				Context.ToFile();
			}

			FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion);

			uint BuiltFromCL = EngineVersion.Changelist;

			string BranchName = EngineVersion.Branch;
			if (string.IsNullOrEmpty(BranchName))
			{
				CrashReporterProcessServicer.WriteEvent("% Warning NoBranch: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath + " EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion);
				Context.PrimaryCrashProperties.ProcessorFailedMessage = "Engine version has no branch name. EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion;
                Context.ToFile();
            }
			else if (BranchName.Equals(CrashReporterConstants.LicenseeBranchName, StringComparison.InvariantCultureIgnoreCase))
			{
				CrashReporterProcessServicer.WriteEvent("% Warning branch is UE4-QA  : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath);
				Context.PrimaryCrashProperties.ProcessorFailedMessage = "Branch was the forbidden LicenseeBranchName=" + BranchName;
                Context.ToFile();
            }

			// Look for the Diagnostics.txt, if we have a diagnostics file we can continue event if the CL is marked as broken.
			bool bHasDiagnostics = FindDiagnostics(NewReportPath);

			if (BuiltFromCL == 0 && (!bHasDiagnostics && !Context.HasProcessedData()))
			{
				// For now ignore all locally made crashes.
				CrashReporterProcessServicer.WriteEvent("% Warning CL=0 and no useful data : BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath);
				Context.PrimaryCrashProperties.ProcessorFailedMessage = "Report from CL=0 has no diagnostics, callstack or error msg";
                Context.ToFile();
            }

			// Check static reports index for duplicated reports
			// This WILL happen when running multiple, non-mutually exclusive crash sources (e.g. Receiver + Data Router)
			// This can be safely discontinued when all crashes come from the same SQS
			// This DOES NOT scale to multiple CRP instances
			lock (ReportIndexLock)
			{
				if (!ReportIndex.TryAddNewReport(ReportName))
				{
					// Crash report not accepted by index
					CrashReporterProcessServicer.WriteEvent(string.Format(
						"EnqueueNewReport: Duplicate report skipped {0} in queue {1}", NewReportPath, QueueName));
					CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.DuplicateRejected);
					ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath));
					return false;
				}
			}

			if (ShouldDecimateNextReport())
			{
				CrashReporterProcessServicer.WriteEvent(string.Format("EnqueueNewReport: Discarding Report due to backlog of {0} in queue {1}: Path={2}", GetTotalWaitingCount(), QueueName, NewReportPath));
				CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.ReportDiscarded);
				ReportProcessor.CleanReport(new DirectoryInfo(NewReportPath));
				return false;
			}

			lock (NewReportsLock)
			{
				NewCrashContexts.Enqueue(Context);
			}
			EnqueueCounter.AddEvent();
			CrashReporterProcessServicer.StatusReporter.IncrementCount(StatusReportingEventNames.QueuedEvent);
			CrashReporterProcessServicer.WriteEvent("+ Enqueued: BuiltFromCL=" + string.Format("{0,7}", BuiltFromCL) + " Path=" + NewReportPath);
			return true;
		}
		/// <summary> Converts WER metadata xml file to the crash context. </summary>
		private static void ConvertMetadataToCrashContext(FReportData ReportData, string NewReportPath, ref FGenericCrashContext OutCrashContext)
		{
			if (OutCrashContext == null)
			{
				OutCrashContext = new FGenericCrashContext();
			}

			OutCrashContext.PrimaryCrashProperties.CrashVersion = (int)ECrashDescVersions.VER_1_NewCrashFormat;

			//OutCrashContext.PrimaryCrashProperties.ProcessId = 0; don't overwrite valid ids, zero is default anyway
			OutCrashContext.PrimaryCrashProperties.CrashGUID = new DirectoryInfo(NewReportPath).Name;
			// 			OutCrashContext.PrimaryCrashProperties.IsInternalBuild
			// 			OutCrashContext.PrimaryCrashProperties.IsPerforceBuild
			// 			OutCrashContext.PrimaryCrashProperties.IsSourceDistribution
			// 			OutCrashContext.PrimaryCrashProperties.SecondsSinceStart
			OutCrashContext.PrimaryCrashProperties.GameName = ReportData.GameName;
			// 			OutCrashContext.PrimaryCrashProperties.ExecutableName
			// 			OutCrashContext.PrimaryCrashProperties.BuildConfiguration
			// 			OutCrashContext.PrimaryCrashProperties.PlatformName
			// 			OutCrashContext.PrimaryCrashProperties.PlatformNameIni
			OutCrashContext.PrimaryCrashProperties.PlatformFullName = ReportData.Platform;
			OutCrashContext.PrimaryCrashProperties.EngineMode = ReportData.EngineMode;
			OutCrashContext.PrimaryCrashProperties.EngineVersion = ReportData.GetEngineVersion();
			OutCrashContext.PrimaryCrashProperties.BuildVersion = ReportData.BuildVersion;
			OutCrashContext.PrimaryCrashProperties.CommandLine = ReportData.CommandLine;
			// 			OutCrashContext.PrimaryCrashProperties.LanguageLCID

			// Create a locate and get the language.
			int LanguageCode = 0;
			int.TryParse(ReportData.Language, out LanguageCode);
			try
			{
				if (LanguageCode > 0)
				{
					CultureInfo LanguageCI = new CultureInfo(LanguageCode);
					OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = LanguageCI.Name;
				}
			}
			catch (Exception)
			{
				OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = null;
			}

			if (string.IsNullOrEmpty(OutCrashContext.PrimaryCrashProperties.AppDefaultLocale))
			{
				// Default to en-US
				OutCrashContext.PrimaryCrashProperties.AppDefaultLocale = "en-US";
			}

			// 			OutCrashContext.PrimaryCrashProperties.IsUE4Release
			string WERUserName = ReportData.UserName;
			if (!string.IsNullOrEmpty(WERUserName) || string.IsNullOrEmpty(OutCrashContext.PrimaryCrashProperties.UserName))
			{
				OutCrashContext.PrimaryCrashProperties.UserName = WERUserName;
			}

			OutCrashContext.PrimaryCrashProperties.BaseDir = ReportData.BaseDir;
			// 			OutCrashContext.PrimaryCrashProperties.RootDir
			OutCrashContext.PrimaryCrashProperties.MachineId = ReportData.MachineId;
			OutCrashContext.PrimaryCrashProperties.EpicAccountId = ReportData.EpicAccountId;
			// 			OutCrashContext.PrimaryCrashProperties.CallStack
			// 			OutCrashContext.PrimaryCrashProperties.SourceContext
			OutCrashContext.PrimaryCrashProperties.UserDescription = string.Join("\n", ReportData.UserDescription);

			// 			OutCrashContext.PrimaryCrashProperties.CrashDumpMode
			// 			OutCrashContext.PrimaryCrashProperties.Misc.NumberOfCores
			// 			OutCrashContext.PrimaryCrashProperties.Misc.NumberOfCoresIncludingHyperthreads
			// 			OutCrashContext.PrimaryCrashProperties.Misc.Is64bitOperatingSystem
			// 			OutCrashContext.PrimaryCrashProperties.Misc.CPUVendor
			// 			OutCrashContext.PrimaryCrashProperties.Misc.CPUBrand
			// 			OutCrashContext.PrimaryCrashProperties.Misc.PrimaryGPUBrand
			// 			OutCrashContext.PrimaryCrashProperties.Misc.OSVersionMajor
			// 			OutCrashContext.PrimaryCrashProperties.Misc.OSVersionMinor
			// 			OutCrashContext.PrimaryCrashProperties.Misc.AppDiskTotalNumberOfBytes
			// 			OutCrashContext.PrimaryCrashProperties.Misc.AppDiskNumberOfFreeBytes
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalPhysical
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalVirtual
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.PageSize
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.TotalPhysicalGB
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.AvailablePhysical
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.AvailableVirtual
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.UsedPhysical
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.PeakUsedPhysical
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.UsedVirtual
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.PeakUsedVirtual
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.bIsOOM
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.OOMAllocationSize
			// 			OutCrashContext.PrimaryCrashProperties.MemoryStats.OOMAllocationAlignment
			OutCrashContext.PrimaryCrashProperties.TimeofCrash = new DateTime(ReportData.Ticks);
			OutCrashContext.PrimaryCrashProperties.bAllowToBeContacted = ReportData.AllowToBeContacted;

			OutCrashContext.PrimaryCrashProperties.DeploymentName = ReportData.DeploymentName;
			OutCrashContext.PrimaryCrashProperties.IsEnsure = ReportData.IsEnsure;
			OutCrashContext.PrimaryCrashProperties.IsAssert = ReportData.IsAssert;
			OutCrashContext.PrimaryCrashProperties.CrashType = ReportData.CrashType;

			GetErrorMessageFromMetadata(ReportData, OutCrashContext);
		}