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;
-}