Merge branch 'zip' of Common/Utils into dev

This commit is contained in:
Jeffery Thompson
2018-06-06 14:57:45 +00:00
committed by Gogs
8 changed files with 370 additions and 44 deletions

View File

@@ -98,6 +98,9 @@
<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" />
<Compile Include="ProcessorUtils.Standard.cs" />
<Compile Include="ProgramUtils.SimplSharp.cs" />
@@ -122,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" />

View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if SIMPLSHARP
using Crestron.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)
{
/*
Copyright (c) 2012-2013 Alexey Yakovlev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using (IcdStream stream = IcdFile.OpenRead(path))
{
using (IcdBinaryReader reader = new IcdBinaryReader(stream))
{
if (stream.Length < 22)
yield break;
stream.Seek(-22, eSeekOrigin.End);
// find directory signature
while (reader.ReadInt32() != DIRECTORY_SIGNATURE)
{
if (stream.Position <= 5)
yield break;
// move 1 byte back
stream.Seek(-5, eSeekOrigin.Current);
}
// read directory properties
stream.Seek(6, eSeekOrigin.Current);
ushort entries = reader.ReadUInt16();
int difSize = reader.ReadInt32();
uint dirOffset = reader.ReadUInt32();
stream.Seek(dirOffset, eSeekOrigin.Begin);
// 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);
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);
short fileNameSize = reader.ReadInt16();
short extraSize = reader.ReadInt16();
int fileOffset = (int)stream.Position + fileNameSize + extraSize;
stream.Seek(position, eSeekOrigin.Begin);
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);
}
}
}

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

View File

@@ -0,0 +1,69 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public sealed class IcdBinaryReader : IDisposable
{
private readonly BinaryReader m_Reader;
public BinaryReader WrappedReader { get { return m_Reader; } }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="stream"></param>
public IcdBinaryReader(IcdStream stream)
: this(new BinaryReader(stream.WrappedStream))
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="reader"></param>
public IcdBinaryReader(BinaryReader reader)
{
m_Reader = reader;
}
public void Dispose()
{
m_Reader.Dispose();
}
public void Close()
{
m_Reader.Close();
}
public ushort ReadUInt16()
{
return m_Reader.ReadUInt16();
}
public int ReadInt32()
{
return m_Reader.ReadInt32();
}
public short ReadInt16()
{
return m_Reader.ReadInt16();
}
public uint ReadUInt32()
{
return m_Reader.ReadUInt32();
}
public byte[] ReadBytes(short numberOfBytesToRead)
{
return m_Reader.ReadBytes(numberOfBytesToRead);
}
}
}

View File

@@ -66,6 +66,11 @@ namespace ICD.Common.Utils.IO
File.Delete(path);
}
public static IcdStream OpenRead(string path)
{
return new IcdFileStream(File.OpenRead(path));
}
[PublicAPI]
public static IcdFileStream OpenWrite(string path)
{

View File

@@ -13,6 +13,10 @@ namespace ICD.Common.Utils.IO
public Stream WrappedStream { get { return m_Stream; } }
public long Length { get { return m_Stream.Length; } }
public long Position { get { return m_Stream.Position; } }
/// <summary>
/// Constructor.
/// </summary>
@@ -29,5 +33,10 @@ namespace ICD.Common.Utils.IO
{
m_Stream.Dispose();
}
public void Seek(long offset, eSeekOrigin seekOrigin)
{
m_Stream.Seek(offset, seekOrigin.ToSeekOrigin());
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
#else
using System.IO;
#endif
namespace ICD.Common.Utils.IO
{
public enum eSeekOrigin
{
Begin,
Current,
End,
}
public static class SeekOriginExtensions
{
/// <summary>
/// Converts the seek origin enum to a system seek origin.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static SeekOrigin ToSeekOrigin(this eSeekOrigin extends)
{
switch (extends)
{
case eSeekOrigin.Begin:
return SeekOrigin.Begin;
case eSeekOrigin.Current:
return SeekOrigin.Current;
case eSeekOrigin.End:
return SeekOrigin.End;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
}
}

View File

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