From 1f0570c7bc03727a3ca52280f76a6449ef2c97b7 Mon Sep 17 00:00:00 2001 From: Daoluong Goro Date: Thu, 16 Jul 2020 18:57:22 +0700 Subject: [PATCH] migrate to net core, add code from pull requests #388 #394 of original fork --- .gitignore | 7 +- ArcFormats/ArcFormats.Core.csproj | 79 ++ ArcFormats/ArcFormats.csproj | 1232 ----------------- ArcFormats/Circus/ImageCRX.cs | 293 +++- ArcFormats/KiriKiri/ArcXP3.cs | 2 +- ArcFormats/Properties/AssemblyInfo.cs | 6 +- ArcFormats/Strings/arcStrings.Designer.cs | 2 +- .../AssemblyInfo.cs | 19 + .../Deployment/Compression/Cab/CabEngine.cs | 88 ++ .../Compression/Cab/CabException.cs | 103 ++ .../Deployment/Compression/Cab/CabFileInfo.cs | 84 ++ .../Deployment/Compression/Cab/CabInfo.cs | 49 + .../Deployment/Compression/Cab/CabPacker.cs | 489 +++++++ .../Deployment/Compression/Cab/CabUnpacker.cs | 415 ++++++ .../Deployment/Compression/Cab/CabWorker.cs | 314 +++++ .../Deployment/Compression/Cab/Errors.resx | 186 +++ .../Compression/Cab/HandleManager`1.cs | 43 + .../Compression/Cab/NativeMethods.cs | 432 ++++++ ...oft.Deployment.Compression.Cab.Core.csproj | 24 + ...icrosoft.Deployment.Compression.Cab.csproj | 57 + .../WindowsInstallerXml/WixDistribution.cs | 65 + .../AssemblyInfo.cs | 19 + .../Compression/ArchiveException.cs | 36 + .../Deployment/Compression/ArchiveFileInfo.cs | 238 ++++ .../Compression/ArchiveFileStreamContext.cs | 268 ++++ .../Deployment/Compression/ArchiveInfo.cs | 375 +++++ .../Compression/ArchiveProgressEventArgs.cs | 161 +++ .../Compression/ArchiveProgressType.cs | 18 + .../Compression/BasicUnpackStreamContext.cs | 56 + .../Deployment/Compression/CargoStream.cs | 118 ++ .../Compression/CompressionEngine.cs | 178 +++ .../Compression/CompressionLevel.cs | 16 + .../Deployment/Compression/DuplicateStream.cs | 134 ++ .../Compression/IPackStreamContext.cs | 33 + .../Compression/IUnpackStreamContext.cs | 29 + .../Deployment/Compression/OffsetStream.cs | 126 ++ .../Compression/SafeNativeMethods.cs | 29 + ...crosoft.Deployment.Compression.Core.csproj | 20 + .../Microsoft.Deployment.Compression.csproj | 57 + .../WindowsInstallerXml/WixDistribution.cs | 65 + Console/ConsoleBrowser.cs | 685 ++++++--- Console/GARbro.Console.Core.csproj | 26 + Console/GARbro.Console.csproj | 110 -- Console/README.md | 32 +- Experimental/CellWorks/ArcDB.cs | 93 +- Experimental/Experimental.Core.csproj | 42 + Experimental/Experimental.csproj | 182 --- Experimental/Properties/AssemblyInfo.cs | 6 +- Experimental/RPGMaker/ImageRPGMV.cs | 10 +- GARbro.sln | 128 +- GUI/App.xaml.cs | 2 + GUI/AutoComplete.cs | 126 +- GUI/ExtractDialog.cs | 2 +- GUI/GARbro.GUI.Core.csproj | 113 ++ GUI/GARbro.GUI.csproj | 362 ----- GUI/GARbro.GUI.csproj.user | 17 - GUI/MainWindow.xaml.cs | 2 +- GUI/Properties/AssemblyInfo.cs | 6 +- GUI/Properties/Settings.Designer.cs | 2 +- GameRes/ArcView.cs | 4 +- GameRes/GameRes.Core.csproj | 52 + GameRes/GameRes.csproj | 145 -- GameRes/Properties/AssemblyInfo.cs | 6 +- GameRes/Strings/garStrings.Designer.cs | 2 +- Image.Convert/Image.Convert.Core.csproj | 25 + Image.Convert/Image.Convert.csproj | 79 -- Image.Convert/Image.Convert.csproj.user | 6 - Legacy/Legacy.Core.csproj | 46 + Legacy/Legacy.csproj | 289 ---- Legacy/Properties/AssemblyInfo.cs | 6 +- Net20/Net20.Core.csproj | 22 + Net20/Net20.csproj | 59 - README.md | 2 +- inc-revision.csx | 140 ++ inc-revision.pl | 70 - 75 files changed, 5949 insertions(+), 2915 deletions(-) create mode 100644 ArcFormats/ArcFormats.Core.csproj delete mode 100644 ArcFormats/ArcFormats.csproj create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/AssemblyInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabEngine.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabException.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabFileInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabPacker.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabUnpacker.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabWorker.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/Errors.resx create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/HandleManager`1.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/NativeMethods.cs create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.Core.csproj create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.csproj create mode 100644 Cab/Microsoft.Deployment.Compression.Cab/Tools/WindowsInstallerXml/WixDistribution.cs create mode 100644 Cab/Microsoft.Deployment.Compression/AssemblyInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveException.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileStreamContext.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveInfo.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressEventArgs.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressType.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/BasicUnpackStreamContext.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/CargoStream.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionEngine.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionLevel.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/DuplicateStream.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/IPackStreamContext.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/IUnpackStreamContext.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/OffsetStream.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Deployment/Compression/SafeNativeMethods.cs create mode 100644 Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.Core.csproj create mode 100644 Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.csproj create mode 100644 Cab/Microsoft.Deployment.Compression/Tools/WindowsInstallerXml/WixDistribution.cs create mode 100644 Console/GARbro.Console.Core.csproj delete mode 100644 Console/GARbro.Console.csproj create mode 100644 Experimental/Experimental.Core.csproj delete mode 100644 Experimental/Experimental.csproj create mode 100644 GUI/GARbro.GUI.Core.csproj delete mode 100644 GUI/GARbro.GUI.csproj delete mode 100644 GUI/GARbro.GUI.csproj.user create mode 100644 GameRes/GameRes.Core.csproj delete mode 100644 GameRes/GameRes.csproj create mode 100644 Image.Convert/Image.Convert.Core.csproj delete mode 100644 Image.Convert/Image.Convert.csproj delete mode 100644 Image.Convert/Image.Convert.csproj.user create mode 100644 Legacy/Legacy.Core.csproj delete mode 100644 Legacy/Legacy.csproj create mode 100644 Net20/Net20.Core.csproj delete mode 100644 Net20/Net20.csproj create mode 100644 inc-revision.csx delete mode 100644 inc-revision.pl diff --git a/.gitignore b/.gitignore index 5d9fb361..7b891ead 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bin obj tags +.vs *.exe *.dll *.pdb @@ -14,5 +15,9 @@ Images SchemeBuilder Makefile packages -Experimental +#Experimental .nuget +*.csproj.user +/.vscode +/omnisharp.json +/inc-revision.pl diff --git a/ArcFormats/ArcFormats.Core.csproj b/ArcFormats/ArcFormats.Core.csproj new file mode 100644 index 00000000..643aba4a --- /dev/null +++ b/ArcFormats/ArcFormats.Core.csproj @@ -0,0 +1,79 @@ + + + + netcoreapp3.1 + ArcFormats + GameRes.Formats + true + false + + + + TRACE;DEBUG;NETCORE + ..\bin\Debug\ + true + + + + ..\bin\Release\ + DEBUG;TRACE;NETCORE + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + arcStrings.resx + + + + + + PublicResXFileCodeGenerator + arcStrings.Designer.cs + + + + + + + + + + + + diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj deleted file mode 100644 index 95ff52b7..00000000 --- a/ArcFormats/ArcFormats.csproj +++ /dev/null @@ -1,1232 +0,0 @@ - - - - - Debug - AnyCPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4} - Library - Properties - GameRes.Formats - ArcFormats - v4.6 - 512 - - ..\ - true - - - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - true - 6291456 - - - none - true - ..\bin\Release\ - - - prompt - 4 - false - true - 6291456 - - - ..\bin\Prerelease\ - 6291456 - true - true - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\packages\SharpZipLib.1.1.0\lib\net45\ICSharpCode.SharpZipLib.dll - True - - - ..\packages\NAudio.1.7.3\lib\net35\NAudio.dll - - - ..\packages\NVorbis.0.8.6\lib\net35\NVorbis.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetAGS.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetLEAF.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetZIP.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetSJDAT.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetMSD.xaml - - - - - - - - - - - - - - - - - - - - - - - - - WidgetBELL.xaml - - - - - WidgetEAGLS.xaml - - - - WidgetGYU.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetAZ.xaml - - - - - - - - - - - - - WidgetSCR.xaml - - - - - - - - - - - - - - - - - - WidgetGAL.xaml - - - - WidgetMGPK.xaml - - - - - - - - - WidgetPAZ.xaml - - - - - - - - - - - WidgetNPK.xaml - - - - - - WidgetNCARC.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetMCG.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetTactics.xaml - - - - - - - WidgetPCK.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetQLIE.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetNSA.xaml - - - - - - - - - - WidgetARC.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WidgetRCT.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CreateAMIWidget.xaml - - - CreateINTWidget.xaml - - - CreateNPAWidget.xaml - - - CreateONSWidget.xaml - - - CreatePDWidget.xaml - - - CreateRPAWidget.xaml - - - CreateSGWidget.xaml - - - CreateARCWidget.xaml - - - CreateXP3Widget.xaml - - - CreateYPFWidget.xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - True - True - arcStrings.resx - - - WidgetDPK.xaml - - - WidgetINT.xaml - - - WidgetISF.xaml - - - WidgetKCAP.xaml - - - Code - WidgetLPK.xaml - - - WidgetMBL.xaml - - - WidgetNOA.xaml - - - WidgetNPA.xaml - - - WidgetWARC.xaml - - - WidgetXP3.xaml - - - WidgetYPF.xaml - - - - - - - - - - - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - - - {73b6c693-9846-4d33-8300-a80239fcfff9} - Net20 - - - - - - PublicSettingsSingleFileGenerator - Settings.Designer.cs - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - - PublicResXFileCodeGenerator - arcStrings.Designer.cs - - - - - - - perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) -exit 0 - - - if not exist "$(TargetDir)\GameData" mkdir "$(TargetDir)\GameData" -xcopy "$(ProjectDir)\Resources\Formats.dat" "$(TargetDir)\GameData\" /D /Y >NUL - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/ArcFormats/Circus/ImageCRX.cs b/ArcFormats/Circus/ImageCRX.cs index b204f154..d3e6fcb9 100644 --- a/ArcFormats/Circus/ImageCRX.cs +++ b/ArcFormats/Circus/ImageCRX.cs @@ -26,6 +26,7 @@ using System; using System.ComponentModel.Composition; using System.IO; +using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using GameRes.Compression; @@ -47,6 +48,7 @@ public class CrxFormat : ImageFormat public override string Tag { get { return "CRX"; } } public override string Description { get { return "Circus image format"; } } public override uint Signature { get { return 0x47585243; } } // 'CRXG' + public override bool CanWrite { get { return true; } } public override ImageMetaData ReadMetaData (IBinaryStream stream) { @@ -81,7 +83,77 @@ public override ImageData Read (IBinaryStream stream, ImageMetaData info) public override void Write (Stream file, ImageData image) { - throw new NotImplementedException ("CrxFormat.Write not implemented"); + //throw new NotImplementedException ("CrxFormat.Write not implemented"); + var header = new byte[0x14]; + + var depth = (short)(24 == image.BPP ? 0 : 32 == image.BPP ? 1 : 2); + var compression = (ushort)3; + var flags = (ushort)17; + var mode = (ushort)0; + + using (var memeStream = new MemoryStream(header)) + { + using (var binaryWriter = new BinaryWriter(memeStream)) + { + binaryWriter.Write(Signature); + binaryWriter.Write((ushort)image.OffsetX); + binaryWriter.Write((ushort)image.OffsetY); + binaryWriter.Write((ushort)image.Width); + binaryWriter.Write((ushort)image.Height); + binaryWriter.Write(compression); + binaryWriter.Write(flags); + binaryWriter.Write(depth); + binaryWriter.Write(mode); + } + } + + var metaData = ReadMetaData(BinaryStream.FromArray(header, "")); + + var bitmap = image.Bitmap; + var pixelFormat = CheckFormat(image.BPP); + + int stride = (int)(image.Width * pixelFormat.BitsPerPixel / 8 + 3) & ~3; + + if (pixelFormat != bitmap.Format) + { + var converted_bitmap = new FormatConvertedBitmap(); + converted_bitmap.BeginInit(); + converted_bitmap.Source = image.Bitmap; + converted_bitmap.DestinationFormat = pixelFormat; + converted_bitmap.EndInit(); + bitmap = converted_bitmap; + } + + var data = new byte[image.Height * stride]; + var row_data = new byte[stride]; + var rect = new Int32Rect(0, 0, (int)image.Width, 1); + + for (uint row = 0; row < image.Height; ++row) + { + bitmap.CopyPixels(rect, row_data, stride, 0); + rect.Y++; + row_data.CopyTo(data, row * stride); + } + + using (var binaryWriter = new BinaryWriter(file)) + { + binaryWriter.Write(header); + using (var writer = new Writer(data, + binaryWriter, (CrxMetaData)metaData)) + { + writer.Write(); + } + } + } + private static PixelFormat CheckFormat(int bpp) + { + switch (bpp) + { + case 24: return PixelFormats.Bgr24; + case 32: return PixelFormats.Bgra32; + case 8: return PixelFormats.Indexed8; + default: throw new InvalidFormatException(); + } } internal sealed class Reader : IDisposable @@ -116,6 +188,7 @@ public Reader (IBinaryStream input, CrxMetaData info) case 8: Format = PixelFormats.Indexed8; break; default: throw new InvalidFormatException(); } + Format = CheckFormat(m_bpp); m_stride = (m_width * m_bpp / 8 + 3) & ~3; m_output = new byte[m_height*m_stride]; m_input = input; @@ -335,6 +408,224 @@ public void Dispose () { } #endregion + + } + + internal sealed class Writer : IDisposable + { + BinaryWriter m_output; + byte[] m_input; + int m_width; + int m_height; + int m_stride; + int m_bpp; + int m_compression; + int m_flags; + int m_mode; + + public byte[] Data { get { return m_input; } } + public PixelFormat Format { get; private set; } + public BitmapPalette Palette { get; private set; } + public int Stride { get { return m_stride; } } + + public Writer(byte[] input, + BinaryWriter output, + CrxMetaData info) + { + m_width = (int)info.Width; + m_height = (int)info.Height; + m_bpp = info.BPP; + m_compression = info.Compression; + m_flags = info.CompressionFlags; + m_mode = info.Mode; + Format = CheckFormat(m_bpp); + m_stride = (m_width * m_bpp / 8 + 3) & ~3; + + m_input = input; + m_output = output; + + m_output.Seek(0x14, SeekOrigin.Begin); + + if (8 == m_bpp) + ReadPalette(info.Colors); + } + + private void ReadPalette(int colors) + { + throw new NotImplementedException("CrxFormat.Write 8bit bpp not implemented"); + } + + + public void Write(bool isDiff = false) + { + int compressed_size_position = 40; + + if (m_compression >= 3) + { + var count = 1; + m_output.Write(count); + m_output.Seek(count * 0x10, SeekOrigin.Current); + + } + if (0 != (m_flags & 0x10)) + { + compressed_size_position = (int)m_output.BaseStream.Position + 4; + m_output.Seek(compressed_size_position, SeekOrigin.Begin); + } + + if (32 == m_bpp && m_mode != 1) + { + int alpha_flip = 2 == m_mode ? 0 : 0xFF; + int line = 0; + for (int h = 0; h < m_height; h++) + { + for (int w = 0; w < m_width; w++) + { + int pixel = line + w * 4; + + var b = m_input[pixel]; + var g = m_input[pixel + 1]; + var r = m_input[pixel + 2]; + var alpha = m_input[pixel + 3]; + + m_input[pixel] = (byte)(alpha ^ alpha_flip); + m_input[pixel + 1] = b; + m_input[pixel + 2] = g; + m_input[pixel + 3] = r; + + } + line += m_stride; + } + } + + if (1 == m_compression) + WriteV1(); + else + WriteV2(); + + m_output.Seek(compressed_size_position - 4, SeekOrigin.Begin); + var compressed_size = (int)m_output.BaseStream.Length; // compressed_size + m_output.Write(compressed_size); + } + + private void WriteV2() + { + int pixel_size = m_bpp / 8; + int src_stride = m_width * pixel_size; + m_output.Flush(); + + using (var zlib = new ZLibStream(m_output.BaseStream, CompressionMode.Compress, true)) + using (var output = new BinaryWriter(zlib)) + { + + if (m_bpp >= 24) + { + for (int y = 0; y < m_height; ++y) + { + + byte ctl = 0; + output.Write(ctl); + + int dst = y * m_stride; + int prev_row = dst - m_stride; + switch (ctl) + { + case 0: + output.Write(m_input, dst, pixel_size); + for (int x = pixel_size; x < src_stride; ++x) + { + output.Write((byte)(m_input[dst + x] - m_input[dst + x - pixel_size])); + } + break; + case 1: + for (int x = 0; x < src_stride; ++x) + { + output.Write((byte)(m_input[dst + x] - m_input[prev_row + x])); + } + break; + case 2: + output.Write(m_input, dst, pixel_size); + + for (int x = pixel_size; x < src_stride; ++x) + { + output.Write((byte)(m_input[dst + x] - m_input[prev_row + x - pixel_size])); + } + break; + case 3: + for (int x = src_stride - pixel_size; x > 0; --x) + { + output.Write((byte)(m_input[dst++] - m_input[prev_row++ + pixel_size])); + } + output.Write(m_input, dst, pixel_size); + break; + case 4: + for (int i = 0; i < pixel_size; ++i) + { + int w = m_width; + byte val = m_input[dst]; + output.Write(val); + while (w > 0) + { + dst += pixel_size; + if (0 == --w) + break; + + byte next = m_input[dst]; + output.Write(next); + + if (val == next) + { + var count = 255; + + output.Write(count); + + dst += pixel_size * count; + w -= count; + + if (w > 0) + { + val = m_input[dst]; + output.Write(val); + } + + } + else + { + val = next; + } + + } + dst -= src_stride - 1; + } + break; + default: + break; + } + } + } + else + { + int dst = 0; + for (int y = 0; y < m_height; ++y) + { + m_output.Write(m_input, dst, src_stride); + dst += m_stride; + } + } + } + + } + + private void WriteV1() + { + throw new NotImplementedException("CrxFormat.Write version 1 not implemented"); + } + + #region IDisposable Members + public void Dispose() + { + } + #endregion } } } diff --git a/ArcFormats/KiriKiri/ArcXP3.cs b/ArcFormats/KiriKiri/ArcXP3.cs index b0971e68..b501ef75 100644 --- a/ArcFormats/KiriKiri/ArcXP3.cs +++ b/ArcFormats/KiriKiri/ArcXP3.cs @@ -595,7 +595,7 @@ void EncryptedFileCopy (FileStream file, Xp3Entry xp3entry, Stream output, bool throw new FileSizeException(); using (var map = MemoryMappedFile.CreateFromFile (file, null, 0, - MemoryMappedFileAccess.Read, null, HandleInheritability.None, true)) + MemoryMappedFileAccess.Read/*, null*/, HandleInheritability.None, true)) { uint unpacked_size = (uint)file.Length; xp3entry.UnpackedSize = (uint)unpacked_size; diff --git a/ArcFormats/Properties/AssemblyInfo.cs b/ArcFormats/Properties/AssemblyInfo.cs index df1ffa68..9922ad20 100644 --- a/ArcFormats/Properties/AssemblyInfo.cs +++ b/ArcFormats/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.2.48.2153")] -[assembly: AssemblyFileVersion ("1.2.48.2153")] +[assembly: AssemblyVersion ("1.2.48.2178")] +[assembly: AssemblyFileVersion ("1.2.48.2178")] diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs index be107284..223154b9 100644 --- a/ArcFormats/Strings/arcStrings.Designer.cs +++ b/ArcFormats/Strings/arcStrings.Designer.cs @@ -19,7 +19,7 @@ namespace GameRes.Formats.Strings { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class arcStrings { diff --git a/Cab/Microsoft.Deployment.Compression.Cab/AssemblyInfo.cs b/Cab/Microsoft.Deployment.Compression.Cab/AssemblyInfo.cs new file mode 100644 index 00000000..bc978b0f --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; + +[assembly: AssemblyDescription("Managed libraries for cabinet archive packing and unpacking")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] +[assembly: AllowPartiallyTrustedCallers] +[assembly: AssemblyFileVersion("3.10.1.2213")] +[assembly: AssemblyCompany("Outercurve Foundation")] +[assembly: AssemblyCopyright("Copyright (c) Outercurve Foundation. All rights reserved.")] +[assembly: AssemblyProduct("Windows Installer XML Toolset")] +[assembly: AssemblyConfiguration("")] +[assembly: NeutralResourcesLanguage("en-US")] +[assembly: AssemblyVersion("3.0.0.0")] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion = true, UnmanagedCode = true)] diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabEngine.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabEngine.cs new file mode 100644 index 00000000..913c0683 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabEngine.cs @@ -0,0 +1,88 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabEngine +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.Deployment.Compression.Cab +{ + public class CabEngine : CompressionEngine + { + private CabPacker packer; + private CabUnpacker unpacker; + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (this.packer != null) + { + this.packer.Dispose(); + this.packer = (CabPacker) null; + } + if (this.unpacker != null) + { + this.unpacker.Dispose(); + this.unpacker = (CabUnpacker) null; + } + } + base.Dispose(disposing); + } + + private CabPacker Packer + { + get + { + if (this.packer == null) + this.packer = new CabPacker(this); + return this.packer; + } + } + + private CabUnpacker Unpacker + { + get + { + if (this.unpacker == null) + this.unpacker = new CabUnpacker(this); + return this.unpacker; + } + } + + public override void Pack( + IPackStreamContext streamContext, + IEnumerable files, + long maxArchiveSize) + { + this.Packer.CompressionLevel = this.CompressionLevel; + this.Packer.UseTempFiles = this.UseTempFiles; + this.Packer.Pack(streamContext, files, maxArchiveSize); + } + + public override bool IsArchive(Stream stream) + { + return this.Unpacker.IsArchive(stream); + } + + public override IList GetFileInfo( + IUnpackStreamContext streamContext, + Predicate fileFilter) + { + return this.Unpacker.GetFileInfo(streamContext, fileFilter); + } + + public override void Unpack(IUnpackStreamContext streamContext, Predicate fileFilter) + { + this.Unpacker.Unpack(streamContext, fileFilter); + } + + internal void ReportProgress(ArchiveProgressEventArgs e) + { + this.OnProgress(e); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabException.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabException.cs new file mode 100644 index 00000000..c9a8b0bd --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabException.cs @@ -0,0 +1,103 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabException +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Globalization; +using System.Resources; +using System.Runtime.Serialization; +using System.Security.Permissions; + +namespace Microsoft.Deployment.Compression.Cab +{ + [Serializable] + public class CabException : ArchiveException + { + private static ResourceManager errorResources; + private int error; + private int errorCode; + + public CabException(string message, Exception innerException) + : this(0, 0, message, innerException) + { + } + + public CabException(string message) + : this(0, 0, message, (Exception) null) + { + } + + public CabException() + : this(0, 0, (string) null, (Exception) null) + { + } + + internal CabException(int error, int errorCode, string message, Exception innerException) + : base(message, innerException) + { + this.error = error; + this.errorCode = errorCode; + } + + internal CabException(int error, int errorCode, string message) + : this(error, errorCode, message, (Exception) null) + { + } + + protected CabException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + if (info == null) + throw new ArgumentNullException(nameof (info)); + this.error = info.GetInt32("cabError"); + this.errorCode = info.GetInt32("cabErrorCode"); + } + + public int Error + { + get + { + return this.error; + } + } + + public int ErrorCode + { + get + { + return this.errorCode; + } + } + + internal static ResourceManager ErrorResources + { + get + { + if (CabException.errorResources == null) + CabException.errorResources = new ResourceManager(typeof (CabException).Namespace + ".Errors", typeof (CabException).Assembly); + return CabException.errorResources; + } + } + + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException(nameof (info)); + info.AddValue("cabError", this.error); + info.AddValue("cabErrorCode", this.errorCode); + base.GetObjectData(info, context); + } + + internal static string GetErrorMessage(int error, int errorCode, bool extracting) + { + int num = extracting ? 2000 : 1000; + string str = CabException.ErrorResources.GetString(checked (num + error).ToString((IFormatProvider) CultureInfo.InvariantCulture.NumberFormat), CultureInfo.CurrentCulture) ?? CabException.ErrorResources.GetString(num.ToString((IFormatProvider) CultureInfo.InvariantCulture.NumberFormat), CultureInfo.CurrentCulture); + if (errorCode != 0) + str = string.Format((IFormatProvider) CultureInfo.InvariantCulture, "{0} " + CabException.ErrorResources.GetString("1", CultureInfo.CurrentCulture), (object) str, (object) errorCode); + return str; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabFileInfo.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabFileInfo.cs new file mode 100644 index 00000000..004d7568 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabFileInfo.cs @@ -0,0 +1,84 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabFileInfo +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Security.Permissions; + +namespace Microsoft.Deployment.Compression.Cab +{ + [Serializable] + public class CabFileInfo : ArchiveFileInfo + { + private int cabFolder; + + public CabFileInfo(CabInfo cabinetInfo, string filePath) + : base((ArchiveInfo) cabinetInfo, filePath) + { + if (cabinetInfo == null) + throw new ArgumentNullException(nameof (cabinetInfo)); + this.cabFolder = -1; + } + + internal CabFileInfo( + string filePath, + int cabFolder, + int cabNumber, + FileAttributes attributes, + DateTime lastWriteTime, + long length) + : base(filePath, cabNumber, attributes, lastWriteTime, length) + { + this.cabFolder = cabFolder; + } + + protected CabFileInfo(SerializationInfo info, StreamingContext context) + : base(info, context) + { + this.cabFolder = info.GetInt32(nameof (cabFolder)); + } + + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("cabFolder", this.cabFolder); + } + + public CabInfo Cabinet + { + get + { + return (CabInfo) this.Archive; + } + } + + public string CabinetName + { + get + { + return this.ArchiveName; + } + } + + public int CabinetFolderNumber + { + get + { + if (this.cabFolder < 0) + this.Refresh(); + return this.cabFolder; + } + } + + protected override void Refresh(ArchiveFileInfo newFileInfo) + { + base.Refresh(newFileInfo); + this.cabFolder = ((CabFileInfo) newFileInfo).cabFolder; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabInfo.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabInfo.cs new file mode 100644 index 00000000..735d6a46 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabInfo.cs @@ -0,0 +1,49 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabInfo +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Microsoft.Deployment.Compression.Cab +{ + [Serializable] + public class CabInfo : ArchiveInfo + { + public CabInfo(string path) + : base(path) + { + } + + protected CabInfo(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + protected override CompressionEngine CreateCompressionEngine() + { + return (CompressionEngine) new CabEngine(); + } + + public IList GetFiles() + { + IList files = base.GetFiles(); + List cabFileInfoList = new List(files.Count); + foreach (CabFileInfo cabFileInfo in (IEnumerable) files) + cabFileInfoList.Add(cabFileInfo); + return (IList) cabFileInfoList.AsReadOnly(); + } + + public IList GetFiles(string searchPattern) + { + IList files = base.GetFiles(searchPattern); + List cabFileInfoList = new List(files.Count); + foreach (CabFileInfo cabFileInfo in (IEnumerable) files) + cabFileInfoList.Add(cabFileInfo); + return (IList) cabFileInfoList.AsReadOnly(); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabPacker.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabPacker.cs new file mode 100644 index 00000000..738c5723 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabPacker.cs @@ -0,0 +1,489 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabPacker +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Text; + +namespace Microsoft.Deployment.Compression.Cab +{ + internal class CabPacker : CabWorker + { + private const string TempStreamName = "%%TEMP%%"; + private NativeMethods.FCI.Handle fciHandle; + private NativeMethods.FCI.PFNALLOC fciAllocMemHandler; + private NativeMethods.FCI.PFNFREE fciFreeMemHandler; + private NativeMethods.FCI.PFNOPEN fciOpenStreamHandler; + private NativeMethods.FCI.PFNREAD fciReadStreamHandler; + private NativeMethods.FCI.PFNWRITE fciWriteStreamHandler; + private NativeMethods.FCI.PFNCLOSE fciCloseStreamHandler; + private NativeMethods.FCI.PFNSEEK fciSeekStreamHandler; + private NativeMethods.FCI.PFNFILEPLACED fciFilePlacedHandler; + private NativeMethods.FCI.PFNDELETE fciDeleteFileHandler; + private NativeMethods.FCI.PFNGETTEMPFILE fciGetTempFileHandler; + private NativeMethods.FCI.PFNGETNEXTCABINET fciGetNextCabinet; + private NativeMethods.FCI.PFNSTATUS fciCreateStatus; + private NativeMethods.FCI.PFNGETOPENINFO fciGetOpenInfo; + private IPackStreamContext context; + private FileAttributes fileAttributes; + private DateTime fileLastWriteTime; + private int maxCabBytes; + private long totalFolderBytesProcessedInCurrentCab; + private CompressionLevel compressionLevel; + private bool dontUseTempFiles; + private IList tempStreams; + + public CabPacker(CabEngine cabEngine) + : base(cabEngine) + { + this.fciAllocMemHandler = new NativeMethods.FCI.PFNALLOC(((CabWorker) this).CabAllocMem); + this.fciFreeMemHandler = new NativeMethods.FCI.PFNFREE(((CabWorker) this).CabFreeMem); + this.fciOpenStreamHandler = new NativeMethods.FCI.PFNOPEN(((CabWorker) this).CabOpenStreamEx); + this.fciReadStreamHandler = new NativeMethods.FCI.PFNREAD(((CabWorker) this).CabReadStreamEx); + this.fciWriteStreamHandler = new NativeMethods.FCI.PFNWRITE(((CabWorker) this).CabWriteStreamEx); + this.fciCloseStreamHandler = new NativeMethods.FCI.PFNCLOSE(((CabWorker) this).CabCloseStreamEx); + this.fciSeekStreamHandler = new NativeMethods.FCI.PFNSEEK(((CabWorker) this).CabSeekStreamEx); + this.fciFilePlacedHandler = new NativeMethods.FCI.PFNFILEPLACED(this.CabFilePlaced); + this.fciDeleteFileHandler = new NativeMethods.FCI.PFNDELETE(this.CabDeleteFile); + this.fciGetTempFileHandler = new NativeMethods.FCI.PFNGETTEMPFILE(this.CabGetTempFile); + this.fciGetNextCabinet = new NativeMethods.FCI.PFNGETNEXTCABINET(this.CabGetNextCabinet); + this.fciCreateStatus = new NativeMethods.FCI.PFNSTATUS(this.CabCreateStatus); + this.fciGetOpenInfo = new NativeMethods.FCI.PFNGETOPENINFO(this.CabGetOpenInfo); + this.tempStreams = (IList) new List(); + this.compressionLevel = CompressionLevel.Normal; + } + + public bool UseTempFiles + { + get + { + return !this.dontUseTempFiles; + } + set + { + this.dontUseTempFiles = !value; + } + } + + public CompressionLevel CompressionLevel + { + get + { + return this.compressionLevel; + } + set + { + this.compressionLevel = value; + } + } + + private void CreateFci(long maxArchiveSize) + { + NativeMethods.FCI.CCAB pccab = new NativeMethods.FCI.CCAB(); + if (maxArchiveSize > 0L && maxArchiveSize < (long) pccab.cb) + pccab.cb = Math.Max(32768, checked ((int) maxArchiveSize)); + object option = this.context.GetOption("maxFolderSize", (object[]) null); + if (option != null) + { + long int64 = Convert.ToInt64(option, (IFormatProvider) CultureInfo.InvariantCulture); + if (int64 > 0L && int64 < (long) pccab.cbFolderThresh) + pccab.cbFolderThresh = checked ((int) int64); + } + this.maxCabBytes = pccab.cb; + pccab.szCab = this.context.GetArchiveName(0); + if (pccab.szCab == null) + throw new FileNotFoundException("Cabinet name not provided by stream context."); + pccab.setID = checked ((short) new Random().Next((int) short.MinValue, 32768)); + this.CabNumbers[pccab.szCab] = (short) 0; + this.currentArchiveName = pccab.szCab; + this.totalArchives = (short) 1; + this.CabStream = (Stream) null; + this.Erf.Clear(); + this.fciHandle = NativeMethods.FCI.Create(this.ErfHandle.AddrOfPinnedObject(), this.fciFilePlacedHandler, this.fciAllocMemHandler, this.fciFreeMemHandler, this.fciOpenStreamHandler, this.fciReadStreamHandler, this.fciWriteStreamHandler, this.fciCloseStreamHandler, this.fciSeekStreamHandler, this.fciDeleteFileHandler, this.fciGetTempFileHandler, pccab, IntPtr.Zero); + this.CheckError(false); + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + public void Pack( + IPackStreamContext streamContext, + IEnumerable files, + long maxArchiveSize) + { + if (streamContext == null) + throw new ArgumentNullException(nameof (streamContext)); + if (files == null) + throw new ArgumentNullException(nameof (files)); + lock (this) + { + try + { + this.context = streamContext; + this.ResetProgressData(); + this.CreateFci(maxArchiveSize); + foreach (string file in files) + { + FileAttributes attributes; + DateTime lastWriteTime; + Stream stream = this.context.OpenFileReadStream(file, out attributes, out lastWriteTime); + if (stream != null) + { + checked { this.totalFileBytes += stream.Length; } + checked { ++this.totalFiles; } + this.context.CloseFileReadStream(file, stream); + } + } + long num = 0; + this.currentFileNumber = -1; + foreach (string file in files) + { + FileAttributes attributes; + DateTime lastWriteTime; + Stream stream = this.context.OpenFileReadStream(file, out attributes, out lastWriteTime); + if (stream != null) + { + if (stream.Length >= 2147450880L) + throw new NotSupportedException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "File {0} exceeds maximum file size for cabinet format.", (object) file)); + if (num > 0L) + { + bool flag = checked (num + stream.Length) >= 2147450880L; + if (!flag) + flag = Convert.ToBoolean(streamContext.GetOption("nextFolder", new object[2] + { + (object) file, + (object) this.currentFolderNumber + }), (IFormatProvider) CultureInfo.InvariantCulture); + if (flag) + { + this.FlushFolder(); + num = 0L; + } + } + if (this.currentFolderTotalBytes > 0L) + { + this.currentFolderTotalBytes = 0L; + checked { ++this.currentFolderNumber; } + num = 0L; + } + this.currentFileName = file; + checked { ++this.currentFileNumber; } + this.currentFileTotalBytes = stream.Length; + this.currentFileBytesProcessed = 0L; + this.OnProgress(ArchiveProgressType.StartFile); + checked { num += stream.Length; } + this.AddFile(file, stream, attributes, lastWriteTime, false, this.CompressionLevel); + } + } + this.FlushFolder(); + this.FlushCabinet(); + } + finally + { + if (this.CabStream != null) + { + this.context.CloseArchiveWriteStream((int) this.currentArchiveNumber, this.currentArchiveName, this.CabStream); + this.CabStream = (Stream) null; + } + if (this.FileStream != null) + { + this.context.CloseFileReadStream(this.currentFileName, this.FileStream); + this.FileStream = (Stream) null; + } + this.context = (IPackStreamContext) null; + if (this.fciHandle != null) + { + this.fciHandle.Dispose(); + this.fciHandle = (NativeMethods.FCI.Handle) null; + } + } + } + } + + internal override int CabOpenStreamEx( + string path, + int openFlags, + int shareMode, + out int err, + IntPtr pv) + { + if (this.CabNumbers.ContainsKey(path)) + { + if (this.CabStream == null) + { + short cabNumber = this.CabNumbers[path]; + this.currentFolderTotalBytes = 0L; + Stream stream = this.context.OpenArchiveWriteStream((int) cabNumber, path, true, (CompressionEngine) this.CabEngine); + if (stream == null) + throw new FileNotFoundException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Cabinet {0} not provided.", (object) cabNumber)); + this.currentArchiveName = path; + this.currentArchiveTotalBytes = Math.Min(this.totalFolderBytesProcessedInCurrentCab, (long) this.maxCabBytes); + this.currentArchiveBytesProcessed = 0L; + this.OnProgress(ArchiveProgressType.StartArchive); + this.CabStream = stream; + } + path = "%%CAB%%"; + } + else + { + if (path == "%%TEMP%%") + { + Stream stream = (Stream) new MemoryStream(); + this.tempStreams.Add(stream); + int num = this.StreamHandles.AllocHandle(stream); + err = 0; + return num; + } + if (path != "%%CAB%%") + { + path = Path.Combine(Path.GetTempPath(), path); + Stream source = (Stream) new FileStream(path, FileMode.Open, FileAccess.ReadWrite); + this.tempStreams.Add(source); + int num = this.StreamHandles.AllocHandle((Stream) new DuplicateStream(source)); + err = 0; + return num; + } + } + return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv); + } + + internal override int CabWriteStreamEx( + int streamHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv) + { + int num = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv); + if (num <= 0 || err != 0 || DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]) != DuplicateStream.OriginalStream(this.CabStream)) + return num; + checked { this.currentArchiveBytesProcessed += (long) cb; } + if (this.currentArchiveBytesProcessed <= this.currentArchiveTotalBytes) + return num; + this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes; + return num; + } + + internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv) + { + Stream stream = DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]); + if (stream == DuplicateStream.OriginalStream(this.FileStream)) + { + this.context.CloseFileReadStream(this.currentFileName, stream); + this.FileStream = (Stream) null; + long num = checked (this.currentFileTotalBytes - this.currentFileBytesProcessed); + checked { this.currentFileBytesProcessed += num; } + checked { this.fileBytesProcessed += num; } + this.OnProgress(ArchiveProgressType.FinishFile); + this.currentFileTotalBytes = 0L; + this.currentFileBytesProcessed = 0L; + this.currentFileName = (string) null; + } + else if (stream == DuplicateStream.OriginalStream(this.CabStream)) + { + if (stream.CanWrite) + stream.Flush(); + this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes; + this.OnProgress(ArchiveProgressType.FinishArchive); + checked { ++this.currentArchiveNumber; } + checked { ++this.totalArchives; } + this.context.CloseArchiveWriteStream((int) this.currentArchiveNumber, this.currentArchiveName, stream); + this.currentArchiveName = this.NextCabinetName; + this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes = 0L; + this.totalFolderBytesProcessedInCurrentCab = 0L; + this.CabStream = (Stream) null; + } + else + { + stream.Close(); + this.tempStreams.Remove(stream); + } + return base.CabCloseStreamEx(streamHandle, out err, pv); + } + + protected override void Dispose(bool disposing) + { + try + { + if (!disposing || this.fciHandle == null) + return; + this.fciHandle.Dispose(); + this.fciHandle = (NativeMethods.FCI.Handle) null; + } + finally + { + base.Dispose(disposing); + } + } + + private static NativeMethods.FCI.TCOMP GetCompressionType( + CompressionLevel compLevel) + { + if (compLevel < CompressionLevel.Min) + return NativeMethods.FCI.TCOMP.TYPE_NONE; + if (compLevel > CompressionLevel.Max) + compLevel = CompressionLevel.Max; + return (NativeMethods.FCI.TCOMP) checked ((ushort) (3 | 3840 + (unchecked (checked (6 * (int) unchecked (compLevel - 1)) / 9) << 8))); + } + + private void AddFile( + string name, + Stream stream, + FileAttributes attributes, + DateTime lastWriteTime, + bool execute, + CompressionLevel compLevel) + { + this.FileStream = stream; + this.fileAttributes = attributes & (FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System | FileAttributes.Archive); + this.fileLastWriteTime = lastWriteTime; + this.currentFileName = name; + NativeMethods.FCI.TCOMP compressionType = CabPacker.GetCompressionType(compLevel); + IntPtr num = IntPtr.Zero; + try + { + Encoding encoding = Encoding.ASCII; + if (Encoding.UTF8.GetByteCount(name) > name.Length) + { + encoding = Encoding.UTF8; + this.fileAttributes |= FileAttributes.Normal; + } + byte[] bytes = encoding.GetBytes(name); + num = Marshal.AllocHGlobal(checked (bytes.Length + 1)); + Marshal.Copy(bytes, 0, num, bytes.Length); + Marshal.WriteByte(num, bytes.Length, (byte) 0); + this.Erf.Clear(); + NativeMethods.FCI.AddFile(this.fciHandle, string.Empty, num, execute, this.fciGetNextCabinet, this.fciCreateStatus, this.fciGetOpenInfo, compressionType); + } + finally + { + if (num != IntPtr.Zero) + Marshal.FreeHGlobal(num); + } + this.CheckError(false); + this.FileStream = (Stream) null; + this.currentFileName = (string) null; + } + + private void FlushFolder() + { + this.Erf.Clear(); + NativeMethods.FCI.FlushFolder(this.fciHandle, this.fciGetNextCabinet, this.fciCreateStatus); + this.CheckError(false); + } + + private void FlushCabinet() + { + this.Erf.Clear(); + NativeMethods.FCI.FlushCabinet(this.fciHandle, false, this.fciGetNextCabinet, this.fciCreateStatus); + this.CheckError(false); + } + + private int CabGetOpenInfo( + string path, + out short date, + out short time, + out short attribs, + out int err, + IntPtr pv) + { + CompressionEngine.DateTimeToDosDateAndTime(this.fileLastWriteTime, out date, out time); + attribs = checked ((short) this.fileAttributes); + Stream fileStream = this.FileStream; + this.FileStream = (Stream) new DuplicateStream(fileStream); + int num = this.StreamHandles.AllocHandle(fileStream); + err = 0; + return num; + } + + private int CabFilePlaced( + IntPtr pccab, + string filePath, + long fileSize, + int continuation, + IntPtr pv) + { + return 0; + } + + private int CabGetNextCabinet(IntPtr pccab, uint prevCabSize, IntPtr pv) + { + NativeMethods.FCI.CCAB ccab = new NativeMethods.FCI.CCAB(); + Marshal.PtrToStructure(pccab, (object) ccab); + ccab.szDisk = string.Empty; + ccab.szCab = this.context.GetArchiveName(ccab.iCab); + this.CabNumbers[ccab.szCab] = checked ((short) ccab.iCab); + this.NextCabinetName = ccab.szCab; + Marshal.StructureToPtr((object) ccab, pccab, false); + return 1; + } + + private int CabCreateStatus( + NativeMethods.FCI.STATUS typeStatus, + uint cb1, + uint cb2, + IntPtr pv) + { + switch (typeStatus) + { + case NativeMethods.FCI.STATUS.FILE: + if (cb2 > 0U && this.currentFileBytesProcessed < this.currentFileTotalBytes) + { + if (checked (this.currentFileBytesProcessed + (long) cb2) > this.currentFileTotalBytes) + cb2 = checked ((uint) this.currentFileTotalBytes - (uint) this.currentFileBytesProcessed); + checked { this.currentFileBytesProcessed += (long) cb2; } + checked { this.fileBytesProcessed += (long) cb2; } + this.OnProgress(ArchiveProgressType.PartialFile); + break; + } + break; + case NativeMethods.FCI.STATUS.FOLDER: + if (cb1 == 0U) + { + this.currentFolderTotalBytes = checked ((long) cb2 - this.totalFolderBytesProcessedInCurrentCab); + this.totalFolderBytesProcessedInCurrentCab = (long) cb2; + break; + } + if (this.currentFolderTotalBytes == 0L) + { + this.OnProgress(ArchiveProgressType.PartialArchive); + break; + } + break; + } + return 0; + } + + private int CabGetTempFile(IntPtr tempNamePtr, int tempNameSize, IntPtr pv) + { + byte[] bytes = Encoding.ASCII.GetBytes(!this.UseTempFiles ? "%%TEMP%%" : Path.GetFileName(Path.GetTempFileName())); + if (bytes.Length >= tempNameSize) + return -1; + Marshal.Copy(bytes, 0, tempNamePtr, bytes.Length); + Marshal.WriteByte(tempNamePtr, bytes.Length, (byte) 0); + return 1; + } + + private int CabDeleteFile(string path, out int err, IntPtr pv) + { + try + { + if (path != "%%TEMP%%") + { + path = Path.Combine(Path.GetTempPath(), path); + File.Delete(path); + } + } + catch (IOException ex) + { + } + err = 0; + return 1; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabUnpacker.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabUnpacker.cs new file mode 100644 index 00000000..a4224720 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabUnpacker.cs @@ -0,0 +1,415 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabUnpacker +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Text; + +namespace Microsoft.Deployment.Compression.Cab +{ + internal class CabUnpacker : CabWorker + { + private NativeMethods.FDI.Handle fdiHandle; + private NativeMethods.FDI.PFNALLOC fdiAllocMemHandler; + private NativeMethods.FDI.PFNFREE fdiFreeMemHandler; + private NativeMethods.FDI.PFNOPEN fdiOpenStreamHandler; + private NativeMethods.FDI.PFNREAD fdiReadStreamHandler; + private NativeMethods.FDI.PFNWRITE fdiWriteStreamHandler; + private NativeMethods.FDI.PFNCLOSE fdiCloseStreamHandler; + private NativeMethods.FDI.PFNSEEK fdiSeekStreamHandler; + private IUnpackStreamContext context; + private List fileList; + private int folderId; + private Predicate filter; + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + public CabUnpacker(CabEngine cabEngine) + : base(cabEngine) + { + this.fdiAllocMemHandler = new NativeMethods.FDI.PFNALLOC(((CabWorker) this).CabAllocMem); + this.fdiFreeMemHandler = new NativeMethods.FDI.PFNFREE(((CabWorker) this).CabFreeMem); + this.fdiOpenStreamHandler = new NativeMethods.FDI.PFNOPEN(((CabWorker) this).CabOpenStream); + this.fdiReadStreamHandler = new NativeMethods.FDI.PFNREAD(((CabWorker) this).CabReadStream); + this.fdiWriteStreamHandler = new NativeMethods.FDI.PFNWRITE(((CabWorker) this).CabWriteStream); + this.fdiCloseStreamHandler = new NativeMethods.FDI.PFNCLOSE(((CabWorker) this).CabCloseStream); + this.fdiSeekStreamHandler = new NativeMethods.FDI.PFNSEEK(((CabWorker) this).CabSeekStream); + this.fdiHandle = NativeMethods.FDI.Create(this.fdiAllocMemHandler, this.fdiFreeMemHandler, this.fdiOpenStreamHandler, this.fdiReadStreamHandler, this.fdiWriteStreamHandler, this.fdiCloseStreamHandler, this.fdiSeekStreamHandler, 1, this.ErfHandle.AddrOfPinnedObject()); + if (this.Erf.Error) + { + int oper = this.Erf.Oper; + int type = this.Erf.Type; + this.ErfHandle.Free(); + throw new CabException(oper, type, CabException.GetErrorMessage(oper, type, true)); + } + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + public bool IsArchive(Stream stream) + { + if (stream == null) + throw new ArgumentNullException(nameof (stream)); + lock (this) + { + short id; + int cabFolderCount; + int fileCount; + return this.IsCabinet(stream, out id, out cabFolderCount, out fileCount); + } + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + public IList GetFileInfo( + IUnpackStreamContext streamContext, + Predicate fileFilter) + { + if (streamContext == null) + throw new ArgumentNullException(nameof (streamContext)); + lock (this) + { + this.context = streamContext; + this.filter = fileFilter; + this.NextCabinetName = string.Empty; + this.fileList = new List(); + bool suppressProgressEvents = this.SuppressProgressEvents; + this.SuppressProgressEvents = true; + try + { + short num = 0; + while (this.NextCabinetName != null) + { + this.Erf.Clear(); + this.CabNumbers[this.NextCabinetName] = num; + NativeMethods.FDI.Copy(this.fdiHandle, this.NextCabinetName, string.Empty, 0, new NativeMethods.FDI.PFNNOTIFY(this.CabListNotify), IntPtr.Zero, IntPtr.Zero); + this.CheckError(true); + checked { ++num; } + } + List fileList = this.fileList; + this.fileList = (List) null; + return (IList) fileList.AsReadOnly(); + } + finally + { + this.SuppressProgressEvents = suppressProgressEvents; + if (this.CabStream != null) + { + this.context.CloseArchiveReadStream((int) this.currentArchiveNumber, this.currentArchiveName, this.CabStream); + this.CabStream = (Stream) null; + } + this.context = (IUnpackStreamContext) null; + } + } + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + public void Unpack(IUnpackStreamContext streamContext, Predicate fileFilter) + { + lock (this) + { + IList fileInfo = this.GetFileInfo(streamContext, fileFilter); + this.ResetProgressData(); + if (fileInfo != null) + { + this.totalFiles = fileInfo.Count; + int index = 0; + while (index < fileInfo.Count) + { + checked { this.totalFileBytes += fileInfo[index].Length; } + if (fileInfo[index].ArchiveNumber >= (int) this.totalArchives) + this.totalArchives = checked ((short) (fileInfo[index].ArchiveNumber + 1)); + checked { ++index; } + } + } + this.context = streamContext; + this.fileList = (List) null; + this.NextCabinetName = string.Empty; + this.folderId = -1; + this.currentFileNumber = -1; + try + { + short num = 0; + while (this.NextCabinetName != null) + { + this.Erf.Clear(); + this.CabNumbers[this.NextCabinetName] = num; + NativeMethods.FDI.Copy(this.fdiHandle, this.NextCabinetName, string.Empty, 0, new NativeMethods.FDI.PFNNOTIFY(this.CabExtractNotify), IntPtr.Zero, IntPtr.Zero); + this.CheckError(true); + checked { ++num; } + } + } + finally + { + if (this.CabStream != null) + { + this.context.CloseArchiveReadStream((int) this.currentArchiveNumber, this.currentArchiveName, this.CabStream); + this.CabStream = (Stream) null; + } + if (this.FileStream != null) + { + this.context.CloseFileWriteStream(this.currentFileName, this.FileStream, FileAttributes.Normal, DateTime.Now); + this.FileStream = (Stream) null; + } + this.context = (IUnpackStreamContext) null; + } + } + } + + internal override int CabOpenStreamEx( + string path, + int openFlags, + int shareMode, + out int err, + IntPtr pv) + { + if (this.CabNumbers.ContainsKey(path)) + { + if (this.CabStream == null) + { + short cabNumber = this.CabNumbers[path]; + Stream stream = this.context.OpenArchiveReadStream((int) cabNumber, path, (CompressionEngine) this.CabEngine); + if (stream == null) + throw new FileNotFoundException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Cabinet {0} not provided.", (object) cabNumber)); + this.currentArchiveName = path; + this.currentArchiveNumber = cabNumber; + if ((int) this.totalArchives <= (int) this.currentArchiveNumber) + this.totalArchives = checked ((short) ((int) this.currentArchiveNumber + 1)); + this.currentArchiveTotalBytes = stream.Length; + this.currentArchiveBytesProcessed = 0L; + if (this.folderId != -3) + this.OnProgress(ArchiveProgressType.StartArchive); + this.CabStream = stream; + } + path = "%%CAB%%"; + } + return base.CabOpenStreamEx(path, openFlags, shareMode, out err, pv); + } + + internal override int CabReadStreamEx( + int streamHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv) + { + int num = base.CabReadStreamEx(streamHandle, memory, cb, out err, pv); + if (err != 0 || this.CabStream == null || (this.fileList != null || DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]) != DuplicateStream.OriginalStream(this.CabStream))) + return num; + checked { this.currentArchiveBytesProcessed += (long) cb; } + if (this.currentArchiveBytesProcessed <= this.currentArchiveTotalBytes) + return num; + this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes; + return num; + } + + internal override int CabWriteStreamEx( + int streamHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv) + { + int num = base.CabWriteStreamEx(streamHandle, memory, cb, out err, pv); + if (num <= 0 || err != 0) + return num; + checked { this.currentFileBytesProcessed += (long) cb; } + checked { this.fileBytesProcessed += (long) cb; } + this.OnProgress(ArchiveProgressType.PartialFile); + return num; + } + + internal override int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv) + { + Stream stream = DuplicateStream.OriginalStream(this.StreamHandles[streamHandle]); + if (stream == DuplicateStream.OriginalStream(this.CabStream)) + { + if (this.folderId != -3) + this.OnProgress(ArchiveProgressType.FinishArchive); + this.context.CloseArchiveReadStream((int) this.currentArchiveNumber, this.currentArchiveName, stream); + this.currentArchiveName = this.NextCabinetName; + this.currentArchiveBytesProcessed = this.currentArchiveTotalBytes = 0L; + this.CabStream = (Stream) null; + } + return base.CabCloseStreamEx(streamHandle, out err, pv); + } + + protected override void Dispose(bool disposing) + { + try + { + if (!disposing || this.fdiHandle == null) + return; + this.fdiHandle.Dispose(); + this.fdiHandle = (NativeMethods.FDI.Handle) null; + } + finally + { + base.Dispose(disposing); + } + } + + private static string GetFileName(NativeMethods.FDI.NOTIFICATION notification) + { + Encoding encoding = ((uint) notification.attribs & 128U) > 0U ? Encoding.UTF8 : Encoding.Default; + int length = 0; + while (Marshal.ReadByte(notification.psz1, length) != (byte) 0) + checked { ++length; } + byte[] numArray = new byte[length]; + Marshal.Copy(notification.psz1, numArray, 0, length); + string path = encoding.GetString(numArray); + if (Path.IsPathRooted(path)) + path = path.Replace(Path.VolumeSeparatorChar.ToString() ?? "", ""); + return path; + } + + private bool IsCabinet( + Stream cabStream, + out short id, + out int cabFolderCount, + out int fileCount) + { + int num = this.StreamHandles.AllocHandle(cabStream); + try + { + this.Erf.Clear(); + NativeMethods.FDI.CABINFO pfdici; + bool flag = (uint) NativeMethods.FDI.IsCabinet(this.fdiHandle, num, out pfdici) > 0U; + if (this.Erf.Error) + { + if (this.Erf.Oper != 3) + throw new CabException(this.Erf.Oper, this.Erf.Type, CabException.GetErrorMessage(this.Erf.Oper, this.Erf.Type, true)); + flag = false; + } + id = pfdici.setID; + cabFolderCount = (int) pfdici.cFolders; + fileCount = (int) pfdici.cFiles; + return flag; + } + finally + { + this.StreamHandles.FreeHandle(num); + } + } + + private int CabListNotify( + NativeMethods.FDI.NOTIFICATIONTYPE notificationType, + NativeMethods.FDI.NOTIFICATION notification) + { + switch (notificationType) + { + case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO: + string stringAnsi = Marshal.PtrToStringAnsi(notification.psz1); + this.NextCabinetName = stringAnsi.Length != 0 ? stringAnsi : (string) null; + return 0; + case NativeMethods.FDI.NOTIFICATIONTYPE.PARTIAL_FILE: + return 0; + case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE: + string fileName = CabUnpacker.GetFileName(notification); + if ((this.filter == null || this.filter(fileName)) && this.fileList != null) + { + FileAttributes attributes = (FileAttributes) ((int) notification.attribs & 39); + if (attributes == (FileAttributes) 0) + attributes = FileAttributes.Normal; + DateTime dateTime; + CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out dateTime); + long cb = (long) notification.cb; + this.fileList.Add((ArchiveFileInfo) new CabFileInfo(fileName, (int) notification.iFolder, (int) notification.iCabinet, attributes, dateTime, cb)); + this.currentFileNumber = checked (this.fileList.Count - 1); + checked { this.fileBytesProcessed += (long) notification.cb; } + } + checked { ++this.totalFiles; } + checked { this.totalFileBytes += (long) notification.cb; } + return 0; + default: + return 0; + } + } + + private int CabExtractNotify( + NativeMethods.FDI.NOTIFICATIONTYPE notificationType, + NativeMethods.FDI.NOTIFICATION notification) + { + switch (notificationType) + { + case NativeMethods.FDI.NOTIFICATIONTYPE.CABINET_INFO: + if (this.NextCabinetName != null && this.NextCabinetName.StartsWith("?", StringComparison.Ordinal)) + { + this.NextCabinetName = this.NextCabinetName.Substring(1); + } + else + { + string stringAnsi = Marshal.PtrToStringAnsi(notification.psz1); + this.NextCabinetName = stringAnsi.Length != 0 ? stringAnsi : (string) null; + } + return 0; + case NativeMethods.FDI.NOTIFICATIONTYPE.COPY_FILE: + return this.CabExtractCopyFile(notification); + case NativeMethods.FDI.NOTIFICATIONTYPE.CLOSE_FILE_INFO: + return this.CabExtractCloseFile(notification); + case NativeMethods.FDI.NOTIFICATIONTYPE.NEXT_CABINET: + this.CabNumbers[Marshal.PtrToStringAnsi(notification.psz1)] = notification.iCabinet; + this.NextCabinetName = "?" + this.NextCabinetName; + return 0; + default: + return 0; + } + } + + private int CabExtractCopyFile(NativeMethods.FDI.NOTIFICATION notification) + { + if ((int) notification.iFolder != this.folderId) + { + if (notification.iFolder != (short) -3 && this.folderId != -1) + checked { ++this.currentFolderNumber; } + this.folderId = (int) notification.iFolder; + } + string fileName = CabUnpacker.GetFileName(notification); + if (this.filter == null || this.filter(fileName)) + { + checked { ++this.currentFileNumber; } + this.currentFileName = fileName; + this.currentFileBytesProcessed = 0L; + this.currentFileTotalBytes = (long) notification.cb; + this.OnProgress(ArchiveProgressType.StartFile); + DateTime dateTime; + CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out dateTime); + Stream stream = this.context.OpenFileWriteStream(fileName, (long) notification.cb, dateTime); + if (stream != null) + { + this.FileStream = stream; + return this.StreamHandles.AllocHandle(stream); + } + checked { this.fileBytesProcessed += (long) notification.cb; } + this.OnProgress(ArchiveProgressType.FinishFile); + this.currentFileName = (string) null; + } + return 0; + } + + private int CabExtractCloseFile(NativeMethods.FDI.NOTIFICATION notification) + { + Stream streamHandle = this.StreamHandles[notification.hf]; + this.StreamHandles.FreeHandle(notification.hf); + string fileName = CabUnpacker.GetFileName(notification); + FileAttributes attributes = (FileAttributes) ((int) notification.attribs & 39); + if (attributes == (FileAttributes) 0) + attributes = FileAttributes.Normal; + DateTime dateTime; + CompressionEngine.DosDateAndTimeToDateTime(notification.date, notification.time, out dateTime); + streamHandle.Flush(); + this.context.CloseFileWriteStream(fileName, streamHandle, attributes, dateTime); + this.FileStream = (Stream) null; + long num = checked (this.currentFileTotalBytes - this.currentFileBytesProcessed); + checked { this.currentFileBytesProcessed += num; } + checked { this.fileBytesProcessed += num; } + this.OnProgress(ArchiveProgressType.FinishFile); + this.currentFileName = (string) null; + return 1; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabWorker.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabWorker.cs new file mode 100644 index 00000000..4513f370 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/CabWorker.cs @@ -0,0 +1,314 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.CabWorker +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; + +namespace Microsoft.Deployment.Compression.Cab +{ + internal abstract class CabWorker : IDisposable + { + internal const string CabStreamName = "%%CAB%%"; + private CabEngine cabEngine; + private HandleManager streamHandles; + private Stream cabStream; + private Stream fileStream; + private NativeMethods.ERF erf; + private GCHandle erfHandle; + private IDictionary cabNumbers; + private string nextCabinetName; + private bool suppressProgressEvents; + private byte[] buf; + protected string currentFileName; + protected int currentFileNumber; + protected int totalFiles; + protected long currentFileBytesProcessed; + protected long currentFileTotalBytes; + protected short currentFolderNumber; + protected long currentFolderTotalBytes; + protected string currentArchiveName; + protected short currentArchiveNumber; + protected short totalArchives; + protected long currentArchiveBytesProcessed; + protected long currentArchiveTotalBytes; + protected long fileBytesProcessed; + protected long totalFileBytes; + + protected CabWorker(CabEngine cabEngine) + { + this.cabEngine = cabEngine; + this.streamHandles = new HandleManager(); + this.erf = new NativeMethods.ERF(); + this.erfHandle = GCHandle.Alloc((object) this.erf, GCHandleType.Pinned); + this.cabNumbers = (IDictionary) new Dictionary(1); + this.buf = new byte[32768]; + } + + ~CabWorker() + { + this.Dispose(false); + } + + public CabEngine CabEngine + { + get + { + return this.cabEngine; + } + } + + internal NativeMethods.ERF Erf + { + get + { + return this.erf; + } + } + + internal GCHandle ErfHandle + { + get + { + return this.erfHandle; + } + } + + internal HandleManager StreamHandles + { + get + { + return this.streamHandles; + } + } + + internal bool SuppressProgressEvents + { + get + { + return this.suppressProgressEvents; + } + set + { + this.suppressProgressEvents = value; + } + } + + internal IDictionary CabNumbers + { + get + { + return this.cabNumbers; + } + } + + internal string NextCabinetName + { + get + { + return this.nextCabinetName; + } + set + { + this.nextCabinetName = value; + } + } + + internal Stream CabStream + { + get + { + return this.cabStream; + } + set + { + this.cabStream = value; + } + } + + internal Stream FileStream + { + get + { + return this.fileStream; + } + set + { + this.fileStream = value; + } + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize((object) this); + } + + protected void ResetProgressData() + { + this.currentFileName = (string) null; + this.currentFileNumber = 0; + this.totalFiles = 0; + this.currentFileBytesProcessed = 0L; + this.currentFileTotalBytes = 0L; + this.currentFolderNumber = (short) 0; + this.currentFolderTotalBytes = 0L; + this.currentArchiveName = (string) null; + this.currentArchiveNumber = (short) 0; + this.totalArchives = (short) 0; + this.currentArchiveBytesProcessed = 0L; + this.currentArchiveTotalBytes = 0L; + this.fileBytesProcessed = 0L; + this.totalFileBytes = 0L; + } + + protected void OnProgress(ArchiveProgressType progressType) + { + if (this.suppressProgressEvents) + return; + this.CabEngine.ReportProgress(new ArchiveProgressEventArgs(progressType, this.currentFileName, this.currentFileNumber >= 0 ? this.currentFileNumber : 0, this.totalFiles, this.currentFileBytesProcessed, this.currentFileTotalBytes, this.currentArchiveName, (int) this.currentArchiveNumber, (int) this.totalArchives, this.currentArchiveBytesProcessed, this.currentArchiveTotalBytes, this.fileBytesProcessed, this.totalFileBytes)); + } + + internal IntPtr CabAllocMem(int byteCount) + { + return Marshal.AllocHGlobal((IntPtr) byteCount); + } + + internal void CabFreeMem(IntPtr memPointer) + { + Marshal.FreeHGlobal(memPointer); + } + + internal int CabOpenStream(string path, int openFlags, int shareMode) + { + int err; + return this.CabOpenStreamEx(path, openFlags, shareMode, out err, IntPtr.Zero); + } + + internal virtual int CabOpenStreamEx( + string path, + int openFlags, + int shareMode, + out int err, + IntPtr pv) + { + path = path.Trim(); + Stream cabStream = this.cabStream; + this.cabStream = (Stream) new DuplicateStream(cabStream); + int num = this.streamHandles.AllocHandle(cabStream); + err = 0; + return num; + } + + internal int CabReadStream(int streamHandle, IntPtr memory, int cb) + { + int err; + return this.CabReadStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero); + } + + internal virtual int CabReadStreamEx( + int streamHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv) + { + Stream streamHandle1 = this.streamHandles[streamHandle]; + int length1 = cb; + if (length1 > this.buf.Length) + this.buf = new byte[length1]; + byte[] buf = this.buf; + int count = length1; + int length2 = streamHandle1.Read(buf, 0, count); + Marshal.Copy(this.buf, 0, memory, length2); + err = 0; + return length2; + } + + internal int CabWriteStream(int streamHandle, IntPtr memory, int cb) + { + int err; + return this.CabWriteStreamEx(streamHandle, memory, cb, out err, IntPtr.Zero); + } + + internal virtual int CabWriteStreamEx( + int streamHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv) + { + Stream streamHandle1 = this.streamHandles[streamHandle]; + int length = cb; + if (length > this.buf.Length) + this.buf = new byte[length]; + Marshal.Copy(memory, this.buf, 0, length); + byte[] buf = this.buf; + int count = length; + streamHandle1.Write(buf, 0, count); + err = 0; + return cb; + } + + internal int CabCloseStream(int streamHandle) + { + int err; + return this.CabCloseStreamEx(streamHandle, out err, IntPtr.Zero); + } + + internal virtual int CabCloseStreamEx(int streamHandle, out int err, IntPtr pv) + { + this.streamHandles.FreeHandle(streamHandle); + err = 0; + return 0; + } + + internal int CabSeekStream(int streamHandle, int offset, int seekOrigin) + { + int err; + return this.CabSeekStreamEx(streamHandle, offset, seekOrigin, out err, IntPtr.Zero); + } + + internal virtual int CabSeekStreamEx( + int streamHandle, + int offset, + int seekOrigin, + out int err, + IntPtr pv) + { + offset = checked ((int) this.streamHandles[streamHandle].Seek((long) offset, (SeekOrigin) seekOrigin)); + err = 0; + return offset; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (this.cabStream != null) + { + this.cabStream.Close(); + this.cabStream = (Stream) null; + } + if (this.fileStream != null) + { + this.fileStream.Close(); + this.fileStream = (Stream) null; + } + } + if (!this.erfHandle.IsAllocated) + return; + this.erfHandle.Free(); + } + + protected void CheckError(bool extracting) + { + if (this.Erf.Error) + throw new CabException(this.Erf.Oper, this.Erf.Type, CabException.GetErrorMessage(this.Erf.Oper, this.Erf.Type, extracting)); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/Errors.resx b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/Errors.resx new file mode 100644 index 00000000..f93b33cf --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/Errors.resx @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Error code: {1} + + + Could not create a temporary file. + + + Unknown compression type. + + + Could not create cabinet file. + + + Client requested abort. + + + Unknown error creating cabinet. + + + Failure opening file to be stored in cabinet. + + + Failure reading file to be stored in cabinet. + + + Could not allocate enough memory to create cabinet. + + + Failure compressing data. + + + Failure decompressing data from a cabinet file. + + + Unknown compression type in a cabinet folder. + + + Could not allocate enough memory to extract cabinet. + + + Cabinet file is corrupt. + + + Cabinet file has an unknown version number. + + + Cabinet file does not have the correct format. + + + Cabinet not found. + + + Unknown error extracting cabinet. + + + Cabinets in a set do not have the same RESERVE sizes. + + + Failure writing to target file. + + + Cabinet returned on NEXT_CABINET is incorrect. + + + Client requested abort. + + \ No newline at end of file diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/HandleManager`1.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/HandleManager`1.cs new file mode 100644 index 00000000..e1732bc6 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/HandleManager`1.cs @@ -0,0 +1,43 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.HandleManager`1 +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System.Collections.Generic; + +namespace Microsoft.Deployment.Compression.Cab +{ + internal sealed class HandleManager where T : class + { + private List handles; + + public HandleManager() + { + this.handles = new List(); + } + + public T this[int handle] + { + get + { + if (handle > 0 && handle <= this.handles.Count) + return this.handles[checked (handle - 1)]; + return default (T); + } + } + + public int AllocHandle(T obj) + { + this.handles.Add(obj); + return this.handles.Count; + } + + public void FreeHandle(int handle) + { + if (handle <= 0 || handle > this.handles.Count) + return; + this.handles[checked (handle - 1)] = default (T); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/NativeMethods.cs b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/NativeMethods.cs new file mode 100644 index 00000000..2a3a6122 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Deployment/Compression/Cab/NativeMethods.cs @@ -0,0 +1,432 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.Cab.NativeMethods +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; + +namespace Microsoft.Deployment.Compression.Cab +{ + internal static class NativeMethods + { + internal static class FCI + { + internal const int MIN_DISK = 32768; + internal const int MAX_DISK = 2147483647; + internal const int MAX_FOLDER = 2147450880; + internal const int MAX_FILENAME = 256; + internal const int MAX_CABINET_NAME = 256; + internal const int MAX_CAB_PATH = 256; + internal const int MAX_DISK_NAME = 256; + internal const int CPU_80386 = 1; + + [DllImport("cabinet.dll", EntryPoint = "FCICreate", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern NativeMethods.FCI.Handle Create( + IntPtr perf, + NativeMethods.FCI.PFNFILEPLACED pfnfcifp, + NativeMethods.FCI.PFNALLOC pfna, + NativeMethods.FCI.PFNFREE pfnf, + NativeMethods.FCI.PFNOPEN pfnopen, + NativeMethods.FCI.PFNREAD pfnread, + NativeMethods.FCI.PFNWRITE pfnwrite, + NativeMethods.FCI.PFNCLOSE pfnclose, + NativeMethods.FCI.PFNSEEK pfnseek, + NativeMethods.FCI.PFNDELETE pfndelete, + NativeMethods.FCI.PFNGETTEMPFILE pfnfcigtf, + [MarshalAs(UnmanagedType.LPStruct)] NativeMethods.FCI.CCAB pccab, + IntPtr pv); + + [DllImport("cabinet.dll", EntryPoint = "FCIAddFile", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern int AddFile( + NativeMethods.FCI.Handle hfci, + string pszSourceFile, + IntPtr pszFileName, + [MarshalAs(UnmanagedType.Bool)] bool fExecute, + NativeMethods.FCI.PFNGETNEXTCABINET pfnfcignc, + NativeMethods.FCI.PFNSTATUS pfnfcis, + NativeMethods.FCI.PFNGETOPENINFO pfnfcigoi, + NativeMethods.FCI.TCOMP typeCompress); + + [DllImport("cabinet.dll", EntryPoint = "FCIFlushCabinet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern int FlushCabinet( + NativeMethods.FCI.Handle hfci, + [MarshalAs(UnmanagedType.Bool)] bool fGetNextCab, + NativeMethods.FCI.PFNGETNEXTCABINET pfnfcignc, + NativeMethods.FCI.PFNSTATUS pfnfcis); + + [DllImport("cabinet.dll", EntryPoint = "FCIFlushFolder", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern int FlushFolder( + NativeMethods.FCI.Handle hfci, + NativeMethods.FCI.PFNGETNEXTCABINET pfnfcignc, + NativeMethods.FCI.PFNSTATUS pfnfcis); + + [SuppressUnmanagedCodeSecurity] + [DllImport("cabinet.dll", EntryPoint = "FCIDestroy", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Destroy(IntPtr hfci); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate IntPtr PFNALLOC(int cb); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void PFNFREE(IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNOPEN(string path, int oflag, int pmode, out int err, IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNREAD( + int fileHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNWRITE( + int fileHandle, + IntPtr memory, + int cb, + out int err, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNCLOSE(int fileHandle, out int err, IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNSEEK( + int fileHandle, + int dist, + int seekType, + out int err, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNDELETE(string path, out int err, IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNGETNEXTCABINET(IntPtr pccab, uint cbPrevCab, IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNFILEPLACED( + IntPtr pccab, + string path, + long fileSize, + int continuation, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNGETOPENINFO( + string path, + out short date, + out short time, + out short pattribs, + out int err, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNSTATUS( + NativeMethods.FCI.STATUS typeStatus, + uint cb1, + uint cb2, + IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNGETTEMPFILE(IntPtr tempNamePtr, int tempNameSize, IntPtr pv); + + internal enum ERROR + { + NONE, + OPEN_SRC, + READ_SRC, + ALLOC_FAIL, + TEMP_FILE, + BAD_COMPR_TYPE, + CAB_FILE, + USER_ABORT, + MCI_FAIL, + } + + internal enum TCOMP : ushort + { + TYPE_NONE = 0, + TYPE_MSZIP = 1, + TYPE_QUANTUM = 2, + TYPE_LZX = 3, + SHIFT_QUANTUM_LEVEL = 4, + SHIFT_LZX_WINDOW = 8, + SHIFT_QUANTUM_MEM = 8, + BAD = 15, // 0x000F + MASK_TYPE = 15, // 0x000F + QUANTUM_LEVEL_LO = 16, // 0x0010 + QUANTUM_LEVEL_HI = 112, // 0x0070 + MASK_QUANTUM_LEVEL = 240, // 0x00F0 + QUANTUM_MEM_LO = 2560, // 0x0A00 + LZX_WINDOW_LO = 3840, // 0x0F00 + LZX_WINDOW_HI = 5376, // 0x1500 + QUANTUM_MEM_HI = 5376, // 0x1500 + MASK_LZX_WINDOW = 7936, // 0x1F00 + MASK_QUANTUM_MEM = 7936, // 0x1F00 + MASK_RESERVED = 57344, // 0xE000 + } + + internal enum STATUS : uint + { + FILE, + FOLDER, + CABINET, + } + + [StructLayout(LayoutKind.Sequential)] + internal class CCAB + { + internal int cb = int.MaxValue; + internal int cbFolderThresh = 2147450880; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + internal string szDisk = string.Empty; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + internal string szCab = string.Empty; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + internal string szCabPath = string.Empty; + internal int cbReserveCFHeader; + internal int cbReserveCFFolder; + internal int cbReserveCFData; + internal int iCab; + internal int iDisk; + internal int fFailOnIncompressible; + internal short setID; + } + + internal class Handle : SafeHandle + { + internal Handle() + : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return NativeMethods.FCI.Destroy(this.handle); + } + } + } + + internal static class FDI + { + internal const int MAX_DISK = 2147483647; + internal const int MAX_FILENAME = 256; + internal const int MAX_CABINET_NAME = 256; + internal const int MAX_CAB_PATH = 256; + internal const int MAX_DISK_NAME = 256; + internal const int CPU_80386 = 1; + + [DllImport("cabinet.dll", EntryPoint = "FDICreate", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern NativeMethods.FDI.Handle Create( + [MarshalAs(UnmanagedType.FunctionPtr)] NativeMethods.FDI.PFNALLOC pfnalloc, + [MarshalAs(UnmanagedType.FunctionPtr)] NativeMethods.FDI.PFNFREE pfnfree, + NativeMethods.FDI.PFNOPEN pfnopen, + NativeMethods.FDI.PFNREAD pfnread, + NativeMethods.FDI.PFNWRITE pfnwrite, + NativeMethods.FDI.PFNCLOSE pfnclose, + NativeMethods.FDI.PFNSEEK pfnseek, + int cpuType, + IntPtr perf); + + [DllImport("cabinet.dll", EntryPoint = "FDICopy", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern int Copy( + NativeMethods.FDI.Handle hfdi, + string pszCabinet, + string pszCabPath, + int flags, + NativeMethods.FDI.PFNNOTIFY pfnfdin, + IntPtr pfnfdid, + IntPtr pvUser); + + [SuppressUnmanagedCodeSecurity] + [DllImport("cabinet.dll", EntryPoint = "FDIDestroy", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool Destroy(IntPtr hfdi); + + [DllImport("cabinet.dll", EntryPoint = "FDIIsCabinet", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ThrowOnUnmappableChar = true, BestFitMapping = false)] + internal static extern int IsCabinet( + NativeMethods.FDI.Handle hfdi, + int hf, + out NativeMethods.FDI.CABINFO pfdici); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate IntPtr PFNALLOC(int cb); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void PFNFREE(IntPtr pv); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNOPEN(string path, int oflag, int pmode); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNREAD(int hf, IntPtr pv, int cb); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNWRITE(int hf, IntPtr pv, int cb); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNCLOSE(int hf); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNSEEK(int hf, int dist, int seektype); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate int PFNNOTIFY( + NativeMethods.FDI.NOTIFICATIONTYPE fdint, + NativeMethods.FDI.NOTIFICATION fdin); + + internal enum ERROR + { + NONE, + CABINET_NOT_FOUND, + NOT_A_CABINET, + UNKNOWN_CABINET_VERSION, + CORRUPT_CABINET, + ALLOC_FAIL, + BAD_COMPR_TYPE, + MDI_FAIL, + TARGET_FILE, + RESERVE_MISMATCH, + WRONG_CABINET, + USER_ABORT, + } + + internal enum NOTIFICATIONTYPE + { + CABINET_INFO, + PARTIAL_FILE, + COPY_FILE, + CLOSE_FILE_INFO, + NEXT_CABINET, + ENUMERATE, + } + + internal struct CABINFO + { + internal int cbCabinet; + internal short cFolders; + internal short cFiles; + internal short setID; + internal short iCabinet; + internal int fReserve; + internal int hasprev; + internal int hasnext; + } + + [StructLayout(LayoutKind.Sequential)] + internal class NOTIFICATION + { + internal int cb; + internal IntPtr psz1; + internal IntPtr psz2; + internal IntPtr psz3; + internal IntPtr pv; + internal IntPtr hf_ptr; + internal short date; + internal short time; + internal short attribs; + internal short setID; + internal short iCabinet; + internal short iFolder; + internal int fdie; + + internal int hf + { + get + { + return (int) this.hf_ptr; + } + } + } + + internal class Handle : SafeHandle + { + internal Handle() + : base(IntPtr.Zero, true) + { + } + + public override bool IsInvalid + { + get + { + return this.handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + return NativeMethods.FDI.Destroy(this.handle); + } + } + } + + [StructLayout(LayoutKind.Sequential)] + internal class ERF + { + private int erfOper; + private int erfType; + private int fError; + + internal int Oper + { + get + { + return this.erfOper; + } + set + { + this.erfOper = value; + } + } + + internal int Type + { + get + { + return this.erfType; + } + set + { + this.erfType = value; + } + } + + internal bool Error + { + get + { + return (uint) this.fError > 0U; + } + set + { + this.fError = value ? 1 : 0; + } + } + + internal void Clear() + { + this.Oper = 0; + this.Type = 0; + this.Error = false; + } + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.Core.csproj b/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.Core.csproj new file mode 100644 index 00000000..02b63947 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.Core.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp3.1 + Microsoft.Deployment.Compression.Cab + Microsoft.Deployment.Compression.Cab + false + + + + true + ..\..\bin\Debug\ + + + + true + ..\..\bin\Release\ + + + + + + + diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.csproj b/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.csproj new file mode 100644 index 00000000..f566bbc5 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Microsoft.Deployment.Compression.Cab.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {51043B1F-2D7B-4A70-B550-32BECBA2CE9A} + Library + Microsoft.Deployment.Compression.Cab + v3.5 + 3.0.0.0 + 512 + Microsoft + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + lib\Microsoft.Deployment.Compression.dll + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Cab/Microsoft.Deployment.Compression.Cab/Tools/WindowsInstallerXml/WixDistribution.cs b/Cab/Microsoft.Deployment.Compression.Cab/Tools/WindowsInstallerXml/WixDistribution.cs new file mode 100644 index 00000000..9245769c --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression.Cab/Tools/WindowsInstallerXml/WixDistribution.cs @@ -0,0 +1,65 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Tools.WindowsInstallerXml.WixDistribution +// Assembly: Microsoft.Deployment.Compression.Cab, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: D94CEDF8-4B4A-4AC8-B27E-50F0AAABF518 +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll + +using System; +using System.Diagnostics; +using System.Reflection; + +namespace Microsoft.Tools.WindowsInstallerXml +{ + internal static class WixDistribution + { + public static string NewsUrl = "http://wixtoolset.org/news/"; + public static string ShortProduct = "WiX Toolset"; + public static string SupportUrl = "http://wixtoolset.org/"; + public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}"; + + public static string ReplacePlaceholders(string original, Assembly assembly) + { + if (assembly != null) + { + FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); + original = original.Replace("[FileComments]", versionInfo.Comments); + original = original.Replace("[FileCopyright]", versionInfo.LegalCopyright); + original = original.Replace("[FileProductName]", versionInfo.ProductName); + original = original.Replace("[FileVersion]", versionInfo.FileVersion); + if (original.Contains("[FileVersionMajorMinor]")) + { + Version version = new Version(versionInfo.FileVersion); + original = original.Replace("[FileVersionMajorMinor]", version.Major.ToString() + "." + (object) version.Minor); + } + AssemblyCompanyAttribute attribute1; + if (WixDistribution.TryGetAttribute(assembly, out attribute1)) + original = original.Replace("[AssemblyCompany]", attribute1.Company); + AssemblyCopyrightAttribute attribute2; + if (WixDistribution.TryGetAttribute(assembly, out attribute2)) + original = original.Replace("[AssemblyCopyright]", attribute2.Copyright); + AssemblyDescriptionAttribute attribute3; + if (WixDistribution.TryGetAttribute(assembly, out attribute3)) + original = original.Replace("[AssemblyDescription]", attribute3.Description); + AssemblyProductAttribute attribute4; + if (WixDistribution.TryGetAttribute(assembly, out attribute4)) + original = original.Replace("[AssemblyProduct]", attribute4.Product); + AssemblyTitleAttribute attribute5; + if (WixDistribution.TryGetAttribute(assembly, out attribute5)) + original = original.Replace("[AssemblyTitle]", attribute5.Title); + } + original = original.Replace("[NewsUrl]", WixDistribution.NewsUrl); + original = original.Replace("[ShortProduct]", WixDistribution.ShortProduct); + original = original.Replace("[SupportUrl]", WixDistribution.SupportUrl); + return original; + } + + private static bool TryGetAttribute(Assembly assembly, out T attribute) where T : Attribute + { + attribute = default (T); + object[] customAttributes = assembly.GetCustomAttributes(typeof (T), false); + if (customAttributes != null && customAttributes.Length != 0) + attribute = customAttributes[0] as T; + return (object) attribute != null; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/AssemblyInfo.cs b/Cab/Microsoft.Deployment.Compression/AssemblyInfo.cs new file mode 100644 index 00000000..7bf748ee --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; + +[assembly: AssemblyDescription("Abstract base libraries for archive packing and unpacking")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] +[assembly: AllowPartiallyTrustedCallers] +[assembly: AssemblyFileVersion("3.10.1.2213")] +[assembly: AssemblyCompany("Outercurve Foundation")] +[assembly: AssemblyCopyright("Copyright (c) Outercurve Foundation. All rights reserved.")] +[assembly: AssemblyProduct("Windows Installer XML Toolset")] +[assembly: AssemblyConfiguration("")] +[assembly: NeutralResourcesLanguage("en-US")] +[assembly: AssemblyVersion("3.0.0.0")] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Unrestricted = true)] diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveException.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveException.cs new file mode 100644 index 00000000..3f110f2e --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveException.cs @@ -0,0 +1,36 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveException +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; +using System.Runtime.Serialization; + +namespace Microsoft.Deployment.Compression +{ + [Serializable] + public class ArchiveException : IOException + { + public ArchiveException(string message, Exception innerException) + : base(message, innerException) + { + } + + public ArchiveException(string message) + : this(message, (Exception) null) + { + } + + public ArchiveException() + : this((string) null, (Exception) null) + { + } + + protected ArchiveException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileInfo.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileInfo.cs new file mode 100644 index 00000000..e1d56a48 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileInfo.cs @@ -0,0 +1,238 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveFileInfo +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Security.Permissions; + +namespace Microsoft.Deployment.Compression +{ + [Serializable] + public abstract class ArchiveFileInfo : FileSystemInfo + { + private ArchiveInfo archiveInfo; + private string name; + private string path; + private bool initialized; + private bool exists; + private int archiveNumber; + private FileAttributes attributes; + private DateTime lastWriteTime; + private long length; + + protected ArchiveFileInfo(ArchiveInfo archiveInfo, string filePath) + { + if (filePath == null) + throw new ArgumentNullException(nameof (filePath)); + this.Archive = archiveInfo; + this.name = System.IO.Path.GetFileName(filePath); + this.path = System.IO.Path.GetDirectoryName(filePath); + this.attributes = FileAttributes.Normal; + this.lastWriteTime = DateTime.MinValue; + } + + protected ArchiveFileInfo( + string filePath, + int archiveNumber, + FileAttributes attributes, + DateTime lastWriteTime, + long length) + : this((ArchiveInfo) null, filePath) + { + this.exists = true; + this.archiveNumber = archiveNumber; + this.attributes = attributes; + this.lastWriteTime = lastWriteTime; + this.length = length; + this.initialized = true; + } + + protected ArchiveFileInfo(SerializationInfo info, StreamingContext context) + : base(info, context) + { + this.archiveInfo = (ArchiveInfo) info.GetValue(nameof (archiveInfo), typeof (ArchiveInfo)); + this.name = info.GetString(nameof (name)); + this.path = info.GetString(nameof (path)); + this.initialized = info.GetBoolean(nameof (initialized)); + this.exists = info.GetBoolean(nameof (exists)); + this.archiveNumber = info.GetInt32(nameof (archiveNumber)); + this.attributes = (FileAttributes) info.GetValue(nameof (attributes), typeof (FileAttributes)); + this.lastWriteTime = info.GetDateTime(nameof (lastWriteTime)); + this.length = info.GetInt64(nameof (length)); + } + + public override string Name + { + get + { + return this.name; + } + } + + public string Path + { + get + { + return this.path; + } + } + + public override string FullName + { + get + { + string path2 = System.IO.Path.Combine(this.Path, this.Name); + if (this.Archive != null) + path2 = System.IO.Path.Combine(this.ArchiveName, path2); + return path2; + } + } + + public ArchiveInfo Archive + { + get + { + return this.archiveInfo; + } + internal set + { + this.archiveInfo = value; + this.OriginalPath = value?.FullName; + this.FullPath = this.OriginalPath; + } + } + + public string ArchiveName + { + get + { + if (this.Archive == null) + return (string) null; + return this.Archive.FullName; + } + } + + public int ArchiveNumber + { + get + { + return this.archiveNumber; + } + } + + public override bool Exists + { + get + { + if (!this.initialized) + this.Refresh(); + return this.exists; + } + } + + public long Length + { + get + { + if (!this.initialized) + this.Refresh(); + return this.length; + } + } + + public new FileAttributes Attributes + { + get + { + if (!this.initialized) + this.Refresh(); + return this.attributes; + } + } + + public new DateTime LastWriteTime + { + get + { + if (!this.initialized) + this.Refresh(); + return this.lastWriteTime; + } + } + + [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("archiveInfo", (object) this.archiveInfo); + info.AddValue("name", (object) this.name); + info.AddValue("path", (object) this.path); + info.AddValue("initialized", this.initialized); + info.AddValue("exists", this.exists); + info.AddValue("archiveNumber", this.archiveNumber); + info.AddValue("attributes", (object) this.attributes); + info.AddValue("lastWriteTime", this.lastWriteTime); + info.AddValue("length", this.length); + } + + public override string ToString() + { + return this.FullName; + } + + public override void Delete() + { + throw new NotSupportedException(); + } + + public new void Refresh() + { + base.Refresh(); + if (this.Archive == null) + return; + string str = System.IO.Path.Combine(this.Path, this.Name); + ArchiveFileInfo file = this.Archive.GetFile(str); + if (file == null) + throw new FileNotFoundException("File not found in archive.", str); + this.Refresh(file); + } + + public void CopyTo(string destFileName) + { + this.CopyTo(destFileName, false); + } + + public void CopyTo(string destFileName, bool overwrite) + { + if (destFileName == null) + throw new ArgumentNullException(nameof (destFileName)); + if (!overwrite && File.Exists(destFileName)) + throw new IOException(); + if (this.Archive == null) + throw new InvalidOperationException(); + this.Archive.UnpackFile(System.IO.Path.Combine(this.Path, this.Name), destFileName); + } + + public Stream OpenRead() + { + return this.Archive.OpenRead(System.IO.Path.Combine(this.Path, this.Name)); + } + + public StreamReader OpenText() + { + return this.Archive.OpenText(System.IO.Path.Combine(this.Path, this.Name)); + } + + protected virtual void Refresh(ArchiveFileInfo newFileInfo) + { + this.exists = newFileInfo.exists; + this.length = newFileInfo.length; + this.attributes = newFileInfo.attributes; + this.lastWriteTime = newFileInfo.lastWriteTime; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileStreamContext.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileStreamContext.cs new file mode 100644 index 00000000..76c1691b --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveFileStreamContext.cs @@ -0,0 +1,268 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveFileStreamContext +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public class ArchiveFileStreamContext : IPackStreamContext, IUnpackStreamContext + { + private IList archiveFiles; + private string directory; + private IDictionary files; + private bool extractOnlyNewerFiles; + private bool enableOffsetOpen; + + public ArchiveFileStreamContext(string archiveFile) + : this(archiveFile, (string) null, (IDictionary) null) + { + } + + public ArchiveFileStreamContext( + string archiveFile, + string directory, + IDictionary files) + : this((IList) new string[1] + { + archiveFile + }, directory, files) + { + if (archiveFile == null) + throw new ArgumentNullException(nameof (archiveFile)); + } + + public ArchiveFileStreamContext( + IList archiveFiles, + string directory, + IDictionary files) + { + if (archiveFiles == null || archiveFiles.Count == 0) + throw new ArgumentNullException(nameof (archiveFiles)); + this.archiveFiles = archiveFiles; + this.directory = directory; + this.files = files; + } + + public IList ArchiveFiles + { + get + { + return this.archiveFiles; + } + } + + public string Directory + { + get + { + return this.directory; + } + } + + public IDictionary Files + { + get + { + return this.files; + } + } + + public bool ExtractOnlyNewerFiles + { + get + { + return this.extractOnlyNewerFiles; + } + set + { + this.extractOnlyNewerFiles = value; + } + } + + public bool EnableOffsetOpen + { + get + { + return this.enableOffsetOpen; + } + set + { + this.enableOffsetOpen = value; + } + } + + public virtual string GetArchiveName(int archiveNumber) + { + if (archiveNumber < this.archiveFiles.Count) + return Path.GetFileName(this.archiveFiles[archiveNumber]); + return string.Empty; + } + + public virtual Stream OpenArchiveWriteStream( + int archiveNumber, + string archiveName, + bool truncate, + CompressionEngine compressionEngine) + { + if (archiveNumber >= this.archiveFiles.Count) + return (Stream) null; + if (string.IsNullOrEmpty(archiveName)) + throw new ArgumentNullException(nameof (archiveName)); + Stream source = (Stream) File.Open(Path.Combine(Path.GetDirectoryName(this.archiveFiles[0]), archiveName), truncate ? FileMode.OpenOrCreate : FileMode.Open, FileAccess.ReadWrite); + if (this.enableOffsetOpen) + { + long offset = compressionEngine.FindArchiveOffset((Stream) new DuplicateStream(source)); + if (offset < 0L) + offset = source.Length; + if (offset > 0L) + source = (Stream) new OffsetStream(source, offset); + source.Seek(0L, SeekOrigin.Begin); + } + if (truncate) + source.SetLength(0L); + return source; + } + + public virtual void CloseArchiveWriteStream( + int archiveNumber, + string archiveName, + Stream stream) + { + if (stream == null) + return; + stream.Close(); + FileStream fileStream = stream as FileStream; + if (fileStream == null) + return; + string name = fileStream.Name; + if (string.IsNullOrEmpty(archiveName) || !(archiveName != Path.GetFileName(name))) + return; + string str = Path.Combine(Path.GetDirectoryName(this.archiveFiles[0]), archiveName); + if (File.Exists(str)) + File.Delete(str); + File.Move(name, str); + } + + public virtual Stream OpenFileReadStream( + string path, + out FileAttributes attributes, + out DateTime lastWriteTime) + { + string path1 = this.TranslateFilePath(path); + if (path1 == null) + { + attributes = FileAttributes.Normal; + lastWriteTime = DateTime.Now; + return (Stream) null; + } + attributes = File.GetAttributes(path1); + lastWriteTime = File.GetLastWriteTime(path1); + return (Stream) File.Open(path1, FileMode.Open, FileAccess.Read, FileShare.Read); + } + + public virtual void CloseFileReadStream(string path, Stream stream) + { + stream?.Close(); + } + + public virtual object GetOption(string optionName, object[] parameters) + { + return (object) null; + } + + public virtual Stream OpenArchiveReadStream( + int archiveNumber, + string archiveName, + CompressionEngine compressionEngine) + { + if (archiveNumber >= this.archiveFiles.Count) + return (Stream) null; + Stream source = (Stream) File.Open(this.archiveFiles[archiveNumber], FileMode.Open, FileAccess.Read, FileShare.Read); + if (this.enableOffsetOpen) + { + long archiveOffset = compressionEngine.FindArchiveOffset((Stream) new DuplicateStream(source)); + if (archiveOffset > 0L) + source = (Stream) new OffsetStream(source, archiveOffset); + else + source.Seek(0L, SeekOrigin.Begin); + } + return source; + } + + public virtual void CloseArchiveReadStream( + int archiveNumber, + string archiveName, + Stream stream) + { + stream?.Close(); + } + + public virtual Stream OpenFileWriteStream( + string path, + long fileSize, + DateTime lastWriteTime) + { + string str = this.TranslateFilePath(path); + if (str == null) + return (Stream) null; + FileInfo fileInfo = new FileInfo(str); + if (fileInfo.Exists) + { + if (this.extractOnlyNewerFiles && lastWriteTime != DateTime.MinValue && fileInfo.LastWriteTime >= lastWriteTime) + return (Stream) null; + FileAttributes fileAttributes = FileAttributes.ReadOnly | FileAttributes.Hidden | FileAttributes.System; + if ((fileInfo.Attributes & fileAttributes) != (FileAttributes) 0) + fileInfo.Attributes &= ~fileAttributes; + } + if (!fileInfo.Directory.Exists) + fileInfo.Directory.Create(); + return (Stream) File.Open(str, FileMode.Create, FileAccess.Write, FileShare.None); + } + + public virtual void CloseFileWriteStream( + string path, + Stream stream, + FileAttributes attributes, + DateTime lastWriteTime) + { + stream?.Close(); + string fileName = this.TranslateFilePath(path); + if (fileName == null) + return; + FileInfo fileInfo = new FileInfo(fileName); + if (lastWriteTime != DateTime.MinValue) + { + try + { + fileInfo.LastWriteTime = lastWriteTime; + } + catch (ArgumentException ex) + { + } + catch (IOException ex) + { + } + } + try + { + fileInfo.Attributes = attributes; + } + catch (IOException ex) + { + } + } + + private string TranslateFilePath(string path) + { + string path2 = this.files == null ? path : this.files[path]; + if (path2 != null && this.directory != null) + path2 = Path.Combine(this.directory, path2); + return path2; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveInfo.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveInfo.cs new file mode 100644 index 00000000..b273e9d7 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveInfo.cs @@ -0,0 +1,375 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveInfo +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Runtime.Serialization; +using System.Text.RegularExpressions; + +namespace Microsoft.Deployment.Compression +{ + [Serializable] + public abstract class ArchiveInfo : FileSystemInfo + { + protected ArchiveInfo(string path) + { + if (path == null) + throw new ArgumentNullException(nameof (path)); + this.OriginalPath = path; + this.FullPath = Path.GetFullPath(path); + } + + protected ArchiveInfo(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + public DirectoryInfo Directory + { + get + { + return new DirectoryInfo(Path.GetDirectoryName(this.FullName)); + } + } + + public string DirectoryName + { + get + { + return Path.GetDirectoryName(this.FullName); + } + } + + public long Length + { + get + { + return new FileInfo(this.FullName).Length; + } + } + + public override string Name + { + get + { + return Path.GetFileName(this.FullName); + } + } + + public override bool Exists + { + get + { + return File.Exists(this.FullName); + } + } + + public override string ToString() + { + return this.FullName; + } + + public override void Delete() + { + File.Delete(this.FullName); + } + + public void CopyTo(string destFileName) + { + File.Copy(this.FullName, destFileName); + } + + public void CopyTo(string destFileName, bool overwrite) + { + File.Copy(this.FullName, destFileName, overwrite); + } + + public void MoveTo(string destFileName) + { + File.Move(this.FullName, destFileName); + this.FullPath = Path.GetFullPath(destFileName); + } + + public bool IsValid() + { + using (Stream stream = (Stream) File.OpenRead(this.FullName)) + { + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + return compressionEngine.FindArchiveOffset(stream) >= 0L; + } + } + + public IList GetFiles() + { + return this.InternalGetFiles((Predicate) null); + } + + public IList GetFiles(string searchPattern) + { + if (searchPattern == null) + throw new ArgumentNullException(nameof (searchPattern)); + Regex regex = new Regex(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "^{0}$", (object) Regex.Escape(searchPattern).Replace("\\*", ".*").Replace("\\?", ".")), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + return this.InternalGetFiles((Predicate) (match => regex.IsMatch(match))); + } + + public void Unpack(string destDirectory) + { + this.Unpack(destDirectory, (EventHandler) null); + } + + public void Unpack( + string destDirectory, + EventHandler progressHandler) + { + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + { + compressionEngine.Progress += progressHandler; + compressionEngine.Unpack((IUnpackStreamContext) new ArchiveFileStreamContext(this.FullName, destDirectory, (IDictionary) null) + { + EnableOffsetOpen = true + }, (Predicate) null); + } + } + + public void UnpackFile(string fileName, string destFileName) + { + if (fileName == null) + throw new ArgumentNullException(nameof (fileName)); + if (destFileName == null) + throw new ArgumentNullException(nameof (destFileName)); + this.UnpackFiles((IList) new string[1] + { + fileName + }, (string) null, (IList) new string[1] + { + destFileName + }); + } + + public void UnpackFiles( + IList fileNames, + string destDirectory, + IList destFileNames) + { + this.UnpackFiles(fileNames, destDirectory, destFileNames, (EventHandler) null); + } + + public void UnpackFiles( + IList fileNames, + string destDirectory, + IList destFileNames, + EventHandler progressHandler) + { + if (fileNames == null) + throw new ArgumentNullException(nameof (fileNames)); + if (destFileNames == null) + { + if (destDirectory == null) + throw new ArgumentNullException(nameof (destFileNames)); + destFileNames = fileNames; + } + if (destFileNames.Count != fileNames.Count) + throw new ArgumentOutOfRangeException(nameof (destFileNames)); + this.UnpackFileSet(ArchiveInfo.CreateStringDictionary(fileNames, destFileNames), destDirectory, progressHandler); + } + + public void UnpackFileSet(IDictionary fileNames, string destDirectory) + { + this.UnpackFileSet(fileNames, destDirectory, (EventHandler) null); + } + + public void UnpackFileSet( + IDictionary fileNames, + string destDirectory, + EventHandler progressHandler) + { + if (fileNames == null) + throw new ArgumentNullException(nameof (fileNames)); + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + { + compressionEngine.Progress += progressHandler; + compressionEngine.Unpack((IUnpackStreamContext) new ArchiveFileStreamContext(this.FullName, destDirectory, fileNames) + { + EnableOffsetOpen = true + }, (Predicate) (match => fileNames.ContainsKey(match))); + } + } + + public Stream OpenRead(string fileName) + { + Stream stream = (Stream) File.OpenRead(this.FullName); + CompressionEngine compressionEngine = this.CreateCompressionEngine(); + return (Stream) new CargoStream(compressionEngine.Unpack(stream, fileName), new IDisposable[2] + { + (IDisposable) stream, + (IDisposable) compressionEngine + }); + } + + public StreamReader OpenText(string fileName) + { + return new StreamReader(this.OpenRead(fileName)); + } + + public void Pack(string sourceDirectory) + { + this.Pack(sourceDirectory, false, CompressionLevel.Max, (EventHandler) null); + } + + public void Pack( + string sourceDirectory, + bool includeSubdirectories, + CompressionLevel compLevel, + EventHandler progressHandler) + { + IList pathsInDirectoryTree = this.GetRelativeFilePathsInDirectoryTree(sourceDirectory, includeSubdirectories); + string sourceDirectory1 = sourceDirectory; + IList stringList = pathsInDirectoryTree; + int num = (int) compLevel; + EventHandler progressHandler1 = progressHandler; + this.PackFiles(sourceDirectory1, stringList, stringList, (CompressionLevel) num, progressHandler1); + } + + public void PackFiles( + string sourceDirectory, + IList sourceFileNames, + IList fileNames) + { + this.PackFiles(sourceDirectory, sourceFileNames, fileNames, CompressionLevel.Max, (EventHandler) null); + } + + public void PackFiles( + string sourceDirectory, + IList sourceFileNames, + IList fileNames, + CompressionLevel compLevel, + EventHandler progressHandler) + { + if (sourceFileNames == null) + throw new ArgumentNullException(nameof (sourceFileNames)); + if (fileNames == null) + { + string[] strArray = new string[sourceFileNames.Count]; + int index = 0; + while (index < sourceFileNames.Count) + { + strArray[index] = Path.GetFileName(sourceFileNames[index]); + checked { ++index; } + } + fileNames = (IList) strArray; + } + else if (fileNames.Count != sourceFileNames.Count) + throw new ArgumentOutOfRangeException(nameof (fileNames)); + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + { + compressionEngine.Progress += progressHandler; + IDictionary stringDictionary = ArchiveInfo.CreateStringDictionary(fileNames, sourceFileNames); + ArchiveFileStreamContext fileStreamContext = new ArchiveFileStreamContext(this.FullName, sourceDirectory, stringDictionary); + fileStreamContext.EnableOffsetOpen = true; + compressionEngine.CompressionLevel = compLevel; + compressionEngine.Pack((IPackStreamContext) fileStreamContext, (IEnumerable) fileNames); + } + } + + public void PackFileSet(string sourceDirectory, IDictionary fileNames) + { + this.PackFileSet(sourceDirectory, fileNames, CompressionLevel.Max, (EventHandler) null); + } + + public void PackFileSet( + string sourceDirectory, + IDictionary fileNames, + CompressionLevel compLevel, + EventHandler progressHandler) + { + if (fileNames == null) + throw new ArgumentNullException(nameof (fileNames)); + string[] array = new string[fileNames.Count]; + fileNames.Keys.CopyTo(array, 0); + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + { + compressionEngine.Progress += progressHandler; + ArchiveFileStreamContext fileStreamContext = new ArchiveFileStreamContext(this.FullName, sourceDirectory, fileNames); + fileStreamContext.EnableOffsetOpen = true; + compressionEngine.CompressionLevel = compLevel; + compressionEngine.Pack((IPackStreamContext) fileStreamContext, (IEnumerable) array); + } + } + + internal IList GetRelativeFilePathsInDirectoryTree( + string dir, + bool includeSubdirectories) + { + IList fileList = (IList) new List(); + this.RecursiveGetRelativeFilePathsInDirectoryTree(dir, string.Empty, includeSubdirectories, fileList); + return fileList; + } + + internal ArchiveFileInfo GetFile(string path) + { + IList files = this.InternalGetFiles((Predicate) (match => string.Compare(match, path, true, CultureInfo.InvariantCulture) == 0)); + if (files == null || files.Count <= 0) + return (ArchiveFileInfo) null; + return files[0]; + } + + protected abstract CompressionEngine CreateCompressionEngine(); + + private static IDictionary CreateStringDictionary( + IList keys, + IList values) + { + IDictionary dictionary = (IDictionary) new Dictionary((IEqualityComparer) StringComparer.OrdinalIgnoreCase); + int index = 0; + while (index < keys.Count) + { + dictionary.Add(keys[index], values[index]); + checked { ++index; } + } + return dictionary; + } + + private void RecursiveGetRelativeFilePathsInDirectoryTree( + string dir, + string relativeDir, + bool includeSubdirectories, + IList fileList) + { + foreach (string file in System.IO.Directory.GetFiles(dir)) + { + string fileName = Path.GetFileName(file); + fileList.Add(Path.Combine(relativeDir, fileName)); + } + if (!includeSubdirectories) + return; + foreach (string directory in System.IO.Directory.GetDirectories(dir)) + { + string fileName = Path.GetFileName(directory); + this.RecursiveGetRelativeFilePathsInDirectoryTree(Path.Combine(dir, fileName), Path.Combine(relativeDir, fileName), includeSubdirectories, fileList); + } + } + + private IList InternalGetFiles(Predicate fileFilter) + { + using (CompressionEngine compressionEngine = this.CreateCompressionEngine()) + { + IList fileInfo = compressionEngine.GetFileInfo((IUnpackStreamContext) new ArchiveFileStreamContext(this.FullName, (string) null, (IDictionary) null) + { + EnableOffsetOpen = true + }, fileFilter); + int index = 0; + while (index < fileInfo.Count) + { + fileInfo[index].Archive = this; + checked { ++index; } + } + return fileInfo; + } + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressEventArgs.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressEventArgs.cs new file mode 100644 index 00000000..05e6cf6a --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressEventArgs.cs @@ -0,0 +1,161 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveProgressEventArgs +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; + +namespace Microsoft.Deployment.Compression +{ + public class ArchiveProgressEventArgs : EventArgs + { + private ArchiveProgressType progressType; + private string currentFileName; + private int currentFileNumber; + private int totalFiles; + private long currentFileBytesProcessed; + private long currentFileTotalBytes; + private string currentArchiveName; + private short currentArchiveNumber; + private short totalArchives; + private long currentArchiveBytesProcessed; + private long currentArchiveTotalBytes; + private long fileBytesProcessed; + private long totalFileBytes; + + public ArchiveProgressEventArgs( + ArchiveProgressType progressType, + string currentFileName, + int currentFileNumber, + int totalFiles, + long currentFileBytesProcessed, + long currentFileTotalBytes, + string currentArchiveName, + int currentArchiveNumber, + int totalArchives, + long currentArchiveBytesProcessed, + long currentArchiveTotalBytes, + long fileBytesProcessed, + long totalFileBytes) + { + this.progressType = progressType; + this.currentFileName = currentFileName; + this.currentFileNumber = currentFileNumber; + this.totalFiles = totalFiles; + this.currentFileBytesProcessed = currentFileBytesProcessed; + this.currentFileTotalBytes = currentFileTotalBytes; + this.currentArchiveName = currentArchiveName; + this.currentArchiveNumber = checked ((short) currentArchiveNumber); + this.totalArchives = checked ((short) totalArchives); + this.currentArchiveBytesProcessed = currentArchiveBytesProcessed; + this.currentArchiveTotalBytes = currentArchiveTotalBytes; + this.fileBytesProcessed = fileBytesProcessed; + this.totalFileBytes = totalFileBytes; + } + + public ArchiveProgressType ProgressType + { + get + { + return this.progressType; + } + } + + public string CurrentFileName + { + get + { + return this.currentFileName; + } + } + + public int CurrentFileNumber + { + get + { + return this.currentFileNumber; + } + } + + public int TotalFiles + { + get + { + return this.totalFiles; + } + } + + public long CurrentFileBytesProcessed + { + get + { + return this.currentFileBytesProcessed; + } + } + + public long CurrentFileTotalBytes + { + get + { + return this.currentFileTotalBytes; + } + } + + public string CurrentArchiveName + { + get + { + return this.currentArchiveName; + } + } + + public int CurrentArchiveNumber + { + get + { + return (int) this.currentArchiveNumber; + } + } + + public int TotalArchives + { + get + { + return (int) this.totalArchives; + } + } + + public long CurrentArchiveBytesProcessed + { + get + { + return this.currentArchiveBytesProcessed; + } + } + + public long CurrentArchiveTotalBytes + { + get + { + return this.currentArchiveTotalBytes; + } + } + + public long FileBytesProcessed + { + get + { + return this.fileBytesProcessed; + } + } + + public long TotalFileBytes + { + get + { + return this.totalFileBytes; + } + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressType.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressType.cs new file mode 100644 index 00000000..2c342b48 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/ArchiveProgressType.cs @@ -0,0 +1,18 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.ArchiveProgressType +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +namespace Microsoft.Deployment.Compression +{ + public enum ArchiveProgressType + { + StartFile, + PartialFile, + FinishFile, + StartArchive, + PartialArchive, + FinishArchive, + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/BasicUnpackStreamContext.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/BasicUnpackStreamContext.cs new file mode 100644 index 00000000..e3decfdd --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/BasicUnpackStreamContext.cs @@ -0,0 +1,56 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.BasicUnpackStreamContext +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public class BasicUnpackStreamContext : IUnpackStreamContext + { + private Stream archiveStream; + private Stream fileStream; + + public BasicUnpackStreamContext(Stream archiveStream) + { + this.archiveStream = archiveStream; + } + + public Stream FileStream + { + get + { + return this.fileStream; + } + } + + public Stream OpenArchiveReadStream( + int archiveNumber, + string archiveName, + CompressionEngine compressionEngine) + { + return (Stream) new DuplicateStream(this.archiveStream); + } + + public void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream) + { + } + + public Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime) + { + this.fileStream = (Stream) new MemoryStream(new byte[fileSize], 0, checked ((int) fileSize), true, true); + return this.fileStream; + } + + public void CloseFileWriteStream( + string path, + Stream stream, + FileAttributes attributes, + DateTime lastWriteTime) + { + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CargoStream.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CargoStream.cs new file mode 100644 index 00000000..b9ee6763 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CargoStream.cs @@ -0,0 +1,118 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.CargoStream +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public class CargoStream : Stream + { + private Stream source; + private List cargo; + + public CargoStream(Stream source, params IDisposable[] cargo) + { + if (source == null) + throw new ArgumentNullException(nameof (source)); + this.source = source; + this.cargo = new List((IEnumerable) cargo); + } + + public Stream Source + { + get + { + return this.source; + } + } + + public IList Cargo + { + get + { + return (IList) this.cargo; + } + } + + public override bool CanRead + { + get + { + return this.source.CanRead; + } + } + + public override bool CanWrite + { + get + { + return this.source.CanWrite; + } + } + + public override bool CanSeek + { + get + { + return this.source.CanSeek; + } + } + + public override long Length + { + get + { + return this.source.Length; + } + } + + public override long Position + { + get + { + return this.source.Position; + } + set + { + this.source.Position = value; + } + } + + public override void Flush() + { + this.source.Flush(); + } + + public override void SetLength(long value) + { + this.source.SetLength(value); + } + + public override void Close() + { + this.source.Close(); + foreach (IDisposable disposable in this.cargo) + disposable.Dispose(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return this.source.Read(buffer, offset, count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + this.source.Write(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return this.source.Seek(offset, origin); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionEngine.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionEngine.cs new file mode 100644 index 00000000..8cdacf86 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionEngine.cs @@ -0,0 +1,178 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.CompressionEngine +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public abstract class CompressionEngine : IDisposable + { + private CompressionLevel compressionLevel; + private bool dontUseTempFiles; + + protected CompressionEngine() + { + this.compressionLevel = CompressionLevel.Normal; + } + + ~CompressionEngine() + { + this.Dispose(false); + } + + public event EventHandler Progress; + + public bool UseTempFiles + { + get + { + return !this.dontUseTempFiles; + } + set + { + this.dontUseTempFiles = !value; + } + } + + public CompressionLevel CompressionLevel + { + get + { + return this.compressionLevel; + } + set + { + this.compressionLevel = value; + } + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize((object) this); + } + + public void Pack(IPackStreamContext streamContext, IEnumerable files) + { + if (files == null) + throw new ArgumentNullException(nameof (files)); + this.Pack(streamContext, files, 0L); + } + + public abstract void Pack( + IPackStreamContext streamContext, + IEnumerable files, + long maxArchiveSize); + + public abstract bool IsArchive(Stream stream); + + public virtual long FindArchiveOffset(Stream stream) + { + if (stream == null) + throw new ArgumentNullException(nameof (stream)); + long num = 4; + long length = stream.Length; + long offset = 0; + while (offset <= checked (length - num)) + { + stream.Seek(offset, SeekOrigin.Begin); + if (this.IsArchive(stream)) + return offset; + checked { offset += num; } + } + return -1; + } + + public IList GetFileInfo(Stream stream) + { + return this.GetFileInfo((IUnpackStreamContext) new BasicUnpackStreamContext(stream), (Predicate) null); + } + + public abstract IList GetFileInfo( + IUnpackStreamContext streamContext, + Predicate fileFilter); + + public IList GetFiles(Stream stream) + { + return this.GetFiles((IUnpackStreamContext) new BasicUnpackStreamContext(stream), (Predicate) null); + } + + public IList GetFiles( + IUnpackStreamContext streamContext, + Predicate fileFilter) + { + if (streamContext == null) + throw new ArgumentNullException(nameof (streamContext)); + IList fileInfo = this.GetFileInfo(streamContext, fileFilter); + IList stringList = (IList) new List(fileInfo.Count); + int index = 0; + while (index < fileInfo.Count) + { + stringList.Add(fileInfo[index].Name); + checked { ++index; } + } + return stringList; + } + + public Stream Unpack(Stream stream, string path) + { + if (stream == null) + throw new ArgumentNullException(nameof (stream)); + if (path == null) + throw new ArgumentNullException(nameof (path)); + BasicUnpackStreamContext unpackStreamContext = new BasicUnpackStreamContext(stream); + this.Unpack((IUnpackStreamContext) unpackStreamContext, (Predicate) (match => string.Compare(match, path, true, CultureInfo.InvariantCulture) == 0)); + Stream fileStream = unpackStreamContext.FileStream; + if (fileStream != null) + fileStream.Position = 0L; + return fileStream; + } + + public abstract void Unpack(IUnpackStreamContext streamContext, Predicate fileFilter); + + protected void OnProgress(ArchiveProgressEventArgs e) + { + if (this.Progress == null) + return; + this.Progress((object) this, e); + } + + protected virtual void Dispose(bool disposing) + { + } + + public static void DosDateAndTimeToDateTime( + short dosDate, + short dosTime, + out DateTime dateTime) + { + if (dosDate == (short) 0 && dosTime == (short) 0) + { + dateTime = DateTime.MinValue; + } + else + { + long fileTime; + SafeNativeMethods.DosDateTimeToFileTime(dosDate, dosTime, out fileTime); + dateTime = DateTime.FromFileTimeUtc(fileTime); + dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Local); + } + } + + public static void DateTimeToDosDateAndTime( + DateTime dateTime, + out short dosDate, + out short dosTime) + { + dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc); + long fileTimeUtc = dateTime.ToFileTimeUtc(); + SafeNativeMethods.FileTimeToDosDateTime(ref fileTimeUtc, out dosDate, out dosTime); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionLevel.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionLevel.cs new file mode 100644 index 00000000..cc0b874b --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/CompressionLevel.cs @@ -0,0 +1,16 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.CompressionLevel +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +namespace Microsoft.Deployment.Compression +{ + public enum CompressionLevel + { + None = 0, + Min = 1, + Normal = 6, + Max = 10, // 0x0000000A + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/DuplicateStream.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/DuplicateStream.cs new file mode 100644 index 00000000..b8ce95ec --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/DuplicateStream.cs @@ -0,0 +1,134 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.DuplicateStream +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public class DuplicateStream : Stream + { + private Stream source; + private long position; + + public DuplicateStream(Stream source) + { + if (source == null) + throw new ArgumentNullException(nameof (source)); + this.source = DuplicateStream.OriginalStream(source); + } + + public Stream Source + { + get + { + return this.source; + } + } + + public override bool CanRead + { + get + { + return this.source.CanRead; + } + } + + public override bool CanWrite + { + get + { + return this.source.CanWrite; + } + } + + public override bool CanSeek + { + get + { + return this.source.CanSeek; + } + } + + public override long Length + { + get + { + return this.source.Length; + } + } + + public override long Position + { + get + { + return this.position; + } + set + { + this.position = value; + } + } + + public static Stream OriginalStream(Stream stream) + { + DuplicateStream duplicateStream = stream as DuplicateStream; + if (duplicateStream == null) + return stream; + return duplicateStream.Source; + } + + public override void Flush() + { + this.source.Flush(); + } + + public override void SetLength(long value) + { + this.source.SetLength(value); + } + + public override void Close() + { + this.source.Close(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + long position = this.source.Position; + this.source.Position = this.position; + int num = this.source.Read(buffer, offset, count); + this.position = this.source.Position; + this.source.Position = position; + return num; + } + + public override void Write(byte[] buffer, int offset, int count) + { + long position = this.source.Position; + this.source.Position = this.position; + this.source.Write(buffer, offset, count); + this.position = this.source.Position; + this.source.Position = position; + } + + public override long Seek(long offset, SeekOrigin origin) + { + long num = 0; + switch (origin) + { + case SeekOrigin.Current: + num = this.position; + break; + case SeekOrigin.End: + num = this.Length; + break; + } + this.position = checked (num + offset); + return this.position; + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IPackStreamContext.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IPackStreamContext.cs new file mode 100644 index 00000000..844aed70 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IPackStreamContext.cs @@ -0,0 +1,33 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.IPackStreamContext +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public interface IPackStreamContext + { + string GetArchiveName(int archiveNumber); + + Stream OpenArchiveWriteStream( + int archiveNumber, + string archiveName, + bool truncate, + CompressionEngine compressionEngine); + + void CloseArchiveWriteStream(int archiveNumber, string archiveName, Stream stream); + + Stream OpenFileReadStream( + string path, + out FileAttributes attributes, + out DateTime lastWriteTime); + + void CloseFileReadStream(string path, Stream stream); + + object GetOption(string optionName, object[] parameters); + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IUnpackStreamContext.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IUnpackStreamContext.cs new file mode 100644 index 00000000..4bbcbcbd --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/IUnpackStreamContext.cs @@ -0,0 +1,29 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.IUnpackStreamContext +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public interface IUnpackStreamContext + { + Stream OpenArchiveReadStream( + int archiveNumber, + string archiveName, + CompressionEngine compressionEngine); + + void CloseArchiveReadStream(int archiveNumber, string archiveName, Stream stream); + + Stream OpenFileWriteStream(string path, long fileSize, DateTime lastWriteTime); + + void CloseFileWriteStream( + string path, + Stream stream, + FileAttributes attributes, + DateTime lastWriteTime); + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/OffsetStream.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/OffsetStream.cs new file mode 100644 index 00000000..d29d2270 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/OffsetStream.cs @@ -0,0 +1,126 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.OffsetStream +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.IO; + +namespace Microsoft.Deployment.Compression +{ + public class OffsetStream : Stream + { + private Stream source; + private long sourceOffset; + + public OffsetStream(Stream source, long offset) + { + if (source == null) + throw new ArgumentNullException(nameof (source)); + this.source = source; + this.sourceOffset = offset; + this.source.Seek(this.sourceOffset, SeekOrigin.Current); + } + + public Stream Source + { + get + { + return this.source; + } + } + + public long Offset + { + get + { + return this.sourceOffset; + } + } + + public override bool CanRead + { + get + { + return this.source.CanRead; + } + } + + public override bool CanWrite + { + get + { + return this.source.CanWrite; + } + } + + public override bool CanSeek + { + get + { + return this.source.CanSeek; + } + } + + public override long Length + { + get + { + return checked (this.source.Length - this.sourceOffset); + } + } + + public override long Position + { + get + { + return checked (this.source.Position - this.sourceOffset); + } + set + { + this.source.Position = checked (value + this.sourceOffset); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return this.source.Read(buffer, offset, count); + } + + public override void Write(byte[] buffer, int offset, int count) + { + this.source.Write(buffer, offset, count); + } + + public override int ReadByte() + { + return this.source.ReadByte(); + } + + public override void WriteByte(byte value) + { + this.source.WriteByte(value); + } + + public override void Flush() + { + this.source.Flush(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return checked (this.source.Seek(offset + (unchecked (origin == SeekOrigin.Begin) ? this.sourceOffset : 0L), origin) - this.sourceOffset); + } + + public override void SetLength(long value) + { + this.source.SetLength(checked (value + this.sourceOffset)); + } + + public override void Close() + { + this.source.Close(); + } + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Deployment/Compression/SafeNativeMethods.cs b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/SafeNativeMethods.cs new file mode 100644 index 00000000..ec28ee83 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Deployment/Compression/SafeNativeMethods.cs @@ -0,0 +1,29 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Deployment.Compression.SafeNativeMethods +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System.Runtime.InteropServices; +using System.Security; + +namespace Microsoft.Deployment.Compression +{ + [SuppressUnmanagedCodeSecurity] + internal static class SafeNativeMethods + { + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DosDateTimeToFileTime( + short wFatDate, + short wFatTime, + out long fileTime); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FileTimeToDosDateTime( + ref long fileTime, + out short wFatDate, + out short wFatTime); + } +} diff --git a/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.Core.csproj b/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.Core.csproj new file mode 100644 index 00000000..b430bfc8 --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.Core.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + Microsoft.Deployment.Compression + Microsoft.Deployment.Compression + false + + + + true + ..\..\bin\Debug\ + + + + true + ..\..\bin\Release\ + + + diff --git a/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.csproj b/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.csproj new file mode 100644 index 00000000..d18bb98e --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Microsoft.Deployment.Compression.csproj @@ -0,0 +1,57 @@ + + + + + Debug + AnyCPU + {7E27586B-D9CF-4B1B-B939-DAECBDF84EA1} + Library + Microsoft.Deployment.Compression + v3.5 + 3.0.0.0 + 512 + Microsoft + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Cab/Microsoft.Deployment.Compression/Tools/WindowsInstallerXml/WixDistribution.cs b/Cab/Microsoft.Deployment.Compression/Tools/WindowsInstallerXml/WixDistribution.cs new file mode 100644 index 00000000..35fdb61d --- /dev/null +++ b/Cab/Microsoft.Deployment.Compression/Tools/WindowsInstallerXml/WixDistribution.cs @@ -0,0 +1,65 @@ +// Decompiled with JetBrains decompiler +// Type: Microsoft.Tools.WindowsInstallerXml.WixDistribution +// Assembly: Microsoft.Deployment.Compression, Version=3.0.0.0, Culture=neutral, PublicKeyToken=ce35f76fcda82bad +// MVID: 6A7FAA37-3E7D-4F08-9CEC-6FFE0F4F3B2D +// Assembly location: E:\Gits\sample code\msftcompressioncab.1.0.0\lib\Microsoft.Deployment.Compression.dll + +using System; +using System.Diagnostics; +using System.Reflection; + +namespace Microsoft.Tools.WindowsInstallerXml +{ + internal static class WixDistribution + { + public static string NewsUrl = "http://wixtoolset.org/news/"; + public static string ShortProduct = "WiX Toolset"; + public static string SupportUrl = "http://wixtoolset.org/"; + public static string TelemetryUrlFormat = "http://wixtoolset.org/telemetry/v{0}/?r={1}"; + + public static string ReplacePlaceholders(string original, Assembly assembly) + { + if (assembly != null) + { + FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(assembly.Location); + original = original.Replace("[FileComments]", versionInfo.Comments); + original = original.Replace("[FileCopyright]", versionInfo.LegalCopyright); + original = original.Replace("[FileProductName]", versionInfo.ProductName); + original = original.Replace("[FileVersion]", versionInfo.FileVersion); + if (original.Contains("[FileVersionMajorMinor]")) + { + Version version = new Version(versionInfo.FileVersion); + original = original.Replace("[FileVersionMajorMinor]", version.Major.ToString() + "." + (object) version.Minor); + } + AssemblyCompanyAttribute attribute1; + if (WixDistribution.TryGetAttribute(assembly, out attribute1)) + original = original.Replace("[AssemblyCompany]", attribute1.Company); + AssemblyCopyrightAttribute attribute2; + if (WixDistribution.TryGetAttribute(assembly, out attribute2)) + original = original.Replace("[AssemblyCopyright]", attribute2.Copyright); + AssemblyDescriptionAttribute attribute3; + if (WixDistribution.TryGetAttribute(assembly, out attribute3)) + original = original.Replace("[AssemblyDescription]", attribute3.Description); + AssemblyProductAttribute attribute4; + if (WixDistribution.TryGetAttribute(assembly, out attribute4)) + original = original.Replace("[AssemblyProduct]", attribute4.Product); + AssemblyTitleAttribute attribute5; + if (WixDistribution.TryGetAttribute(assembly, out attribute5)) + original = original.Replace("[AssemblyTitle]", attribute5.Title); + } + original = original.Replace("[NewsUrl]", WixDistribution.NewsUrl); + original = original.Replace("[ShortProduct]", WixDistribution.ShortProduct); + original = original.Replace("[SupportUrl]", WixDistribution.SupportUrl); + return original; + } + + private static bool TryGetAttribute(Assembly assembly, out T attribute) where T : Attribute + { + attribute = default (T); + object[] customAttributes = assembly.GetCustomAttributes(typeof (T), false); + if (customAttributes != null && customAttributes.Length != 0) + attribute = customAttributes[0] as T; + return (object) attribute != null; + } + } +} diff --git a/Console/ConsoleBrowser.cs b/Console/ConsoleBrowser.cs index 552b7503..1772a5b2 100644 --- a/Console/ConsoleBrowser.cs +++ b/Console/ConsoleBrowser.cs @@ -1,197 +1,504 @@ -//! \file Program.cs -//! \date Mon Jun 30 20:12:13 2014 -//! \brief game resources browser. -// - -using System; +using System; +using System.Collections.Generic; using System.IO; -using System.IO.MemoryMappedFiles; using System.Text; using System.Linq; -using System.Collections.Generic; using System.Diagnostics; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Media.Imaging; using GameRes; +// ReSharper disable LocalizableElement namespace GARbro { - class ConsoleBrowser - { - private string m_arc_name; - private ImageFormat m_image_format; - private bool m_extract_all; - - void ListFormats () - { - Console.WriteLine ("Recognized resource formats:"); - foreach (var impl in FormatCatalog.Instance.ArcFormats) - { - Console.WriteLine ("{0,-4} {1}", impl.Tag, impl.Description); - } - } - - void ExtractAll (ArcFile arc) - { - arc.ExtractFiles ((i, entry, msg) => { - if (null != entry) - { - Console.WriteLine ("Extracting {0} ...", entry.Name); - } - else if (null != msg) - { - Console.WriteLine (msg); - } - return ArchiveOperation.Continue; - }); - } - - void ExtractFile (ArcFile arc, string name) - { - Entry entry = arc.Dir.FirstOrDefault (e => e.Name.Equals (name, StringComparison.OrdinalIgnoreCase)); - if (null == entry) - { - Console.Error.WriteLine ("'{0}' not found within {1}", name, m_arc_name); - return; - } - Console.WriteLine ("Extracting {0} ...", entry.Name); - arc.Extract (entry); - } - - void TestArc (string[] args) - { -/* - if (args.Length > 1) - { - uint pass = GameRes.Formats.IntOpener.EncodePassPhrase (args[1]); - Console.WriteLine ("{0:X8}", pass); - } -*/ - } - - void Run (string[] args) - { - int argn = 0; - while (argn < args.Length) - { - if (args[argn].Equals ("-l")) - { - ListFormats(); - return; - } - else if (args[argn].Equals ("-t")) - { - TestArc (args); - return; - } - else if (args[argn].Equals ("-c")) - { - if (argn+1 >= args.Length) - { - Usage(); - return; - } - var tag = args[argn+1]; - m_image_format = FindFormat (tag); - if (null == m_image_format) - { - Console.Error.WriteLine ("{0}: unknown format specified", tag); - return; - } - argn += 2; - } - else if (args[argn].Equals ("-x")) - { - m_extract_all = true; - ++argn; - if (args.Length <= argn) - { - Usage(); - return; - } - } - else - { - break; - } - } - if (argn >= args.Length) - { - Usage(); - return; - } - DeserializeGameData(); - foreach (var file in VFS.GetFiles (args[argn])) - { - m_arc_name = file.Name; - try - { - VFS.ChDir (m_arc_name); - } - catch (Exception X) - { - Console.Error.WriteLine ("{0}: unknown format", m_arc_name); - continue; - } - var arc = (ArchiveFileSystem)VFS.Top; - if (args.Length > argn+1) - { - for (int i = argn+1; i < args.Length; ++i) - ExtractFile (arc, args[i]); - } - else if (m_extract_all) - { - ExtractAll (arc); - } - else - { - foreach (var entry in arc.Dir.OrderBy (e => e.Offset)) - { - Console.WriteLine ("{0,9} [{2:X8}] {1}", entry.Size, entry.Name, entry.Offset); - } - } - } - } - - void DeserializeGameData () - { - string scheme_file = Path.Combine (FormatCatalog.Instance.DataDirectory, "Formats.dat"); - try - { - using (var file = File.OpenRead (scheme_file)) - FormatCatalog.Instance.DeserializeScheme (file); - } - catch (Exception X) - { - Console.Error.WriteLine ("Scheme deserialization failed: {0}", X.Message); - } - } - - static void Usage () - { - Console.WriteLine ("Usage: gameres [OPTIONS] ARC [ENTRIES]"); - Console.WriteLine (" -l list recognized archive formats"); - Console.WriteLine (" -x extract all files"); - Console.WriteLine ("Without options displays contents of specified archive."); - } - - static void Main (string[] args) - { - Console.OutputEncoding = Encoding.UTF8; - if (0 == args.Length) - { - Usage(); - return; - } - var listener = new TextWriterTraceListener (Console.Error); - Trace.Listeners.Add(listener); - try - { - var browser = new ConsoleBrowser(); - browser.Run (args); - } - catch (Exception X) - { - Console.Error.WriteLine (X.Message); - } - } - } -} + public enum ExistingFileAction + { + Ask, + Skip, + Overwrite, + Rename + } + + class ConsoleBrowser + { + private string outputDirectory; + + private Regex fileFilter; + private ImageFormat imageFormat; + private bool autoImageFormat = false; + private bool ignoreErrors = true; + private bool skipImages; + private bool skipScript; + private bool skipAudio; + private bool convertAudio; + private bool adjustImageOffset; + + private ExistingFileAction existingFileAction = ExistingFileAction.Ask; + + public static readonly HashSet CommonAudioFormats = new HashSet { "wav", "mp3", "ogg" }; + public static readonly HashSet CommonImageFormats = new HashSet { "jpeg", "png", "bmp", "tga" }; + + private void ListFormats() + { + Console.WriteLine("Recognized resource formats:\n"); + foreach (var format in FormatCatalog.Instance.ArcFormats.OrderBy(format => format.Tag)) + { + Console.WriteLine("{0,-20} {1}", format.Tag, format.Description); + } + } + + private void ListFiles(Entry[] fileList) + { + Console.WriteLine(" Offset Size Name"); + Console.WriteLine(" ---------- -------- ------------------------------------------------------"); + foreach (var entry in fileList) + { + Console.WriteLine(" [{1:X8}] {0,9} {2}", entry.Offset, entry.Size, entry.Name); + } + + Console.WriteLine(" ---------- -------- ------------------------------------------------------"); + Console.WriteLine($" {fileList.Length} files"); + } + + private void ExtractFiles(Entry[] fileList, ArcFile arc) + { + Directory.CreateDirectory(outputDirectory); + + var iSkipped = 0; + for (var i = 0; i < fileList.Length; i++) + { + var entry = fileList[i]; + Console.WriteLine(string.Format("[{0}/{1}] {2}", i + 1, fileList.Length, entry.Name)); + + try + { + if (imageFormat != null && entry.Type == "image") + { + ExtractImage(arc, entry, imageFormat); + } + else if (convertAudio && entry.Type == "audio") + { + ExtractAudio(arc, entry); + } + else + { + using (var input = arc.OpenEntry(entry)) + using (var output = CreateNewFile(entry.Name)) + input.CopyTo(output); + } + } + catch (TargetException) + { + iSkipped++; + } +#if !DEBUG + catch (Exception e) { + PrintError(string.Format($"Failed to extract {entry.Name}: {e.Message}")); + if (!ignoreErrors) return; + + iSkipped++; + } +#endif + } + + Console.WriteLine(); + Console.WriteLine(iSkipped > 0 ? iSkipped + " files were skipped" : "All OK"); + } + + void ExtractImage(ArcFile arc, Entry entry, ImageFormat targetFormat) + { + using (var decoder = arc.OpenImage(entry)) + { + var src_format = decoder.SourceFormat; // could be null + + if (autoImageFormat && src_format != null) targetFormat = CommonImageFormats.Contains(src_format.Tag.ToLower()) ? src_format : ImageFormat.Png; + + var target_ext = targetFormat.Extensions.FirstOrDefault() ?? ""; + var outputName = Path.ChangeExtension(entry.Name, target_ext); + if (src_format == targetFormat) + { + // source format is the same as a target, copy file as is + using (var output = CreateNewFile(outputName)) decoder.Source.CopyTo(output); + return; + } + + var image = decoder.Image; + if (adjustImageOffset) image = AdjustImageOffset(image); + + using (var outfile = CreateNewFile(outputName)) + { + targetFormat.Write(outfile, image); + } + } + } + + static ImageData AdjustImageOffset(ImageData image) + { + if (0 == image.OffsetX && 0 == image.OffsetY) return image; + var width = (int)image.Width + image.OffsetX; + var height = (int)image.Height + image.OffsetY; + if (width <= 0 || height <= 0) return image; + + var x = Math.Max(image.OffsetX, 0); + var y = Math.Max(image.OffsetY, 0); + var src_x = image.OffsetX < 0 ? Math.Abs(image.OffsetX) : 0; + var src_y = image.OffsetY < 0 ? Math.Abs(image.OffsetY) : 0; + var src_stride = (int)image.Width * (image.BPP + 7) / 8; + var dst_stride = width * (image.BPP + 7) / 8; + var pixels = new byte[height * dst_stride]; + var offset = y * dst_stride + x * image.BPP / 8; + var rect = new Int32Rect(src_x, src_y, (int)image.Width - src_x, 1); + for (var row = src_y; row < image.Height; ++row) + { + rect.Y = row; + image.Bitmap.CopyPixels(rect, pixels, src_stride, offset); + offset += dst_stride; + } + + var bitmap = BitmapSource.Create(width, height, image.Bitmap.DpiX, image.Bitmap.DpiY, + image.Bitmap.Format, image.Bitmap.Palette, pixels, dst_stride); + return new ImageData(bitmap); + } + + void ExtractAudio(ArcFile arc, Entry entry) + { + using (var file = arc.OpenBinaryEntry(entry)) + using (var sound = AudioFormat.Read(file)) + { + if (sound == null) throw new InvalidFormatException("Unable to interpret audio format"); + ConvertAudio(entry.Name, sound); + } + } + + public void ConvertAudio(string filename, SoundInput input) + { + var source_format = input.SourceFormat; + if (CommonAudioFormats.Contains(source_format)) + { + var output_name = Path.ChangeExtension(filename, source_format); + using (var output = CreateNewFile(output_name)) + { + input.Source.Position = 0; + input.Source.CopyTo(output); + } + } + else + { + var output_name = Path.ChangeExtension(filename, "wav"); + using (var output = CreateNewFile(output_name)) AudioFormat.Wav.Write(input, output); + } + } + + protected Stream CreateNewFile(string filename) + { + var path = Path.Combine(outputDirectory, filename); + path = Path.GetFullPath(path); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + if (File.Exists(path)) + { + path = OverwritePrompt(path); + if (path == null) throw new TargetException(); + } + + return File.Open(path, FileMode.Create); + } + + void Run(string[] args) + { + var command = args.Length < 1 ? "h" : args[0]; + + switch (command) + { + case "h": + case "-h": + case "--help": + case "/?": + case "-?": + Usage(); + return; + case "f": + ListFormats(); + return; + } + + if (command.Length != 1) + { + PrintError(File.Exists(command) ? "No command specified. Use -h command line parameter to show help." : "Invalid command: " + command); + return; + } + if (args.Length < 2) + { + PrintError("No archive file specified"); + return; + } + + var inputFile = args[args.Length - 1]; + if (!File.Exists(inputFile)) + { + PrintError("Input file " + inputFile + " does not exist"); + return; + } + + var argLength = args.Length - 1; + outputDirectory = Directory.GetCurrentDirectory(); + for (var i = 1; i < argLength; i++) + { + switch (args[i]) + { + case "-o": + i++; + if (i >= argLength) + { + PrintError("No output directory specified"); + return; + } + outputDirectory = args[i]; + if (File.Exists(outputDirectory)) + { + PrintError("Invalid output directory"); + return; + } + + //Directory.SetCurrentDirectory(outputDirectory); + break; + case "-f": + i++; + if (i >= argLength) + { + PrintError("No filter specified"); + return; + } + + try + { + fileFilter = new Regex(args[i]); + } + catch (ArgumentException e) + { + PrintError("Invalid filter: " + e.Message); + return; + } + + break; + case "-if": + i++; + var formatTag = args[i].ToUpper(); + if (formatTag == "JPG") formatTag = "JPEG"; + + imageFormat = ImageFormat.FindByTag(formatTag); + if (imageFormat == null) + { + PrintError("Unknown image format specified: " + args[i]); + return; + } + break; + case "-ca": + convertAudio = true; + break; + case "-na": + skipAudio = true; + break; + case "-ni": + skipImages = true; + break; + case "-ns": + skipScript = true; + break; + case "-aio": + adjustImageOffset = true; + break; + case "-ocu": + autoImageFormat = true; + break; + default: + Console.WriteLine("Warning: Unknown command line parameter: " + args[i]); + return; + } + } + + if (autoImageFormat && imageFormat == null) + { + PrintError("The parameter -ocu requires the image format (-if parameter) to be set"); + return; + } + + DeserializeGameData(); + + try + { + VFS.ChDir(inputFile); + } + catch (Exception) + { + PrintError("Input file has an unknown format"); + return; + } + + var m_fs = (ArchiveFileSystem)VFS.Top; + var fileList = m_fs.GetFilesRecursive().Where(e => e.Offset >= 0); + + if (skipImages || skipScript || skipAudio || fileFilter != null) + { + fileList = fileList.Where(f => !(skipImages && f.Type == "image") && + !(skipScript && f.Type == "script") && + !(skipAudio && f.Type == "audio") && + (fileFilter == null || fileFilter.IsMatch(f.Name))); + } + + if (!fileList.Any()) + { + var hasFilter = skipAudio || skipImages || skipScript || fileFilter != null; + PrintError(hasFilter ? "No files match the given filter" : "Archive is empty"); + return; + } + + var fileArray = fileList.OrderBy(e => e.Offset).ToArray(); + + Console.WriteLine(fileArray[0].Offset); + + switch (command) + { + case "i": + Console.WriteLine(m_fs.Source.Tag); + break; + case "l": + ListFiles(fileArray); + break; + case "x": + ExtractFiles(fileArray, m_fs.Source); + break; + } + } + + void DeserializeGameData() + { + var scheme_file = Path.Combine(FormatCatalog.Instance.DataDirectory, "Formats.dat"); + try + { + using (var file = File.OpenRead(scheme_file)) FormatCatalog.Instance.DeserializeScheme(file); + } + catch (Exception) + { + //Console.Error.WriteLine("Scheme deserialization failed: {0}", e.Message); + } + } + + static void Usage() + { + Console.WriteLine(string.Format("Usage: {0} [...] ", Process.GetCurrentProcess().ProcessName)); + Console.WriteLine("\nCommands:"); + Console.WriteLine(" i Identify archive format"); + Console.WriteLine(" f List supported formats"); + Console.WriteLine(" l List contents of archive"); + Console.WriteLine(" x Extract files from archive"); + Console.WriteLine("\nSwitches:"); + Console.WriteLine(" -o Set output directory for extraction"); + Console.WriteLine(" -f Only process files matching the regular expression "); + Console.WriteLine(" -if Set image output format (e.g. 'png', 'jpg', 'bmp')"); + Console.WriteLine(" -ca Convert audio files to wav format"); + Console.WriteLine(" -na Ignore audio files"); + Console.WriteLine(" -ni Ignore image files"); + Console.WriteLine(" -ns Ignore scripts"); + Console.WriteLine(" -aio Adjust image offset"); + Console.WriteLine(" -ocu Set -if switch to only convert unknown image formats"); + Console.WriteLine(); + //Console.WriteLine(FormatCatalog.Instance.ArcFormats.Count() + " supported formats"); + } + + static void PrintError(string msg) + { + Console.WriteLine("Error: " + msg); + } + + string OverwritePrompt(string filename) + { + switch (existingFileAction) + { + + case ExistingFileAction.Skip: + return null; + case ExistingFileAction.Overwrite: + return filename; + case ExistingFileAction.Rename: + return GetPathToRename(filename); + } + + Console.WriteLine(string.Format($"The file {filename} already exists. Overwrite? [Y]es | [N]o | [A]lways | n[E]ver | [R]ename | A[l]ways rename")); + + while (true) + { + switch (Console.Read()) + { + case 'y': + case 'Y': + return filename; + case 'n': + case 'N': + return null; + case 'a': + case 'A': + existingFileAction = ExistingFileAction.Overwrite; + return filename; + case 'e': + case 'E': + existingFileAction = ExistingFileAction.Skip; + return null; + case 'r': + case 'R': + return GetPathToRename(filename); + case 'l': + case 'L': + existingFileAction = ExistingFileAction.Rename; + return GetPathToRename(filename); + } + } + } + + string GetPathToRename(string path) + { + var directory = Path.GetDirectoryName(path); + var fileName = Path.GetFileNameWithoutExtension(path); + var fileExtension = Path.GetExtension(path); + + var i = 2; + do + { + path = Path.Combine(directory, string.Format($"{fileName} ({i}){fileExtension}")); + i++; + } while (File.Exists(path)); + + return path; + } + + private static void OnParametersRequest(object sender, ParametersRequestEventArgs eventArgs) + { + // Some archives are encrypted or require parameters to be set. + // Let's just use the default values for now. + var format = (IResource)sender; + //Console.WriteLine(eventArgs.Notice); + eventArgs.InputResult = true; + eventArgs.Options = format.GetDefaultOptions(); + } + + static void Main(string[] args) + { + Console.OutputEncoding = Encoding.UTF8; + Console.WriteLine(string.Format("GARbro - Game Resource browser, version {0}\n2014-2019 by mørkt, published under a MIT license", Assembly.GetAssembly(typeof(FormatCatalog)).GetName().Version)); + Console.WriteLine("-----------------------------------------------------------------------------\n"); + + FormatCatalog.Instance.ParametersRequest += OnParametersRequest; + //var listener = new TextWriterTraceListener(Console.Error); + //Trace.Listeners.Add(listener); + + var browser = new ConsoleBrowser(); + browser.Run(args); + +#if DEBUG + Console.Read(); +#endif + } + } +} \ No newline at end of file diff --git a/Console/GARbro.Console.Core.csproj b/Console/GARbro.Console.Core.csproj new file mode 100644 index 00000000..b79274db --- /dev/null +++ b/Console/GARbro.Console.Core.csproj @@ -0,0 +1,26 @@ + + + + Exe + netcoreapp3.1 + false + GARbro.Console + GARbro + true + + + + TRACE;DEBUG;NETCORE + ..\bin\Debug\ + + + + ..\bin\Release\ + TRACE;NETCORE + + + + + + + diff --git a/Console/GARbro.Console.csproj b/Console/GARbro.Console.csproj deleted file mode 100644 index d645b9c8..00000000 --- a/Console/GARbro.Console.csproj +++ /dev/null @@ -1,110 +0,0 @@ - - - - - Debug - AnyCPU - {B966F292-431A-4D8A-A1D3-1EB45048A1D2} - Exe - Properties - GARbro - GARbro.Console - v4.6 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - AnyCPU - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - ..\bin\Release\ - TRACE - prompt - 4 - false - - - ..\bin\Prerelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - Designer - - - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - \ No newline at end of file diff --git a/Console/README.md b/Console/README.md index 9570838b..f74b9991 100644 --- a/Console/README.md +++ b/Console/README.md @@ -1,7 +1,31 @@ -GameRes.Console +GARbro.Console =============== -Console utility that extracts files from game archives. Used as a testing -playground for GameRes library. +Standalone command line version of GARbro, which can list and extract files from supported archives. -No longer developed. +### Usage + +`GARbro.Console.exe [...] ` + +###### Commands: + +| Command | Description | +| ------- | ------------------------------------------------------------ | +| i | Identify archive format | +| f | Display supported formats. This prints a list of all formats GARbro can recognize. | +| l | List contents of archive | +| x | Extract files from archive | + +###### Switches: + +| Switch | Description | +| -------------- | ------------------------------------------------------------ | +| -o | Set output directory for extraction | +| -f | Only process files matching the regular expression | +| -if | Set image output format (e.g. 'png', 'jpg', 'bmp'). This converts all image files to the specified format. Caution: conversion might reduce the image quality and transparency can be lost (depending on the output format). Use the `-ocu` switch to skip common image formats. | +| -ca | Convert audio files to wav format; without this switch the original format is retained | +| -na | Skip audio files | +| -ni | Skip image files | +| -ns | Skip scripts | +| -aio | Adjust image offset | +| -ocu | Set -if switch to only convert unknown image formats.
The default behavior of `-if` is to convert all images to the specified format. This might not desirable because it reduces the image quality or transparency information can be lost. With the `-ocu` switch only uncommon formats are converted - for example jpg and png files are kept as is, while proprietary formats are converted. | \ No newline at end of file diff --git a/Experimental/CellWorks/ArcDB.cs b/Experimental/CellWorks/ArcDB.cs index 8e7c8009..f58c3dcf 100644 --- a/Experimental/CellWorks/ArcDB.cs +++ b/Experimental/CellWorks/ArcDB.cs @@ -37,65 +37,65 @@ namespace GameRes.Formats.CellWorks [Export(typeof(ArchiveFormat))] public class IgsDatOpener : ArchiveFormat { - public override string Tag { get { return "DAT/IGS"; } } + public override string Tag { get { return "DAT/IGS"; } } public override string Description { get { return "IGS engine resource archive"; } } - public override uint Signature { get { return 0; } } - public override bool IsHierarchic { get { return true; } } - public override bool CanWrite { get { return false; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return true; } } + public override bool CanWrite { get { return false; } } internal static readonly string[] KnownPasswords = { "igs sample", "igs samp1e" }; - public override ArcFile TryOpen (ArcView file) + public override ArcFile TryOpen(ArcView file) { - if (VFS.IsVirtual || !file.Name.HasExtension (".dat")) + if (VFS.IsVirtual || !file.Name.HasExtension(".dat")) return null; - var db_files = VFS.GetFiles (VFS.CombinePath (VFS.GetDirectoryName (file.Name), "*.db")); + var db_files = VFS.GetFiles(VFS.CombinePath(VFS.GetDirectoryName(file.Name), "*.db")); if (!db_files.Any()) return null; - using (var igs = new IgsDbReader (file.Name)) + using (var igs = new IgsDbReader(file.Name)) { - foreach (var db_name in db_files.Select (e => e.Name)) + foreach (var db_name in db_files.Select(e => e.Name)) { int arc_id; - if (igs.GetArchiveId (db_name, out arc_id)) + if (igs.GetArchiveId(db_name, out arc_id)) { - var dir = igs.ReadIndex (arc_id); + var dir = igs.ReadIndex(arc_id); if (0 == dir.Count) return null; - return new ArcFile (file, this, dir); + return new ArcFile(file, this, dir); } } return null; } } - public override Stream OpenEntry (ArcFile arc, Entry entry) + public override Stream OpenEntry(ArcFile arc, Entry entry) { using (var aes = Aes.Create()) { - var name_bytes = Encoding.UTF8.GetBytes (entry.Name); + var name_bytes = Encoding.UTF8.GetBytes(entry.Name); aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; - aes.Key = CreateKey (32, name_bytes); - aes.IV = CreateKey (16, name_bytes); + aes.Key = CreateKey(32, name_bytes); + aes.IV = CreateKey(16, name_bytes); using (var decryptor = aes.CreateDecryptor()) - using (var enc = arc.File.CreateStream (entry.Offset, 0x110)) - using (var input = new CryptoStream (enc, decryptor, CryptoStreamMode.Read)) + using (var enc = arc.File.CreateStream(entry.Offset, 0x110)) + using (var input = new CryptoStream(enc, decryptor, CryptoStreamMode.Read)) { - var header = new byte[Math.Min (entry.Size, 0x100u)]; - input.Read (header, 0, header.Length); + var header = new byte[Math.Min(entry.Size, 0x100u)]; + input.Read(header, 0, header.Length); if (entry.Size <= 0x100) - return new BinMemoryStream (header); - var rest = arc.File.CreateStream (entry.Offset+0x110, entry.Size-0x100); - return new PrefixStream (header, rest); + return new BinMemoryStream(header); + var rest = arc.File.CreateStream(entry.Offset + 0x110, entry.Size - 0x100); + return new PrefixStream(header, rest); } } } - internal static byte[] CreateKey (int length, byte[] src) + internal static byte[] CreateKey(int length, byte[] src) { var key = new byte[length]; - Buffer.BlockCopy (src, 0, key, 0, Math.Min (src.Length, length)); + Buffer.BlockCopy(src, 0, key, 0, Math.Min(src.Length, length)); for (int i = length; i < src.Length; ++i) key[i % length] ^= src[i]; return key; @@ -104,24 +104,31 @@ internal static byte[] CreateKey (int length, byte[] src) internal sealed class IgsDbReader : IDisposable { - SQLiteConnection m_conn; - SQLiteCommand m_arc_cmd; + SQLiteConnection m_conn; + SQLiteCommand m_arc_cmd; - public IgsDbReader (string arc_name) + public IgsDbReader(string arc_name) { m_conn = new SQLiteConnection(); m_arc_cmd = m_conn.CreateCommand(); m_arc_cmd.CommandText = @"SELECT id FROM archives WHERE name=?"; - m_arc_cmd.Parameters.Add (m_arc_cmd.CreateParameter()); - m_arc_cmd.Parameters[0].Value = Path.GetFileNameWithoutExtension (arc_name); + m_arc_cmd.Parameters.Add(m_arc_cmd.CreateParameter()); + m_arc_cmd.Parameters[0].Value = Path.GetFileNameWithoutExtension(arc_name); } - public bool GetArchiveId (string db_name, out int arc_id) + public bool GetArchiveId(string db_name, out int arc_id) { - m_conn.ConnectionString = string.Format ("Data Source={0};Read Only=true;", db_name); + //m_conn.ConnectionString = string.Format("Data Source={0};Read Only=true;", db_name); + + SQLiteConnectionStringBuilder sQLiteConnectionStringBuilder = new SQLiteConnectionStringBuilder(); + + sQLiteConnectionStringBuilder.ConnectionString = string.Format("Data Source={0};Read Only=true;", db_name); + foreach (var password in IgsDatOpener.KnownPasswords) { - m_conn.SetPassword (password); + sQLiteConnectionStringBuilder.Password = password; + m_conn.ConnectionString = sQLiteConnectionStringBuilder.ToString(); + //m_conn.SetPassword(password); m_conn.Open(); try { @@ -129,7 +136,7 @@ public bool GetArchiveId (string db_name, out int arc_id) { if (reader.Read()) { - arc_id = reader.GetInt32 (0); + arc_id = reader.GetInt32(0); return true; } } @@ -147,7 +154,7 @@ public bool GetArchiveId (string db_name, out int arc_id) return false; } - public List ReadIndex (int arc_id) + public List ReadIndex(int arc_id) { // tables: m_types file_infos images archives // m_types: id type -> [normal, image, voice] @@ -156,18 +163,18 @@ public List ReadIndex (int arc_id) using (var cmd = m_conn.CreateCommand()) { cmd.CommandText = @"SELECT filepath,offset,size FROM file_infos WHERE archiveID=?"; - cmd.Parameters.Add (cmd.CreateParameter()); + cmd.Parameters.Add(cmd.CreateParameter()); cmd.Parameters[0].Value = arc_id; using (var reader = cmd.ExecuteReader()) { var dir = new List(); while (reader.Read()) { - var name = reader.GetString (0); - var entry = FormatCatalog.Instance.Create (name); - entry.Offset = reader.GetInt64 (1); - entry.Size = (uint)reader.GetInt32 (2); - dir.Add (entry); + var name = reader.GetString(0); + var entry = FormatCatalog.Instance.Create(name); + entry.Offset = reader.GetInt64(1); + entry.Size = (uint)reader.GetInt32(2); + dir.Add(entry); } return dir; } @@ -175,7 +182,7 @@ public List ReadIndex (int arc_id) } bool _disposed = false; - public void Dispose () + public void Dispose() { if (!_disposed) { @@ -183,7 +190,7 @@ public void Dispose () m_conn.Dispose(); _disposed = true; } - GC.SuppressFinalize (this); + GC.SuppressFinalize(this); } } } diff --git a/Experimental/Experimental.Core.csproj b/Experimental/Experimental.Core.csproj new file mode 100644 index 00000000..4145b455 --- /dev/null +++ b/Experimental/Experimental.Core.csproj @@ -0,0 +1,42 @@ + + + + netcoreapp3.1 + ArcExtra + GameRes.Extra + true + false + + + + TRACE;DEBUG;NETCORE + true + ..\bin\Debug\ + + + + TRACE;NETCORE + ..\bin\Release\ + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/Experimental/Experimental.csproj b/Experimental/Experimental.csproj deleted file mode 100644 index a828663d..00000000 --- a/Experimental/Experimental.csproj +++ /dev/null @@ -1,182 +0,0 @@ - - - - - Debug - AnyCPU - {60054FD9-4472-4BB4-9E3D-2F80D3D22468} - Library - Properties - GameRes.Extra - ArcExtra - v4.6 - 512 - d57ff7cf - ..\ - - true - - - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - 16777216 - true - - - none - true - ..\bin\Release\ - - - prompt - 4 - 16777216 - true - - - ..\bin\Prerelease\ - 16777216 - true - true - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\packages\Concentus.1.1.7\lib\portable-net45+win+wpa81+wp80\Concentus.dll - - - ..\packages\Concentus.OggFile.1.0.3\lib\portable-net45+win+wpa81+wp80\Concentus.Oggfile.dll - - - ..\packages\MSFTCompressionCab.1.0.0\lib\Microsoft.Deployment.Compression.dll - - - ..\packages\MSFTCompressionCab.1.0.0\lib\Microsoft.Deployment.Compression.Cab.dll - - - - - - - ..\packages\System.Data.SQLite.Core.1.0.109.2\lib\net46\System.Data.SQLite.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - {a8865685-27cc-427b-ac38-e48d2ad05df4} - ArcFormats - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - - - - - - PreserveNewest - - - PreserveNewest - - - - - - IPT.parser - - - True - True - IPT.Language.grammar.y - - - IPT.parser - - - True - True - IPT.Language.analyzer.lex - - - IPT.parser - - - IPT.parser - - - - - ipt - - - - perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) -exit 0 - - - $(SolutionDir)packages\YaccLexTools.0.2.2\tools\ - "$(YltTools)gplex.exe" - "$(YltTools)gppg.exe" - - - $(ProjectDir)Artemis\IPT - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Experimental/Properties/AssemblyInfo.cs b/Experimental/Properties/AssemblyInfo.cs index 99544193..0b8878c9 100644 --- a/Experimental/Properties/AssemblyInfo.cs +++ b/Experimental/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.0.16.39")] -[assembly: AssemblyFileVersion ("1.0.16.39")] +[assembly: AssemblyVersion ("1.0.16.42")] +[assembly: AssemblyFileVersion ("1.0.16.42")] diff --git a/Experimental/RPGMaker/ImageRPGMV.cs b/Experimental/RPGMaker/ImageRPGMV.cs index 5a01ca04..f431941f 100644 --- a/Experimental/RPGMaker/ImageRPGMV.cs +++ b/Experimental/RPGMaker/ImageRPGMV.cs @@ -28,7 +28,8 @@ using System.ComponentModel.Composition; using System.IO; using System.Text; -using System.Web.Script.Serialization; +using Newtonsoft.Json; +//using System.Web.Script.Serialization; namespace GameRes.Formats.RPGMaker { @@ -124,8 +125,11 @@ static int HexToInt (char x) static byte[] ParseSystemJson (string filename) { var json = File.ReadAllText (filename, Encoding.UTF8); - var serializer = new JavaScriptSerializer(); - var sys = serializer.DeserializeObject (json) as IDictionary; + //var serializer = new JavaScriptSerializer(); + //var sys = serializer.DeserializeObject (json) as IDictionary; + + + var sys = JsonConvert.DeserializeObject(json); if (null == sys) return null; var key = sys["encryptionKey"] as string; diff --git a/GARbro.sln b/GARbro.sln index 1fb08ac8..89e7b995 100644 --- a/GARbro.sln +++ b/GARbro.sln @@ -1,35 +1,27 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30309.148 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GARbro.Console", "Console\GARbro.Console.csproj", "{B966F292-431A-4D8A-A1D3-1EB45048A1D2}" - ProjectSection(ProjectDependencies) = postProject - {453C087F-E416-4AE9-8C03-D8760DA0574B} = {453C087F-E416-4AE9-8C03-D8760DA0574B} - {A8865685-27CC-427B-AC38-E48D2AD05DF4} = {A8865685-27CC-427B-AC38-E48D2AD05DF4} - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchemeBuilder", "SchemeBuilder\SchemeBuilder.csproj", "{B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArcFormats", "ArcFormats\ArcFormats.csproj", "{A8865685-27CC-427B-AC38-E48D2AD05DF4}" - ProjectSection(ProjectDependencies) = postProject - {453C087F-E416-4AE9-8C03-D8760DA0574B} = {453C087F-E416-4AE9-8C03-D8760DA0574B} - EndProjectSection +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LegacyNet", "LegacyNet", "{015EA4FF-2464-4B20-B041-C4318FBC2696}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameRes", "GameRes\GameRes.csproj", "{453C087F-E416-4AE9-8C03-D8760DA0574B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameRes.Core", "GameRes\GameRes.Core.csproj", "{448E105D-CCD3-4465-85B2-722CB83F036F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GARbro.GUI", "GUI\GARbro.GUI.csproj", "{2935BE57-C4E0-43E7-86DE-C1848C820B19}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArcFormats.Core", "ArcFormats\ArcFormats.Core.csproj", "{98175244-F4FB-42DA-A1FD-09D281081BC9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Image.Convert", "Image.Convert\Image.Convert.csproj", "{757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}" - ProjectSection(ProjectDependencies) = postProject - {A8865685-27CC-427B-AC38-E48D2AD05DF4} = {A8865685-27CC-427B-AC38-E48D2AD05DF4} - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Experimental.Core", "Experimental\Experimental.Core.csproj", "{DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchemeBuilder", "SchemeBuilder\SchemeBuilder.csproj", "{B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Net20.Core", "Net20\Net20.Core.csproj", "{ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Legacy.Core", "Legacy\Legacy.Core.csproj", "{114050BF-CB4E-4296-8D09-C96A24903167}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Experimental", "Experimental\Experimental.csproj", "{60054FD9-4472-4BB4-9E3D-2F80D3D22468}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GARbro.GUI.Core", "GUI\GARbro.GUI.Core.csproj", "{AA001966-9A17-4843-84E1-19142C3BE1C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Legacy", "Legacy\Legacy.csproj", "{C79E82A8-8D32-485D-8442-2D4F71FBB5D5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Image.Convert.Core", "Image.Convert\Image.Convert.Core.csproj", "{96C528AB-1794-44FF-B656-C5BF8552A712}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Net20", "Net20\Net20.csproj", "{73B6C693-9846-4D33-8300-A80239FCFFF9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GARbro.Console.Core", "Console\GARbro.Console.Core.csproj", "{62AACEB7-B1F3-421B-A3CE-0107B5C44041}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -38,52 +30,66 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Release|Any CPU.Build.0 = Release|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {453C087F-E416-4AE9-8C03-D8760DA0574B}.Release|Any CPU.Build.0 = Release|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Release|Any CPU.Build.0 = Release|Any CPU - {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU {B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD}.Release|Any CPU.Build.0 = Release|Any CPU - {60054FD9-4472-4BB4-9E3D-2F80D3D22468}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60054FD9-4472-4BB4-9E3D-2F80D3D22468}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {60054FD9-4472-4BB4-9E3D-2F80D3D22468}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60054FD9-4472-4BB4-9E3D-2F80D3D22468}.Release|Any CPU.Build.0 = Release|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5}.Release|Any CPU.Build.0 = Release|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73B6C693-9846-4D33-8300-A80239FCFFF9}.Release|Any CPU.Build.0 = Release|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {448E105D-CCD3-4465-85B2-722CB83F036F}.Release|Any CPU.Build.0 = Release|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98175244-F4FB-42DA-A1FD-09D281081BC9}.Release|Any CPU.Build.0 = Release|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFCD3DB2-04F9-4A3C-AEBB-B85203A02FB1}.Release|Any CPU.Build.0 = Release|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED42A0E2-176C-446A-BAB6-72ACC6F1BD81}.Release|Any CPU.Build.0 = Release|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Debug|Any CPU.Build.0 = Debug|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Release|Any CPU.ActiveCfg = Release|Any CPU + {114050BF-CB4E-4296-8D09-C96A24903167}.Release|Any CPU.Build.0 = Release|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA001966-9A17-4843-84E1-19142C3BE1C5}.Release|Any CPU.Build.0 = Release|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96C528AB-1794-44FF-B656-C5BF8552A712}.Release|Any CPU.Build.0 = Release|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Prerelease|Any CPU.Build.0 = Debug|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62AACEB7-B1F3-421B-A3CE-0107B5C44041}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B7E7EBFB-C06E-4FC8-9AF2-7CD132AB15FD} = {015EA4FF-2464-4B20-B041-C4318FBC2696} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9DCBA24E-9BB5-49C5-B311-ADF3B5C274CC} + EndGlobalSection EndGlobal diff --git a/GUI/App.xaml.cs b/GUI/App.xaml.cs index 56a9024d..21e9d3d2 100644 --- a/GUI/App.xaml.cs +++ b/GUI/App.xaml.cs @@ -81,6 +81,8 @@ void ApplicationStartup (object sender, StartupEventArgs e) DeserializeScheme (Path.Combine (FormatCatalog.Instance.DataDirectory, FormatsDat)); DeserializeScheme (Path.Combine (GetLocalAppDataFolder(), FormatsDat)); + + System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); } public string GetLocalAppDataFolder () diff --git a/GUI/AutoComplete.cs b/GUI/AutoComplete.cs index 72c713d5..6fce684e 100644 --- a/GUI/AutoComplete.cs +++ b/GUI/AutoComplete.cs @@ -29,69 +29,119 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using AutoCompleteTextBox.Editors; namespace GARbro.GUI { /// /// TextBox that uses filesystem as source for autocomplete. /// - public class ExtAutoCompleteBox : AutoCompleteBox + public class ExtAutoCompleteBox : AutoCompleteTextBox.Editors.AutoCompleteTextBox { - public delegate void EnterKeyDownEvent (object sender, KeyEventArgs e); + public delegate void EnterKeyDownEvent(object sender, KeyEventArgs e); public event EnterKeyDownEvent EnterKeyDown; + public event TextChangedEventHandler TextChanged; - public ExtAutoCompleteBox () + //public TextBox Editor { get; set; } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + //Editor = Template.FindName(PartEditor, this) as TextBox; + + if (Editor != null) + { + Editor.TextChanged += OnEditorTextChanged; + } + } + + public ExtAutoCompleteBox() { this.GotFocus += (s, e) => { IsTextBoxFocused = true; }; this.LostFocus += (s, e) => { IsTextBoxFocused = false; }; - } + Provider = new SuggestionProvider(x => + { + List candidates = new List(); + + try + { + if (!GameRes.VFS.IsVirtual && IsTextBoxFocused) + { + + this.Dispatcher.Invoke(() => + { + string dirname = Path.GetDirectoryName(Editor.Text); + if (!string.IsNullOrEmpty(dirname) && Directory.Exists(dirname)) + { + foreach (var dir in Directory.GetDirectories(dirname)) + { + if (dir.StartsWith(dirname, StringComparison.CurrentCultureIgnoreCase)) + candidates.Add(dir); + } + } + }); + + } + } + catch + { + } + + return candidates; + }); + } + private void OnEditorTextChanged(object sender, TextChangedEventArgs e) + { + TextChanged?.Invoke(sender, e); + } public bool IsTextBoxFocused { - get { return (bool)GetValue (HasFocusProperty); } - private set { SetValue (HasFocusProperty, value); } + get { return (bool)GetValue(HasFocusProperty); } + private set { SetValue(HasFocusProperty, value); } } - public static readonly DependencyProperty HasFocusProperty = - DependencyProperty.RegisterAttached ("IsTextBoxFocused", typeof(bool), typeof(ExtAutoCompleteBox), new UIPropertyMetadata()); + public static readonly DependencyProperty HasFocusProperty = + DependencyProperty.RegisterAttached("IsTextBoxFocused", typeof(bool), typeof(ExtAutoCompleteBox), new UIPropertyMetadata()); - protected override void OnKeyDown (KeyEventArgs e) + protected override void OnKeyDown(KeyEventArgs e) { - base.OnKeyDown (e); + base.OnKeyDown(e); if (e.Key == Key.Enter) - RaiseEnterKeyDownEvent (e); + RaiseEnterKeyDownEvent(e); } - private void RaiseEnterKeyDownEvent (KeyEventArgs e) + private void RaiseEnterKeyDownEvent(KeyEventArgs e) { if (EnterKeyDown != null) - EnterKeyDown (this, e); + EnterKeyDown(this, e); } - protected override void OnPopulating (PopulatingEventArgs e) - { - try - { - if (!GameRes.VFS.IsVirtual) - { - var candidates = new List(); - string dirname = Path.GetDirectoryName (this.Text); - if (!string.IsNullOrEmpty (dirname) && Directory.Exists (dirname)) - { - foreach (var dir in Directory.GetDirectories (dirname)) - { - if (dir.StartsWith (dirname, StringComparison.CurrentCultureIgnoreCase)) - candidates.Add (dir); - } - } - this.ItemsSource = candidates; - } - } - catch - { - // ignore filesystem errors - } - base.OnPopulating (e); - } + //protected override void OnPopulating(PopulatingEventArgs e) + //{ + // try + // { + // if (!GameRes.VFS.IsVirtual) + // { + // var candidates = new List(); + // string dirname = Path.GetDirectoryName(this.Text); + // if (!string.IsNullOrEmpty(dirname) && Directory.Exists(dirname)) + // { + // foreach (var dir in Directory.GetDirectories(dirname)) + // { + // if (dir.StartsWith(dirname, StringComparison.CurrentCultureIgnoreCase)) + // candidates.Add(dir); + // } + // } + // this.ItemsSource = candidates; + // } + // } + // catch + // { + // // ignore filesystem errors + // } + // base.OnPopulating(e); + //} } } diff --git a/GUI/ExtractDialog.cs b/GUI/ExtractDialog.cs index a45bca02..a22e7a64 100644 --- a/GUI/ExtractDialog.cs +++ b/GUI/ExtractDialog.cs @@ -98,7 +98,7 @@ public string ChooseFolder (string title, string initial) protected void acb_OnEnterKeyDown (object sender, KeyEventArgs e) { - string path = (sender as AutoCompleteBox).Text; + string path = (sender as AutoCompleteTextBox.Editors.AutoCompleteTextBox).Editor.Text; if (!string.IsNullOrEmpty (path)) this.DialogResult = true; } diff --git a/GUI/GARbro.GUI.Core.csproj b/GUI/GARbro.GUI.Core.csproj new file mode 100644 index 00000000..5e5d6b69 --- /dev/null +++ b/GUI/GARbro.GUI.Core.csproj @@ -0,0 +1,113 @@ + + + + WinExe + netcoreapp3.1 + true + GARbro.GUI + GARbro.GUI + false + Images\sample.ico + Properties\app.manifest + + + + DEBUG;TRACE;NETCORE + false + ..\bin\Debug\ + + + + TRACE;NETCORE + ..\bin\Release\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + Never + + + + + + True + True + Settings.settings + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + \ No newline at end of file diff --git a/GUI/GARbro.GUI.csproj b/GUI/GARbro.GUI.csproj deleted file mode 100644 index 22b36cf9..00000000 --- a/GUI/GARbro.GUI.csproj +++ /dev/null @@ -1,362 +0,0 @@ - - - - - Debug - AnyCPU - {2935BE57-C4E0-43E7-86DE-C1848C820B19} - WinExe - Properties - GARbro.GUI - GARbro.GUI - v4.6 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - false - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.1.%2a - false - true - true - ..\ - true - - - AnyCPU - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - none - true - ..\bin\Release\ - - - prompt - 4 - false - - - Images\sample.ico - - - 751F4A9FD4F4CC3D99D70509FF1F9D9CC9E49516 - - - GARbro.GUI_TemporaryKey.pfx - - - false - - - LocalIntranet - - - - true - - - Properties\app.manifest - - - ..\bin\Prerelease\ - true - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - ..\packages\WindowsAPICodePack-Core.1.1.2\lib\Microsoft.WindowsAPICodePack.dll - True - - - ..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll - True - - - ..\packages\NAudio.1.8.4\lib\net35\NAudio.dll - True - - - - - ..\packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Input.Toolkit.dll - True - - - - - - - - 4.0 - - - - - - ..\packages\WPFToolkit.3.5.50211.1\lib\WPFToolkit.dll - True - - - - - MSBuild:Compile - Designer - - - AboutBox.xaml - - - ArcParameters.xaml - - - - ConvertMedia.xaml - - - CreateArchive.xaml - - - - EnterMaskDialog.xaml - - - ExtractArchive.xaml - - - - ExtractFile.xaml - - - FileErrorDialog.xaml - - - FileExistsDialog.xaml - - - - - - - Component - - - - - - - - - Component - - - - SettingsWindow.xaml - - - - True - True - guiStrings.resx - - - TextViewer.xaml - - - TroubleShootingDialog.xaml - - - UpdateDialog.xaml - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - Code - - - True - Settings.settings - True - - - - - PublicResXFileCodeGenerator - guiStrings.Designer.cs - - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - Designer - - - - - - - - - - - - - - - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - False - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - - - - - - - perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) "$(SolutionDir)\" -exit 0 - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/GUI/GARbro.GUI.csproj.user b/GUI/GARbro.GUI.csproj.user deleted file mode 100644 index 0e581867..00000000 --- a/GUI/GARbro.GUI.csproj.user +++ /dev/null @@ -1,17 +0,0 @@ - - - - publish\ - - - - - - en-US - false - - - - - - \ No newline at end of file diff --git a/GUI/MainWindow.xaml.cs b/GUI/MainWindow.xaml.cs index 31dfefa6..290ef1af 100644 --- a/GUI/MainWindow.xaml.cs +++ b/GUI/MainWindow.xaml.cs @@ -738,7 +738,7 @@ private void acb_OnKeyDown (object sender, KeyEventArgs e) { if (e.Key != Key.Return) return; - string path = (sender as AutoCompleteBox).Text; + string path = (sender as AutoCompleteTextBox.Editors.AutoCompleteTextBox).Editor.Text; path = path.Trim (' ', '"'); if (string.IsNullOrEmpty (path)) return; diff --git a/GUI/Properties/AssemblyInfo.cs b/GUI/Properties/AssemblyInfo.cs index abb91452..6a8b735d 100644 --- a/GUI/Properties/AssemblyInfo.cs +++ b/GUI/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -51,5 +51,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.5.44.2904")] -[assembly: AssemblyFileVersion ("1.5.44.2904")] +[assembly: AssemblyVersion ("1.5.44.2934")] +[assembly: AssemblyFileVersion ("1.5.44.2934")] diff --git a/GUI/Properties/Settings.Designer.cs b/GUI/Properties/Settings.Designer.cs index 6f9fc681..062dd117 100644 --- a/GUI/Properties/Settings.Designer.cs +++ b/GUI/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace GARbro.GUI.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/GameRes/ArcView.cs b/GameRes/ArcView.cs index 66747307..22137650 100644 --- a/GameRes/ArcView.cs +++ b/GameRes/ArcView.cs @@ -144,7 +144,7 @@ public ArcView (Stream input, string name, uint length) private void InitFromFileStream (FileStream fs, uint length) { m_map = MemoryMappedFile.CreateFromFile (fs, null, length, - MemoryMappedFileAccess.Read, null, HandleInheritability.None, true); + MemoryMappedFileAccess.Read/*, null*/, HandleInheritability.None, true); try { View = new Frame (this); } catch { @@ -156,7 +156,7 @@ private void InitFromFileStream (FileStream fs, uint length) private void InitFromStream (Stream input, uint length) { m_map = MemoryMappedFile.CreateNew (null, length, MemoryMappedFileAccess.ReadWrite, - MemoryMappedFileOptions.None, null, HandleInheritability.None); + MemoryMappedFileOptions.None/*, null*/, HandleInheritability.None); try { using (var view = m_map.CreateViewAccessor (0, length, MemoryMappedFileAccess.Write)) diff --git a/GameRes/GameRes.Core.csproj b/GameRes/GameRes.Core.csproj new file mode 100644 index 00000000..a81d88c8 --- /dev/null +++ b/GameRes/GameRes.Core.csproj @@ -0,0 +1,52 @@ + + + + netcoreapp3.1 + GameRes + GameRes + true + false + + + + TRACE;DEBUG;NETCORE + true + ..\bin\Debug\ + + + + ..\bin\Release\ + DEBUG;TRACE;NETCORE + true + + + + + + + + + + + + + + + True + True + garStrings.resx + + + + + + PublicResXFileCodeGenerator + garStrings.Designer.cs + + + + + + + + diff --git a/GameRes/GameRes.csproj b/GameRes/GameRes.csproj deleted file mode 100644 index 66ded7b1..00000000 --- a/GameRes/GameRes.csproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - - Debug - AnyCPU - {453C087F-E416-4AE9-8C03-D8760DA0574B} - Library - Properties - GameRes - GameRes - v4.6 - 512 - - ..\ - true - - - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - true - - - none - true - ..\bin\Release\ - - - prompt - 4 - false - true - - - ..\bin\Prerelease\ - true - true - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\packages\NAudio.1.8.4\lib\net35\NAudio.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Settings.settings - - - - - - True - True - garStrings.resx - - - - - - - - - - - - - PublicResXFileCodeGenerator - garStrings.Designer.cs - - - - - - - - - PublicSettingsSingleFileGenerator - Settings.Designer.cs - - - - - perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) -exit 0 - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/GameRes/Properties/AssemblyInfo.cs b/GameRes/Properties/AssemblyInfo.cs index 67bc98cf..d508ecdd 100644 --- a/GameRes/Properties/AssemblyInfo.cs +++ b/GameRes/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.5.44.319")] -[assembly: AssemblyFileVersion ("1.5.44.319")] +[assembly: AssemblyVersion ("1.5.44.324")] +[assembly: AssemblyFileVersion ("1.5.44.324")] diff --git a/GameRes/Strings/garStrings.Designer.cs b/GameRes/Strings/garStrings.Designer.cs index 0872a82d..d7913ddf 100644 --- a/GameRes/Strings/garStrings.Designer.cs +++ b/GameRes/Strings/garStrings.Designer.cs @@ -19,7 +19,7 @@ namespace GameRes.Strings { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class garStrings { diff --git a/Image.Convert/Image.Convert.Core.csproj b/Image.Convert/Image.Convert.Core.csproj new file mode 100644 index 00000000..9a416625 --- /dev/null +++ b/Image.Convert/Image.Convert.Core.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp3.1 + false + Image.Convert + Image.Convert + Exe + + + + ..\bin\Debug\ + TRACE;DEBUG;NETCORE + + + + ..\bin\Release\ + TRACE;NETCORE + + + + + + + diff --git a/Image.Convert/Image.Convert.csproj b/Image.Convert/Image.Convert.csproj deleted file mode 100644 index 668b61d3..00000000 --- a/Image.Convert/Image.Convert.csproj +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Debug - AnyCPU - {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E} - Exe - Properties - Image.Convert - Image.Convert - v4.6 - 512 - - - - AnyCPU - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - ..\bin\Release\ - TRACE - prompt - 4 - false - - - true - - - ..\bin\Prerelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - - - - - \ No newline at end of file diff --git a/Image.Convert/Image.Convert.csproj.user b/Image.Convert/Image.Convert.csproj.user deleted file mode 100644 index 154d74d4..00000000 --- a/Image.Convert/Image.Convert.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - -t tga uninstall.hg3 - - \ No newline at end of file diff --git a/Legacy/Legacy.Core.csproj b/Legacy/Legacy.Core.csproj new file mode 100644 index 00000000..27a5bc7e --- /dev/null +++ b/Legacy/Legacy.Core.csproj @@ -0,0 +1,46 @@ + + + + netcoreapp3.1 + ArcLegacy + GameRes.Legacy + true + false + + + + TRACE;DEBUG;NETCORE + true + ..\bin\Debug\ + + + + TRACE;NETCORE + true + ..\bin\Release\ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Legacy/Legacy.csproj b/Legacy/Legacy.csproj deleted file mode 100644 index 20ffc4ce..00000000 --- a/Legacy/Legacy.csproj +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Debug - AnyCPU - {C79E82A8-8D32-485D-8442-2D4F71FBB5D5} - Library - Properties - GameRes.Legacy - ArcLegacy - v4.6 - 512 - - - - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - pdbonly - true - ..\bin\Release\ - - - prompt - 4 - true - - - bin\Prerelease\ - TRACE - true - pdbonly - AnyCPU - prompt - MinimumRecommendedRules.ruleset - true - - - - False - ..\packages\SharpZipLib.1.1.0\lib\net45\ICSharpCode.SharpZipLib.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {a8865685-27cc-427b-ac38-e48d2ad05df4} - ArcFormats - - - {453c087f-e416-4ae9-8c03-d8760da0574b} - GameRes - - - - - - - - - perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName) -exit 0 - - - \ No newline at end of file diff --git a/Legacy/Properties/AssemblyInfo.cs b/Legacy/Properties/AssemblyInfo.cs index d039f8ff..2b29d4f2 100644 --- a/Legacy/Properties/AssemblyInfo.cs +++ b/Legacy/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.0.10.196")] -[assembly: AssemblyFileVersion ("1.0.10.196")] +[assembly: AssemblyVersion ("1.0.10.199")] +[assembly: AssemblyFileVersion ("1.0.10.199")] diff --git a/Net20/Net20.Core.csproj b/Net20/Net20.Core.csproj new file mode 100644 index 00000000..98e10257 --- /dev/null +++ b/Net20/Net20.Core.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1 + Net20 + GameRes.Net20 + false + + + + DEBUG;TRACE;NETCORE + true + ..\bin\Debug\ + + + + TRACE;NETCORE + true + ..\bin\Release\ + + + diff --git a/Net20/Net20.csproj b/Net20/Net20.csproj deleted file mode 100644 index 7191d81b..00000000 --- a/Net20/Net20.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Debug - AnyCPU - {73B6C693-9846-4D33-8300-A80239FCFFF9} - Library - Properties - GameRes.Net20 - Net20 - v2.0 - 512 - - - - true - full - false - ..\bin\Debug\ - DEBUG;TRACE - prompt - 4 - 301989888 - - - pdbonly - true - ..\bin\Release\ - - - prompt - 4 - 301989888 - - - ..\bin\Prerelease\ - true - 301989888 - - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 7fc28b84..ec753b2a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ GARbro Visual Novels resource browser. -Requires .NET Framework v4.6 or newer (https://www.microsoft.com/net) +Requires .NET core 3.1 (https://www.microsoft.com/net) [Supported formats](https://morkt.github.io/GARbro/supported.html) diff --git a/inc-revision.csx b/inc-revision.csx new file mode 100644 index 00000000..93ce8fbf --- /dev/null +++ b/inc-revision.csx @@ -0,0 +1,140 @@ +#! dotnet-script +#r "System.ValueTuple" +// increment .Net assembly revision +using System; +using System.IO; +using System.Text.RegularExpressions; + +static string IDX(this IList args, int index) => index >= args.Count ? null : args[index]; +Match match_version(string s) => new Regex(@"^(\d+)\.(\d+)(?:\.(\d+)\.(\d+))?").Match(s); + +if (Args.Count < 1) +{ + Console.WriteLine("usage: inc-revision.csx PROJECT-FILE CONFIG [ROOT-DIR]\n"); + Environment.Exit(0); +} + +(string project_path, string config, string root_dir) = (Args.IDX(0), Args.IDX(1), Args.IDX(2)); + +var project_dir = new DirectoryInfo(project_path).Parent.FullName; +if (string.IsNullOrEmpty(root_dir)) +{ + root_dir = project_dir; +} +var is_release = ("release" == config.ToLower()); +// try +// { +// Directory.SetCurrentDirectory(root_dir); +// } +// catch (System.Exception) +// { +// throw new Exception($"{root_dir}"); +// } + + +var proc = new Process +{ + StartInfo = new ProcessStartInfo + { + FileName = "git", + Arguments = "rev-list HEAD --count .", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + WorkingDirectory = root_dir + } +}; + +try +{ + proc.Start(); +} +catch (System.Exception) +{ + throw new Exception("Git not found"); +} + +string revision = proc.StandardOutput.ReadLine(); +proc.WaitForExit(); +if (proc.ExitCode != 0) +{ + throw new Exception("git.exe failed"); +} +var prop_dir = Path.Combine(project_dir, "Properties"); +var assembly_info = Path.Combine(project_dir, "Properties", "AssemblyInfo.cs"); + + + +var version_changed = false; +string tmp_filename; +StreamWriter tmp_output; +{ + var assembly_file = File.OpenText(assembly_info); + tmp_filename = Path.Combine(prop_dir, Guid.NewGuid().ToString()); + + tmp_output = File.CreateText(tmp_filename); + + string line; + var r = new Regex(@"^\[assembly:\s*(Assembly(?:File)?Version)\s*\(""(.*?)""\)\]"); + + while ((line = assembly_file.ReadLine()) != null) + { + if (r.IsMatch(line)) + { + var match = r.Match(line); + (string attr, string version) = (match.Groups[1].Value, match.Groups[2].Value); + var mv = match_version(version); + (int major, int minor, int build, int rev) = (Convert.ToInt32(mv.Groups[1].Value), Convert.ToInt32(mv.Groups[2].Value), Convert.ToInt32(mv.Groups[3].Value), Convert.ToInt32(mv.Groups[4].Value)); + if (is_release) + { + build += 1; + } + + var new_version = $"{major}.{minor}.{build}.{revision}"; + line = $"[assembly: {attr} (\"{new_version}\")]"; + + if (attr == "AssemblyVersion") + { + Console.WriteLine($"AssemblyVersion: {new_version}"); + } + version_changed |= (version != new_version); + } + tmp_output.WriteLine(line); + } + + assembly_file.Close(); +} +tmp_output.Flush(); +tmp_output.Close(); +if (version_changed) +{ + try + { + File.Delete($"{assembly_info}~"); + File.Move(assembly_info, $"{assembly_info}~"); + } + catch (System.Exception) + { + throw new Exception(assembly_info); + } + try + { + File.Move(tmp_filename, assembly_info); + } + catch (System.Exception) + { + throw new Exception(tmp_filename); + } +} +else +{ + try + { + File.Delete($"{assembly_info}~"); + File.Delete(tmp_filename); + } + catch (System.Exception) + { + throw new Exception(tmp_filename); + } +} \ No newline at end of file diff --git a/inc-revision.pl b/inc-revision.pl deleted file mode 100644 index 3f204f97..00000000 --- a/inc-revision.pl +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/perl -# -# increment .Net assembly revision - -use strict; -use Win32; -use File::Basename; -use File::Spec; -use File::Temp; - -sub get_git_exe { - my $user_app_data = Win32::GetFolderPath (Win32::CSIDL_LOCAL_APPDATA); - my $git_glob = File::Spec->catfile ($user_app_data, 'GitHub', 'PortableGit_*', 'cmd', 'git.exe'); - my $git_path = glob ($git_glob); - die "PortableGit not found\n" unless -x $git_path; - return $git_path; -} - -sub match_version { - return $_[0] =~ /^(\d+)\.(\d+)(?:\.(\d+)\.(\d+))?/; -} - -if ($#ARGV < 1) { - print "usage: inc-revision.pl PROJECT-FILE CONFIG [ROOT-DIR]\n"; - exit 0; -} - -my ($project_path, $config, $root_dir) = @ARGV; -my $project_dir = dirname ($project_path); -$root_dir //= $project_dir; -my $is_release = 'release' eq lc $config; -chdir $root_dir or die "$root_dir: $!\n"; - -my $git_exe = get_git_exe; -my $revision = `$git_exe rev-list HEAD --count .`; -die "git.exe failed\n" if $? != 0; -my $prop_dir = File::Spec->catfile ($project_dir, 'Properties'); -my $assembly_info = File::Spec->catfile ($prop_dir, 'AssemblyInfo.cs'); -chomp $revision; - -my $version_changed = 0; -my $tmp_filename; -{ - open (my $assembly_file, '<', $assembly_info) or die "${assembly_info}: $!"; - my $tmp_output = File::Temp->new (DIR => $prop_dir, UNLINK => 0); - $tmp_filename = $tmp_output->filename; - binmode ($tmp_output, ':crlf'); - - while (<$assembly_file>) { - m,^//, and next; - /^\[assembly:\s*(Assembly(?:File)?Version)\s*\("(.*?)"\)\]/ and do { - my ($attr, $version) = ($1, $2); - my ($major, $minor, $build, $rev) = match_version ($version); - $build += 1 if $is_release; - my $new_version = "${major}.${minor}.${build}.${revision}"; - $_ = "[assembly: ${attr} (\"${new_version}\")]\n"; - print "AssemblyVersion: $new_version\n" if $attr eq 'AssemblyVersion'; - $version_changed ||= $version ne $new_version; - }; - } continue { - print $tmp_output $_; - } -} - -if ($version_changed) { - rename $assembly_info, "${assembly_info}~" or die "${assembly_info}: $!"; - rename $tmp_filename, $assembly_info or die "${tmp_filename}: $!"; -} else { - unlink $tmp_filename; -}