mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-16 13:15:07 +00:00
feat: Adding methods for inspecting contents of a ZIP file
This commit is contained in:
@@ -98,6 +98,7 @@
|
|||||||
<Compile Include="Extensions\UriExtensions.cs" />
|
<Compile Include="Extensions\UriExtensions.cs" />
|
||||||
<Compile Include="Extensions\UshortExtensions.cs" />
|
<Compile Include="Extensions\UshortExtensions.cs" />
|
||||||
<Compile Include="IcdUriBuilder.cs" />
|
<Compile Include="IcdUriBuilder.cs" />
|
||||||
|
<Compile Include="IO\Compression\IcdZipEntry.cs" />
|
||||||
<Compile Include="IO\IcdBinaryReader.cs" />
|
<Compile Include="IO\IcdBinaryReader.cs" />
|
||||||
<Compile Include="IO\eSeekOrigin.cs" />
|
<Compile Include="IO\eSeekOrigin.cs" />
|
||||||
<Compile Include="ProcessorUtils.SimplSharp.cs" />
|
<Compile Include="ProcessorUtils.SimplSharp.cs" />
|
||||||
@@ -124,7 +125,7 @@
|
|||||||
<Compile Include="IcdEnvironment.cs" />
|
<Compile Include="IcdEnvironment.cs" />
|
||||||
<Compile Include="IcdEnvironment.SimplSharp.cs" />
|
<Compile Include="IcdEnvironment.SimplSharp.cs" />
|
||||||
<Compile Include="IcdEnvironment.Standard.cs" />
|
<Compile Include="IcdEnvironment.Standard.cs" />
|
||||||
<Compile Include="IcdZip.cs" />
|
<Compile Include="IO\Compression\IcdZip.cs" />
|
||||||
<Compile Include="IO\IcdDirectory.cs" />
|
<Compile Include="IO\IcdDirectory.cs" />
|
||||||
<Compile Include="EnumUtils.cs" />
|
<Compile Include="EnumUtils.cs" />
|
||||||
<Compile Include="Extensions\AssemblyExtensions.cs" />
|
<Compile Include="Extensions\AssemblyExtensions.cs" />
|
||||||
|
|||||||
163
ICD.Common.Utils/IO/Compression/IcdZip.cs
Normal file
163
ICD.Common.Utils/IO/Compression/IcdZip.cs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
#if SIMPLSHARP
|
||||||
|
|
||||||
|
#else
|
||||||
|
using System.IO.Compression;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ICD.Common.Utils.IO.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utils for managing archives.
|
||||||
|
/// </summary>
|
||||||
|
public static class IcdZip
|
||||||
|
{
|
||||||
|
private const int DIRECTORY_SIGNATURE = 0x06054B50;
|
||||||
|
private const int ENTRY_SIGNATURE = 0x02014B50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unzips the archive at the given path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="outputPath"></param>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public static bool Unzip(string path, string outputPath, out string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if SIMPLSHARP
|
||||||
|
CrestronZIP.ResultCode result = CrestronZIP.Unzip(path, outputPath);
|
||||||
|
message = result.ToString();
|
||||||
|
return result == CrestronZIP.ResultCode.ZR_OK;
|
||||||
|
#else
|
||||||
|
using (ZipArchive archive = ZipFile.Open(path, ZipArchiveMode.Read))
|
||||||
|
archive.ExtractToDirectory(outputPath);
|
||||||
|
message = "Success";
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
message = e.Message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sequence of files names in the archive at the given path.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<string> GetFileNames(string path)
|
||||||
|
{
|
||||||
|
return GetEntries(path).Select(e => e.Name)
|
||||||
|
.Where(f => !f.EndsWith("/"))
|
||||||
|
.OrderBy(f => f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets sequence of zip file entries in the archive at the given path.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<IcdZipEntry> GetEntries(string path)
|
||||||
|
{
|
||||||
|
using (IcdStream stream = IcdFile.OpenRead(path))
|
||||||
|
{
|
||||||
|
using (IcdBinaryReader reader = new IcdBinaryReader(stream))
|
||||||
|
{
|
||||||
|
if (stream.Length < 22)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
stream.Seek(-22, eSeekOrigin.End.ToSeekOrigin());
|
||||||
|
|
||||||
|
// find directory signature
|
||||||
|
while (reader.ReadInt32() != DIRECTORY_SIGNATURE)
|
||||||
|
{
|
||||||
|
if (stream.Position <= 5)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
// move 1 byte back
|
||||||
|
stream.Seek(-5, eSeekOrigin.Current.ToSeekOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
|
// read directory properties
|
||||||
|
stream.Seek(6, eSeekOrigin.Current.ToSeekOrigin());
|
||||||
|
ushort entries = reader.ReadUInt16();
|
||||||
|
int difSize = reader.ReadInt32();
|
||||||
|
uint dirOffset = reader.ReadUInt32();
|
||||||
|
stream.Seek(dirOffset, eSeekOrigin.Begin.ToSeekOrigin());
|
||||||
|
|
||||||
|
// read directory entries
|
||||||
|
for (int i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
if (reader.ReadInt32() != ENTRY_SIGNATURE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// read file properties
|
||||||
|
reader.ReadInt32();
|
||||||
|
bool utf8 = (reader.ReadInt16() & 0x0800) != 0;
|
||||||
|
short method = reader.ReadInt16();
|
||||||
|
int timestamp = reader.ReadInt32();
|
||||||
|
uint crc32 = reader.ReadUInt32();
|
||||||
|
int compressedSize = reader.ReadInt32();
|
||||||
|
int fileSize = reader.ReadInt32();
|
||||||
|
short fileNameSize = reader.ReadInt16();
|
||||||
|
short extraSize = reader.ReadInt16();
|
||||||
|
short commentSize = reader.ReadInt16();
|
||||||
|
int headerOffset = reader.ReadInt32();
|
||||||
|
reader.ReadInt32();
|
||||||
|
int fileHeaderOffset = reader.ReadInt32();
|
||||||
|
byte[] fileNameBytes = reader.ReadBytes(fileNameSize);
|
||||||
|
stream.Seek(extraSize, eSeekOrigin.Current.ToSeekOrigin());
|
||||||
|
byte[] fileCommentBytes = reader.ReadBytes(commentSize);
|
||||||
|
int fileDataOffset = CalculateFileDataOffset(stream, reader, fileHeaderOffset);
|
||||||
|
|
||||||
|
// decode zip file entry
|
||||||
|
Encoding encoder = utf8 ? Encoding.UTF8 : Encoding.Default;
|
||||||
|
|
||||||
|
yield return new IcdZipEntry
|
||||||
|
{
|
||||||
|
Name = encoder.GetString(fileNameBytes, 0, fileNameBytes.Length),
|
||||||
|
Comment = encoder.GetString(fileCommentBytes, 0, fileCommentBytes.Length),
|
||||||
|
Crc32 = crc32,
|
||||||
|
CompressedSize = compressedSize,
|
||||||
|
OriginalSize = fileSize,
|
||||||
|
HeaderOffset = fileHeaderOffset,
|
||||||
|
DataOffset = fileDataOffset,
|
||||||
|
Deflated = method == 8,
|
||||||
|
Timestamp = ConvertToDateTime(timestamp)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CalculateFileDataOffset(IcdStream stream, IcdBinaryReader reader, int fileHeaderOffset)
|
||||||
|
{
|
||||||
|
long position = stream.Position;
|
||||||
|
stream.Seek(fileHeaderOffset + 26, eSeekOrigin.Begin.ToSeekOrigin());
|
||||||
|
short fileNameSize = reader.ReadInt16();
|
||||||
|
short extraSize = reader.ReadInt16();
|
||||||
|
|
||||||
|
int fileOffset = (int)stream.Position + fileNameSize + extraSize;
|
||||||
|
stream.Seek(position, eSeekOrigin.Begin.ToSeekOrigin());
|
||||||
|
return fileOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts DOS timestamp to a <see cref="DateTime"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dosTimestamp">The DOS timestamp.</param>
|
||||||
|
/// <returns>The <see cref="DateTime"/> instance.</returns>
|
||||||
|
private static DateTime ConvertToDateTime(int dosTimestamp)
|
||||||
|
{
|
||||||
|
return new DateTime((dosTimestamp >> 25) + 1980,
|
||||||
|
(dosTimestamp >> 21) & 15,
|
||||||
|
(dosTimestamp >> 16) & 31,
|
||||||
|
(dosTimestamp >> 11) & 31,
|
||||||
|
(dosTimestamp >> 5) & 63,
|
||||||
|
(dosTimestamp & 31) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
ICD.Common.Utils/IO/Compression/IcdZipEntry.cs
Normal file
59
ICD.Common.Utils/IO/Compression/IcdZipEntry.cs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ICD.Common.Utils.IO.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Zip archive entry.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class IcdZipEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of a file or a directory.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the comment.
|
||||||
|
/// </summary>
|
||||||
|
public string Comment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CRC32.
|
||||||
|
/// </summary>
|
||||||
|
public uint Crc32 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the compressed size of the file.
|
||||||
|
/// </summary>
|
||||||
|
public int CompressedSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the original size of the file.
|
||||||
|
/// </summary>
|
||||||
|
public int OriginalSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether this <see cref="IcdZipEntry" /> is deflated.
|
||||||
|
/// </summary>
|
||||||
|
public bool Deflated { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="IcdZipEntry" /> is a directory.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDirectory { get { return Name.EndsWith("/"); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the timestamp.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this <see cref="IcdZipEntry" /> is a file.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsFile { get { return !IsDirectory; } }
|
||||||
|
|
||||||
|
public int HeaderOffset { get; set; }
|
||||||
|
|
||||||
|
public int DataOffset { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
#if SIMPLSHARP
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
#else
|
|
||||||
using System.IO.Compression;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ICD.Common.Utils
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Utils for managing archives.
|
|
||||||
/// </summary>
|
|
||||||
public static class IcdZip
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Unzips the archive at the given path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path"></param>
|
|
||||||
/// <param name="outputPath"></param>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
public static bool Unzip(string path, string outputPath, out string message)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#if SIMPLSHARP
|
|
||||||
CrestronZIP.ResultCode result = CrestronZIP.Unzip(path, outputPath);
|
|
||||||
message = result.ToString();
|
|
||||||
return result == CrestronZIP.ResultCode.ZR_OK;
|
|
||||||
#else
|
|
||||||
using (ZipArchive archive = ZipFile.Open(path, ZipArchiveMode.Read))
|
|
||||||
archive.ExtractToDirectory(outputPath);
|
|
||||||
message = "Success";
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
message = e.Message;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user