// Marshal operations private IntPtr MarshalPOD(PatchOptionData managed) { if (null == managed) { throw new ArgumentNullException("managed"); } IntPtr native = this.CreateMainStruct(managed.oldFileSymbolPathArray.Length); Marshal.WriteInt32(native, patchOptionDataSize); // SizeOfThisStruct WriteUInt32(native, symbolOptionFlagsOffset, (uint)managed.symbolOptionFlags); Marshal.WriteIntPtr(native, newFileSymbolPathOffset, PatchAPIMarshaler.OptionalAnsiString(managed.newFileSymbolPath)); Marshal.WriteIntPtr(native, oldFileSymbolPathArrayOffset, PatchAPIMarshaler.CreateArrayOfStringA(managed.oldFileSymbolPathArray)); WriteUInt32(native, extendedOptionFlagsOffset, managed.extendedOptionFlags); // GetFunctionPointerForDelegate() throws an ArgumentNullException if the delegate is null. if (null == managed.symLoadCallback) { Marshal.WriteIntPtr(native, symLoadCallbackOffset, IntPtr.Zero); } else { Marshal.WriteIntPtr(native, symLoadCallbackOffset, Marshal.GetFunctionPointerForDelegate(managed.symLoadCallback)); } Marshal.WriteIntPtr(native, symLoadContextOffset, managed.symLoadContext); Marshal.WriteIntPtr(native, interleaveMapArrayOffset, PatchAPIMarshaler.CreateInterleaveMap(managed.interleaveMapArray)); WriteUInt32(native, maxLzxWindowSizeOffset, managed.maxLzxWindowSize); return(native); }
internal static extern bool CreatePatchFileExW( uint oldFileCount, // maximum 255 [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PatchAPIMarshaler), MarshalCookie = "PATCH_OLD_FILE_INFO_W")] PatchOldFileInfoW[] oldFileInfoArray, string newFileName, // input file (required) string patchFileName, // output file (required) uint optionFlags, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PatchAPIMarshaler), MarshalCookie = "PATCH_OPTION_DATA")] PatchOptionData optionData, [MarshalAs(UnmanagedType.FunctionPtr)] PatchProgressCallback progressCallback, IntPtr context );
/// <summary> /// Create a binary delta file. /// </summary> /// <param name="deltaFile">Name of the delta file to create.</param> /// <param name="targetFile">Name of updated file.</param> /// <param name="targetSymbolPath">Optional paths to updated file's symbols.</param> /// <param name="targetRetainOffsets">Optional offsets to the delta retain sections in the updated file.</param> /// <param name="basisFiles">Optional array of target files.</param> /// <param name="basisSymbolPaths">Optional array of target files' symbol paths (must match basisFiles array).</param> /// <param name="basisIgnoreLengths">Optional array of target files' delta ignore section lengths (must match basisFiles array)(each entry must match basisIgnoreOffsets entries).</param> /// <param name="basisIgnoreOffsets">Optional array of target files' delta ignore section offsets (must match basisFiles array)(each entry must match basisIgnoreLengths entries).</param> /// <param name="basisRetainLengths">Optional array of target files' delta protect section lengths (must match basisFiles array)(each entry must match basisRetainOffsets and targetRetainOffsets entries).</param> /// <param name="basisRetainOffsets">Optional array of target files' delta protect section offsets (must match basisFiles array)(each entry must match basisRetainLengths and targetRetainOffsets entries).</param> /// <param name="apiPatchingSymbolFlags">ApiPatchingSymbolFlags value.</param> /// <param name="optimizePatchSizeForLargeFiles">OptimizePatchSizeForLargeFiles value.</param> /// <param name="retainRangesIgnored">Flag to indicate retain ranges were ignored due to mismatch.</param> /// <returns>true if delta file was created, false if whole file should be used instead.</returns> static public bool CreateDelta( string deltaFile, string targetFile, string targetSymbolPath, string targetRetainOffsets, string[] basisFiles, string[] basisSymbolPaths, string[] basisIgnoreLengths, string[] basisIgnoreOffsets, string[] basisRetainLengths, string[] basisRetainOffsets, PatchSymbolFlagsType apiPatchingSymbolFlags, bool optimizePatchSizeForLargeFiles, out bool retainRangesIgnored ) { retainRangesIgnored = false; if (0 != (apiPatchingSymbolFlags & ~(PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP | PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES | PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO))) { throw new ArgumentOutOfRangeException("apiPatchingSymbolFlags"); } if (null == deltaFile || 0 == deltaFile.Length) { throw new ArgumentNullException("deltaFile"); } if (null == targetFile || 0 == targetFile.Length) { throw new ArgumentNullException("targetFile"); } if (null == basisFiles || 0 == basisFiles.Length) { return(false); } uint countOldFiles = (uint)basisFiles.Length; if (null != basisSymbolPaths) { if (0 != basisSymbolPaths.Length) { if ((uint)basisSymbolPaths.Length != countOldFiles) { throw new ArgumentOutOfRangeException("basisSymbolPaths"); } } } // a null basisSymbolPaths is allowed. if (null != basisIgnoreLengths) { if (0 != basisIgnoreLengths.Length) { if ((uint)basisIgnoreLengths.Length != countOldFiles) { throw new ArgumentOutOfRangeException("basisIgnoreLengths"); } } } else { basisIgnoreLengths = new string[countOldFiles]; } if (null != basisIgnoreOffsets) { if (0 != basisIgnoreOffsets.Length) { if ((uint)basisIgnoreOffsets.Length != countOldFiles) { throw new ArgumentOutOfRangeException("basisIgnoreOffsets"); } } } else { basisIgnoreOffsets = new string[countOldFiles]; } if (null != basisRetainLengths) { if (0 != basisRetainLengths.Length) { if ((uint)basisRetainLengths.Length != countOldFiles) { throw new ArgumentOutOfRangeException("basisRetainLengths"); } } } else { basisRetainLengths = new string[countOldFiles]; } if (null != basisRetainOffsets) { if (0 != basisRetainOffsets.Length) { if ((uint)basisRetainOffsets.Length != countOldFiles) { throw new ArgumentOutOfRangeException("basisRetainOffsets"); } } } else { basisRetainOffsets = new string[countOldFiles]; } PatchOptionData pod = new PatchOptionData(); pod.symbolOptionFlags = apiPatchingSymbolFlags; pod.newFileSymbolPath = targetSymbolPath; pod.oldFileSymbolPathArray = basisSymbolPaths; pod.extendedOptionFlags = 0; PatchOldFileInfoW[] oldFileInfoArray = new PatchOldFileInfoW[countOldFiles]; string[] newRetainOffsetArray = ((null == targetRetainOffsets) ? new string[0] : targetRetainOffsets.Split(',')); for (uint i = 0; i < countOldFiles; ++i) { PatchOldFileInfoW ofi = new PatchOldFileInfoW(); ofi.oldFileName = basisFiles[i]; string[] ignoreLengthArray = ((null == basisIgnoreLengths[i]) ? new string[0] : basisIgnoreLengths[i].Split(',')); string[] ignoreOffsetArray = ((null == basisIgnoreOffsets[i]) ? new string[0] : basisIgnoreOffsets[i].Split(',')); string[] retainLengthArray = ((null == basisRetainLengths[i]) ? new string[0] : basisRetainLengths[i].Split(',')); string[] retainOffsetArray = ((null == basisRetainOffsets[i]) ? new string[0] : basisRetainOffsets[i].Split(',')); // Validate inputs if (ignoreLengthArray.Length != ignoreOffsetArray.Length) { throw new ArgumentOutOfRangeException("basisIgnoreLengths"); } if (retainLengthArray.Length != retainOffsetArray.Length) { throw new ArgumentOutOfRangeException("basisRetainLengths"); } if (newRetainOffsetArray.Length != retainOffsetArray.Length) { // remove all retain range information retainRangesIgnored = true; for (uint j = 0; j < countOldFiles; ++j) { basisRetainLengths[j] = null; basisRetainOffsets[j] = null; } retainLengthArray = new string[0]; retainOffsetArray = new string[0]; newRetainOffsetArray = new string[0]; for (uint j = 0; j < oldFileInfoArray.Length; ++j) { oldFileInfoArray[j].retainRange = null; } } // Populate IgnoreRange structure PatchIgnoreRange[] ignoreArray = null; if (0 != ignoreLengthArray.Length) { ignoreArray = new PatchIgnoreRange[ignoreLengthArray.Length]; for (int j = 0; j < ignoreLengthArray.Length; ++j) { PatchIgnoreRange ignoreRange = new PatchIgnoreRange(); ignoreRange.offsetInOldFile = ParseHexOrDecimal(ignoreOffsetArray[j]); ignoreRange.lengthInBytes = ParseHexOrDecimal(ignoreLengthArray[j]); ignoreArray[j] = ignoreRange; } ofi.ignoreRange = ignoreArray; } PatchRetainRange[] retainArray = null; if (0 != newRetainOffsetArray.Length) { retainArray = new PatchRetainRange[retainLengthArray.Length]; for (int j = 0; j < newRetainOffsetArray.Length; ++j) { PatchRetainRange retainRange = new PatchRetainRange(); retainRange.offsetInOldFile = ParseHexOrDecimal(retainOffsetArray[j]); retainRange.lengthInBytes = ParseHexOrDecimal(retainLengthArray[j]); retainRange.offsetInNewFile = ParseHexOrDecimal(newRetainOffsetArray[j]); retainArray[j] = retainRange; } ofi.retainRange = retainArray; } oldFileInfoArray[i] = ofi; } if (CreatePatchFileExW( countOldFiles, oldFileInfoArray, targetFile, deltaFile, PatchOptionFlags(optimizePatchSizeForLargeFiles), pod, null, IntPtr.Zero)) { return(true); } // determine if this is an error or a need to use whole file. int err = Marshal.GetLastWin32Error(); switch (err) { case unchecked ((int)ERROR_PATCH_BIGGER_THAN_COMPRESSED): break; // too late to exclude this file -- should have been caught before case unchecked ((int)ERROR_PATCH_SAME_FILE): default: throw new System.ComponentModel.Win32Exception(err); } return(false); }