mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-11 18:54:55 +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\UshortExtensions.cs" />
|
||||
<Compile Include="IcdUriBuilder.cs" />
|
||||
<Compile Include="IO\Compression\IcdZipEntry.cs" />
|
||||
<Compile Include="IO\IcdBinaryReader.cs" />
|
||||
<Compile Include="IO\eSeekOrigin.cs" />
|
||||
<Compile Include="ProcessorUtils.SimplSharp.cs" />
|
||||
@@ -124,7 +125,7 @@
|
||||
<Compile Include="IcdEnvironment.cs" />
|
||||
<Compile Include="IcdEnvironment.SimplSharp.cs" />
|
||||
<Compile Include="IcdEnvironment.Standard.cs" />
|
||||
<Compile Include="IcdZip.cs" />
|
||||
<Compile Include="IO\Compression\IcdZip.cs" />
|
||||
<Compile Include="IO\IcdDirectory.cs" />
|
||||
<Compile Include="EnumUtils.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