From fa2cbebad2842a89ae872366c31ad5bbf3c16074 Mon Sep 17 00:00:00 2001 From: Valeriy Mironov Date: Wed, 29 Nov 2017 04:42:21 +0200 Subject: [PATCH] Added saving resources version on unpacking .res file, added packing .res file, closes #1 --- Resources/Extractor.cs | 38 ++++++++++ .../{ResourcesFileReader.cs => FileReader.cs} | 23 +++--- Resources/FileWriter.cs | 41 ++++++++++ Resources/{Dithering => Image}/ColorError.cs | 2 +- .../FloydSteinbergDitherer.cs | 2 +- Resources/{ImageReader.cs => Image/Reader.cs} | 7 +- Resources/{ImageWriter.cs => Image/Writer.cs} | 8 +- Resources/Models/FileDescriptor.cs | 11 +++ Resources/Models/Header.cs | 40 ++++++++++ Resources/Properties/AssemblyInfo.cs | 4 +- Resources/{ResourcesReader.cs => Reader.cs} | 21 +++--- Resources/Resources.csproj | 24 +++--- Resources/ResourcesExtractor.cs | 29 ------- Resources/ResourcesHeader.cs | 29 ------- Resources/{ => Utils}/BitReader.cs | 2 +- Resources/{ => Utils}/BitWriter.cs | 2 +- Resources/Writer.cs | 51 +++++++++++++ WatchFace.Parser/Models/Header.cs | 10 +-- WatchFace.Parser/Properties/AssemblyInfo.cs | 4 +- WatchFace.Parser/Reader.cs | 5 +- WatchFace.Parser/Utils/ImagesLoader.cs | 1 + WatchFace.Parser/Writer.cs | 42 +++-------- WatchFace/Program.cs | 75 ++++++++++++++++--- WatchFace/Properties/AssemblyInfo.cs | 4 +- 24 files changed, 315 insertions(+), 160 deletions(-) create mode 100644 Resources/Extractor.cs rename Resources/{ResourcesFileReader.cs => FileReader.cs} (55%) create mode 100644 Resources/FileWriter.cs rename Resources/{Dithering => Image}/ColorError.cs (97%) rename Resources/{Dithering => Image}/FloydSteinbergDitherer.cs (98%) rename Resources/{ImageReader.cs => Image/Reader.cs} (96%) rename Resources/{ImageWriter.cs => Image/Writer.cs} (97%) create mode 100644 Resources/Models/FileDescriptor.cs create mode 100644 Resources/Models/Header.cs rename Resources/{ResourcesReader.cs => Reader.cs} (66%) delete mode 100644 Resources/ResourcesExtractor.cs delete mode 100644 Resources/ResourcesHeader.cs rename Resources/{ => Utils}/BitReader.cs (98%) rename Resources/{ => Utils}/BitWriter.cs (98%) create mode 100644 Resources/Writer.cs diff --git a/Resources/Extractor.cs b/Resources/Extractor.cs new file mode 100644 index 0000000..28338cb --- /dev/null +++ b/Resources/Extractor.cs @@ -0,0 +1,38 @@ +using System.Drawing.Imaging; +using System.IO; +using NLog; +using Resources.Models; + +namespace Resources +{ + public class Extractor + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly FileDescriptor _descriptor; + + public Extractor(FileDescriptor descriptor) + { + _descriptor = descriptor; + } + + public void Extract(string outputDirectory) + { + if (_descriptor.Version != null) + { + var fileName = Path.Combine(outputDirectory, "version"); + using (var stream = File.OpenWrite(fileName)) + using (var writer = new BinaryWriter(stream)) + { + writer.Write(_descriptor.Version.Value); + } + } + for (var i = 0; i < _descriptor.Images.Count; i++) + { + var fileName = Path.Combine(outputDirectory, $"{i}.png"); + Logger.Debug("Extracting {0}...", fileName); + _descriptor.Images[i].Save(fileName, ImageFormat.Png); + } + } + } +} \ No newline at end of file diff --git a/Resources/ResourcesFileReader.cs b/Resources/FileReader.cs similarity index 55% rename from Resources/ResourcesFileReader.cs rename to Resources/FileReader.cs index 0cc4f2b..5247b42 100644 --- a/Resources/ResourcesFileReader.cs +++ b/Resources/FileReader.cs @@ -1,27 +1,20 @@ using System; -using System.Drawing; using System.IO; using NLog; +using Resources.Models; namespace Resources { - public class ResourcesFileReader + public class FileReader { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly BinaryReader _binaryReader; - private readonly Stream _stream; - - public ResourcesFileReader(Stream stream) + public static FileDescriptor Read(Stream stream) { - _stream = stream; - _binaryReader = new BinaryReader(stream); - } + var binaryReader = new BinaryReader(stream); - public Bitmap[] Read() - { Logger.Trace("Reading resources header"); - var header = ResourcesHeader.ReadFrom(_binaryReader); + var header = Header.ReadFrom(binaryReader); Logger.Trace("Resources header was read:"); Logger.Trace("Signature: {0}, Version: {1}, ResourcesCount: {2}, IsValid: {3}", header.Signature, header.Version, header.ResourcesCount, header.IsValid @@ -30,7 +23,11 @@ namespace Resources if (!header.IsValid) throw new ArgumentException("Invalid resources header"); - return new ResourcesReader(_stream).Read(header.ResourcesCount); + return new FileDescriptor + { + Version = header.Version, + Images = new Reader(stream).Read(header.ResourcesCount) + }; } } } \ No newline at end of file diff --git a/Resources/FileWriter.cs b/Resources/FileWriter.cs new file mode 100644 index 0000000..88c9adc --- /dev/null +++ b/Resources/FileWriter.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using NLog; +using Resources.Models; + +namespace Resources +{ + public class FileWriter + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly BinaryWriter _binaryWriter; + private readonly Stream _stream; + + public FileWriter(Stream stream) + { + _stream = stream; + _binaryWriter = new BinaryWriter(stream); + } + + public void Write(FileDescriptor descriptor) + { + if (descriptor.Version == null) + throw new ArgumentException("Res file version required"); + + var header = new Header + { + ResourcesCount = (uint) descriptor.Images.Count, + Version = descriptor.Version.Value + }; + Logger.Trace("Writing resources header..."); + Logger.Trace("Signature: {0}, Version: {1}, ResourcesCount: {2}, IsValid: {3}", + header.Signature, header.Version, header.ResourcesCount, header.IsValid + ); + header.WriteTo(_binaryWriter); + + Logger.Trace("Writing images..."); + new Writer(_stream).Write(descriptor.Images); + } + } +} \ No newline at end of file diff --git a/Resources/Dithering/ColorError.cs b/Resources/Image/ColorError.cs similarity index 97% rename from Resources/Dithering/ColorError.cs rename to Resources/Image/ColorError.cs index a9a4e0d..5e32c7d 100644 --- a/Resources/Dithering/ColorError.cs +++ b/Resources/Image/ColorError.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace Resources.Dithering +namespace Resources.Image { public class ColorError { diff --git a/Resources/Dithering/FloydSteinbergDitherer.cs b/Resources/Image/FloydSteinbergDitherer.cs similarity index 98% rename from Resources/Dithering/FloydSteinbergDitherer.cs rename to Resources/Image/FloydSteinbergDitherer.cs index 1ed6531..f52023a 100644 --- a/Resources/Dithering/FloydSteinbergDitherer.cs +++ b/Resources/Image/FloydSteinbergDitherer.cs @@ -1,7 +1,7 @@ using System.Drawing; using NLog; -namespace Resources.Dithering +namespace Resources.Image { public class FloydSteinbergDitherer { diff --git a/Resources/ImageReader.cs b/Resources/Image/Reader.cs similarity index 96% rename from Resources/ImageReader.cs rename to Resources/Image/Reader.cs index 8d80cdf..517fc15 100644 --- a/Resources/ImageReader.cs +++ b/Resources/Image/Reader.cs @@ -2,10 +2,11 @@ using System.Drawing; using System.IO; using NLog; +using Resources.Utils; -namespace Resources +namespace Resources.Image { - public class ImageReader + public class Reader { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); @@ -18,7 +19,7 @@ namespace Resources private bool _transparency; private ushort _width; - public ImageReader(Stream stream) + public Reader(Stream stream) { _reader = new BinaryReader(stream); } diff --git a/Resources/ImageWriter.cs b/Resources/Image/Writer.cs similarity index 97% rename from Resources/ImageWriter.cs rename to Resources/Image/Writer.cs index 783457d..2fb0af8 100644 --- a/Resources/ImageWriter.cs +++ b/Resources/Image/Writer.cs @@ -4,11 +4,11 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using NLog; -using Resources.Dithering; +using Resources.Utils; -namespace Resources +namespace Resources.Image { - public class ImageWriter + public class Writer { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly byte[] Signature = {(byte) 'B', (byte) 'M', (byte) 'd', 0}; @@ -24,7 +24,7 @@ namespace Resources private ushort _transparency; private ushort _width; - public ImageWriter(Stream stream) + public Writer(Stream stream) { _writer = new BinaryWriter(stream); _palette = new List(); diff --git a/Resources/Models/FileDescriptor.cs b/Resources/Models/FileDescriptor.cs new file mode 100644 index 0000000..aa3eeae --- /dev/null +++ b/Resources/Models/FileDescriptor.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Drawing; + +namespace Resources.Models +{ + public class FileDescriptor + { + public byte? Version { get; set; } + public List Images { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/Resources/Models/Header.cs b/Resources/Models/Header.cs new file mode 100644 index 0000000..77fa45c --- /dev/null +++ b/Resources/Models/Header.cs @@ -0,0 +1,40 @@ +using System; +using System.IO; +using System.Text; + +namespace Resources.Models +{ + public class Header + { + public const int HeaderSize = 20; + private const string ResSignature = "HMRES"; + + public string Signature { get; private set; } = ResSignature; + public byte Version { get; set; } + public uint ResourcesCount { get; set; } + + public bool IsValid => Signature == ResSignature; + + public void WriteTo(BinaryWriter writer) + { + var buffer = new byte[HeaderSize]; + for (var i = 0; i < buffer.Length; i++) buffer[i] = 0xff; + + Encoding.ASCII.GetBytes(ResSignature).CopyTo(buffer, 0); + buffer[5] = Version; + BitConverter.GetBytes(ResourcesCount).CopyTo(buffer, 16); + writer.Write(buffer); + } + + public static Header ReadFrom(BinaryReader reader) + { + var buffer = reader.ReadBytes(HeaderSize); + return new Header + { + Signature = Encoding.ASCII.GetString(buffer, 0, 5), + Version = buffer[5], + ResourcesCount = BitConverter.ToUInt32(buffer, 16) + }; + } + } +} \ No newline at end of file diff --git a/Resources/Properties/AssemblyInfo.cs b/Resources/Properties/AssemblyInfo.cs index 7b707fc..ad3957c 100644 --- a/Resources/Properties/AssemblyInfo.cs +++ b/Resources/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // 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.0.2")] -[assembly: AssemblyFileVersion("1.0.0.2")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.0.3")] +[assembly: AssemblyFileVersion("1.0.0.3")] \ No newline at end of file diff --git a/Resources/ResourcesReader.cs b/Resources/Reader.cs similarity index 66% rename from Resources/ResourcesReader.cs rename to Resources/Reader.cs index 42799cc..7afaa35 100644 --- a/Resources/ResourcesReader.cs +++ b/Resources/Reader.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using NLog; namespace Resources { - public class ResourcesReader + public class Reader { private const int OffsetTableItemLength = 4; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); @@ -13,13 +14,13 @@ namespace Resources private readonly BinaryReader _binaryReader; private readonly Stream _stream; - public ResourcesReader(Stream stream) + public Reader(Stream stream) { _stream = stream; _binaryReader = new BinaryReader(_stream); } - public Bitmap[] Read(uint imagesTableLength) + public List Read(uint imagesTableLength) { var offsetsTableLength = (int) (imagesTableLength * OffsetTableItemLength); Logger.Trace("Reading resources offsets table with {0} elements ({1} bytes)", @@ -29,18 +30,20 @@ namespace Resources var imagesOffset = _stream.Position; Logger.Debug("Reading {0} images...", imagesTableLength); - var images = new Bitmap[imagesTableLength]; + var images = new List((int) imagesTableLength); for (var i = 0; i < imagesTableLength; i++) { - var imageOffset = BitConverter.ToUInt32(imagesOffsets, i * OffsetTableItemLength) + imagesOffset; - if (_stream.Position != imageOffset) + var imageOffset = BitConverter.ToUInt32(imagesOffsets, i * OffsetTableItemLength); + var realOffset = imageOffset + imagesOffset; + Logger.Trace("Image {0} offset is {1}...", i, imageOffset); + if (_stream.Position != realOffset) { - var bytesGap = imageOffset - _stream.Position; + var bytesGap = realOffset - _stream.Position; Logger.Warn("Found {0} bytes gap before resource number {1}", bytesGap, i); - _stream.Seek(imageOffset, SeekOrigin.Begin); + _stream.Seek(realOffset, SeekOrigin.Begin); } Logger.Debug("Reading image {0}...", i); - images[i] = new ImageReader(_stream).Read(); + images.Add(new Image.Reader(_stream).Read()); } return images; } diff --git a/Resources/Resources.csproj b/Resources/Resources.csproj index 068ac22..b3f2504 100644 --- a/Resources/Resources.csproj +++ b/Resources/Resources.csproj @@ -44,20 +44,24 @@ - - - - - - - - - + + + + + + + + + + + + - + + \ No newline at end of file diff --git a/Resources/ResourcesExtractor.cs b/Resources/ResourcesExtractor.cs deleted file mode 100644 index 12a130b..0000000 --- a/Resources/ResourcesExtractor.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using NLog; - -namespace Resources -{ - public class ResourcesExtractor - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - private readonly Bitmap[] _images; - - public ResourcesExtractor(Bitmap[] images) - { - _images = images; - } - - public void Extract(string outputDirectory) - { - for (var i = 0; i < _images.Length; i++) - { - var fileName = Path.Combine(outputDirectory, $"{i}.png"); - Logger.Debug("Exporting {0}...", fileName); - _images[i].Save(fileName, ImageFormat.Png); - } - } - } -} \ No newline at end of file diff --git a/Resources/ResourcesHeader.cs b/Resources/ResourcesHeader.cs deleted file mode 100644 index 3a3617f..0000000 --- a/Resources/ResourcesHeader.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace Resources -{ - public class ResourcesHeader - { - public const int HeaderSize = 20; - private const string ResHeaderSignature = "HMRES"; - private readonly byte[] _header; - - public ResourcesHeader(byte[] header) - { - _header = header; - } - - public string Signature => Encoding.ASCII.GetString(_header, 0, 5); - public bool IsValid => Signature == ResHeaderSignature; - public uint Version => _header[5]; - public uint ResourcesCount => BitConverter.ToUInt32(_header, 16); - - public static ResourcesHeader ReadFrom(BinaryReader reader) - { - var buffer = reader.ReadBytes(HeaderSize); - return new ResourcesHeader(buffer); - } - } -} \ No newline at end of file diff --git a/Resources/BitReader.cs b/Resources/Utils/BitReader.cs similarity index 98% rename from Resources/BitReader.cs rename to Resources/Utils/BitReader.cs index da803e3..937b226 100644 --- a/Resources/BitReader.cs +++ b/Resources/Utils/BitReader.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace Resources +namespace Resources.Utils { public class BitReader { diff --git a/Resources/BitWriter.cs b/Resources/Utils/BitWriter.cs similarity index 98% rename from Resources/BitWriter.cs rename to Resources/Utils/BitWriter.cs index 8c45a27..ca9e63d 100644 --- a/Resources/BitWriter.cs +++ b/Resources/Utils/BitWriter.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace Resources +namespace Resources.Utils { public class BitWriter { diff --git a/Resources/Writer.cs b/Resources/Writer.cs new file mode 100644 index 0000000..39550f1 --- /dev/null +++ b/Resources/Writer.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using NLog; + +namespace Resources +{ + public class Writer + { + private const int OffsetTableItemLength = 4; + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly Stream _stream; + + public Writer(Stream stream) + { + _stream = stream; + } + + public void Write(List images) + { + var offsetsTable = new byte[images.Count * OffsetTableItemLength]; + var encodedImages = new MemoryStream[images.Count]; + + var offset = (uint) 0; + for (var i = 0; i < images.Count; i++) + { + Logger.Trace("Image {0} offset is {1}...", i, offset); + var offsetBytes = BitConverter.GetBytes(offset); + offsetBytes.CopyTo(offsetsTable, i * OffsetTableItemLength); + + var encodedImage = new MemoryStream(); + Logger.Debug("Encoding image {0}...", i); + new Image.Writer(encodedImage).Write(images[i]); + offset += (uint) encodedImage.Length; + encodedImages[i] = encodedImage; + } + + Logger.Trace("Writing images offsets table"); + _stream.Write(offsetsTable, 0, offsetsTable.Length); + + Logger.Debug("Writing images"); + foreach (var encodedImage in encodedImages) + { + encodedImage.Seek(0, SeekOrigin.Begin); + encodedImage.CopyTo(_stream); + } + } + } +} \ No newline at end of file diff --git a/WatchFace.Parser/Models/Header.cs b/WatchFace.Parser/Models/Header.cs index 80b12ac..e06b42c 100644 --- a/WatchFace.Parser/Models/Header.cs +++ b/WatchFace.Parser/Models/Header.cs @@ -20,13 +20,9 @@ namespace WatchFace.Parser.Models var buffer = new byte[HeaderSize]; for (var i = 0; i < buffer.Length; i++) buffer[i] = 0xff; - var signature = Encoding.ASCII.GetBytes(Signature); - var unknown = BitConverter.GetBytes(Unknown); - var parametersSize = BitConverter.GetBytes(ParametersSize); - - signature.CopyTo(buffer, 0); - unknown.CopyTo(buffer, 32); - parametersSize.CopyTo(buffer, 36); + Encoding.ASCII.GetBytes(Signature).CopyTo(buffer, 0); + BitConverter.GetBytes(Unknown).CopyTo(buffer, 32); + BitConverter.GetBytes(ParametersSize).CopyTo(buffer, 36); stream.Write(buffer, 0, HeaderSize); } diff --git a/WatchFace.Parser/Properties/AssemblyInfo.cs b/WatchFace.Parser/Properties/AssemblyInfo.cs index 136bc27..fdc96d5 100644 --- a/WatchFace.Parser/Properties/AssemblyInfo.cs +++ b/WatchFace.Parser/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // 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.0.2")] -[assembly: AssemblyFileVersion("1.0.0.2")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.0.3")] +[assembly: AssemblyFileVersion("1.0.0.3")] \ No newline at end of file diff --git a/WatchFace.Parser/Reader.cs b/WatchFace.Parser/Reader.cs index 1235920..9c59a15 100644 --- a/WatchFace.Parser/Reader.cs +++ b/WatchFace.Parser/Reader.cs @@ -2,7 +2,6 @@ using System.Drawing; using System.IO; using NLog; -using Resources; using WatchFace.Parser.Models; namespace WatchFace.Parser @@ -19,7 +18,7 @@ namespace WatchFace.Parser } public List Parameters { get; private set; } - public Bitmap[] Images { get; private set; } + public List Images { get; private set; } public void Read() { @@ -47,7 +46,7 @@ namespace WatchFace.Parser Logger.Trace("Watch face parameters locations were read:"); Parameters = ReadParameters(parametrsTableLength, parametersLocations); - Images = new ResourcesReader(_stream).Read((uint) imagesCount); + Images = new Resources.Reader(_stream).Read((uint) imagesCount); } private List ReadParameters(long coordinatesTableSize, ICollection parametersDescriptors) diff --git a/WatchFace.Parser/Utils/ImagesLoader.cs b/WatchFace.Parser/Utils/ImagesLoader.cs index 896eec7..a8310c9 100644 --- a/WatchFace.Parser/Utils/ImagesLoader.cs +++ b/WatchFace.Parser/Utils/ImagesLoader.cs @@ -104,6 +104,7 @@ namespace WatchFace.Parser.Utils var fileName = Path.Combine(_imagesDirectory, $"{index}.png"); var newImageIndex = Images.Count; + Logger.Trace("Loading {0} image from file {1}", newImageIndex, fileName); Images.Add((Bitmap) Image.FromFile(fileName)); _mapping[index] = newImageIndex; return newImageIndex; diff --git a/WatchFace.Parser/Writer.cs b/WatchFace.Parser/Writer.cs index 7ebef7b..a6511fa 100644 --- a/WatchFace.Parser/Writer.cs +++ b/WatchFace.Parser/Writer.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; using System.IO; using NLog; -using Resources; using WatchFace.Parser.Models; using WatchFace.Parser.Utils; @@ -24,7 +22,10 @@ namespace WatchFace.Parser public void Write(WatchFace watchFace) { + Logger.Trace("Building parameters for watch face..."); var descriptor = ParametersConverter.Build(watchFace); + + Logger.Trace("Encoding parameters..."); var encodedParameters = new Dictionary(descriptor.Count); foreach (var parameter in descriptor) { @@ -34,9 +35,9 @@ namespace WatchFace.Parser encodedParameters[parameter.Id] = memoryStream; } + Logger.Trace("Encoding offsets and lengths..."); var parametersPositions = new List(descriptor.Count + 1); var offset = (long) 0; - foreach (var encodedParameter in encodedParameters) { var encodedParameterId = encodedParameter.Key; @@ -58,6 +59,7 @@ namespace WatchFace.Parser foreach (var parametersPosition in parametersPositions) parametersPosition.Write(encodedParametersPositions); + Logger.Trace("Writing header..."); var header = new Header { ParametersSize = (uint) encodedParametersPositions.Length, @@ -65,43 +67,19 @@ namespace WatchFace.Parser }; header.WriteTo(_stream); + Logger.Trace("Writing parameters offsets and lengths..."); encodedParametersPositions.Seek(0, SeekOrigin.Begin); encodedParametersPositions.WriteTo(_stream); + Logger.Trace("Writing parameters..."); foreach (var encodedParameter in encodedParameters) { var stream = encodedParameter.Value; stream.Seek(0, SeekOrigin.Begin); stream.WriteTo(_stream); } - WriteImages(); - } - - public void WriteImages() - { - var offsetsTable = new byte[_images.Count * 4]; - var encodedImages = new MemoryStream[_images.Count]; - - var offset = (uint) 0; - for (var i = 0; i < _images.Count; i++) - { - var offsetBytes = BitConverter.GetBytes(offset); - offsetBytes.CopyTo(offsetsTable, i * 4); - - var encodedImage = new MemoryStream(); - Logger.Debug("Writing image {0}...", i); - new ImageWriter(encodedImage).Write(_images[i]); - offset += (uint) encodedImage.Length; - encodedImages[i] = encodedImage; - } - - _stream.Write(offsetsTable, 0, offsetsTable.Length); - - foreach (var encodedImage in encodedImages) - { - encodedImage.Seek(0, SeekOrigin.Begin); - encodedImage.CopyTo(_stream); - } + Logger.Trace("Writing images..."); + new Resources.Writer(_stream).Write(_images); } } } \ No newline at end of file diff --git a/WatchFace/Program.cs b/WatchFace/Program.cs index 88f725b..834ab4e 100644 --- a/WatchFace/Program.cs +++ b/WatchFace/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using Newtonsoft.Json; @@ -6,8 +7,10 @@ using NLog; using NLog.Config; using NLog.Targets; using Resources; -using WatchFace.Parser; +using Resources.Models; using WatchFace.Parser.Utils; +using Reader = WatchFace.Parser.Reader; +using Writer = WatchFace.Parser.Writer; namespace WatchFace { @@ -22,12 +25,13 @@ namespace WatchFace if (args.Length == 0 || args[0] == null) { Console.WriteLine( - "{0}.exe unpacks and packs Amazfit Bip downloadable watch faces and unpacks res files.", AppName); + "{0}.exe unpacks and packs Amazfit Bip downloadable watch faces and resource files.", AppName); Console.WriteLine(); Console.WriteLine("Usage examples:"); - Console.WriteLine(" {0}.exe watchface.bin - unpacks watchface images and config", AppName); - Console.WriteLine(" {0}.exe watchface.res - unpacks resource file images", AppName); - Console.WriteLine(" {0}.exe watchface.json - packs config and referenced images to bin file", AppName); + Console.WriteLine(" {0}.exe watchface.bin - unpacks watchface images and config", AppName); + Console.WriteLine(" {0}.exe watchface.json - packs config and referenced images to bin file", AppName); + Console.WriteLine(" {0}.exe mili_chaohu.res - unpacks resource file images", AppName); + Console.WriteLine(" {0}.exe mili_chaohu - packs folder content to res file", AppName); return; } @@ -36,9 +40,24 @@ namespace WatchFace foreach (var inputFileName in args) { - if (!File.Exists(inputFileName)) + var isDirectory = Directory.Exists(inputFileName); + var isFile = File.Exists(inputFileName); + if (!isDirectory && !isFile) { - Console.WriteLine("File '{0}' doesn't exists.", inputFileName); + Console.WriteLine("File or directory '{0}' doesn't exists.", inputFileName); + continue; + } + if (isDirectory) + { + Console.WriteLine("Processing directory '{0}'", inputFileName); + try + { + PackResources(inputFileName); + } + catch (Exception e) + { + Logger.Fatal(e); + } continue; } @@ -105,23 +124,57 @@ namespace WatchFace if (watchFace == null) return; Logger.Debug("Exporting resources to '{0}'", outputDirectory); - new ResourcesExtractor(reader.Images).Extract(outputDirectory); + var reDescriptor = new FileDescriptor {Images = reader.Images}; + new Extractor(reDescriptor).Extract(outputDirectory); ExportConfig(watchFace, Path.Combine(outputDirectory, $"{baseName}.json")); } + private static void PackResources(string inputDirectory) + { + var outputDirectory = Path.GetDirectoryName(inputDirectory); + var baseName = Path.GetFileName(inputDirectory); + var outputFileName = Path.Combine(outputDirectory, $"{baseName}_packed.res"); + var logFileName = Path.Combine(outputDirectory, $"{baseName}_packed.log"); + SetupLogger(logFileName); + + var versionFileName = Path.Combine(inputDirectory, "version"); + var resDescriptor = new FileDescriptor(); + using (var stream = File.OpenRead(versionFileName)) + using (var reader = new BinaryReader(stream)) + { + resDescriptor.Version = reader.ReadByte(); + } + var i = 0; + var images = new List(); + while (true) + { + var fileName = Path.Combine(inputDirectory, $"{i}.png"); + if (!File.Exists(fileName)) break; + + images.Add((Bitmap) Image.FromFile(fileName)); + i++; + } + resDescriptor.Images = images; + + using (var stream = File.OpenWrite(outputFileName)) + { + new FileWriter(stream).Write(resDescriptor); + } + } + private static void UnpackResources(string inputFileName) { var outputDirectory = CreateOutputDirectory(inputFileName); var baseName = Path.GetFileNameWithoutExtension(inputFileName); SetupLogger(Path.Combine(outputDirectory, $"{baseName}.log")); - Bitmap[] images; + FileDescriptor resDescriptor; using (var stream = File.OpenRead(inputFileName)) { - images = new ResourcesFileReader(stream).Read(); + resDescriptor = FileReader.Read(stream); } - new ResourcesExtractor(images).Extract(outputDirectory); + new Extractor(resDescriptor).Extract(outputDirectory); } private static void WriteWatchFace(string outputFileName, string imagesDirectory, Parser.WatchFace watchFace) diff --git a/WatchFace/Properties/AssemblyInfo.cs b/WatchFace/Properties/AssemblyInfo.cs index aa0302a..c94891c 100644 --- a/WatchFace/Properties/AssemblyInfo.cs +++ b/WatchFace/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // 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.0.2")] -[assembly: AssemblyFileVersion("1.0.0.2")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.0.3")] +[assembly: AssemblyFileVersion("1.0.0.3")] \ No newline at end of file