diff --git a/LICENSE b/LICENSE index 1e5140d..71fdf78 100644 --- a/LICENSE +++ b/LICENSE @@ -20,30 +20,3 @@ 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. - - -This software contains code of third-parties. - -LibraryPropertyReader.cs: -========================= - -Copyright (c) 2023 Andrew Burks - -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. \ No newline at end of file diff --git a/TwinpackRegistry/Program.cs b/TwinpackRegistry/Program.cs index 53766ad..261e1aa 100644 --- a/TwinpackRegistry/Program.cs +++ b/TwinpackRegistry/Program.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using Twinpack.Models; @@ -25,6 +26,19 @@ public class UpdateOptions [Option('r', "name", Required = false, Default = "Twinpack-Registry", HelpText = "")] public string RegistryName { get; set; } + + [Option('d', "dry-run", Required = false, Default = false, HelpText = "")] + public bool DryRun { get; set; } + + [Option('D', "dump", Required = false, Default = false, HelpText = "")] + public bool Dump { get; set; } + } + + [Verb("dump", HelpText = "")] + public class DumpOptions + { + [Option('p', "path", Required = false, Default = "Twinpack-Registry", HelpText = "")] + public string Path { get; set; } } private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); @@ -49,14 +63,31 @@ static int Main(string[] args) try { - return Parser.Default.ParseArguments(args) + return Parser.Default.ParseArguments(args) .MapResult( (UpdateOptions opts) => { Login(opts.Username, opts.Password); - new TwinpackRegistry(_twinpackServer).DownloadAsync(opts.RegistryOwner, opts.RegistryName).GetAwaiter().GetResult(); - _twinpackServer.PushAsync(TwinpackUtils.PlcProjectsFromConfig(compiled: false, target: "TC3.1"), "Release", "main", "TC3.1", null, false).GetAwaiter().GetResult(); + new TwinpackRegistry(_twinpackServer).DownloadAsync(opts.RegistryOwner, opts.RegistryName, dump: opts.Dump).GetAwaiter().GetResult(); + if(!opts.DryRun) + _twinpackServer.PushAsync(TwinpackUtils.PlcProjectsFromConfig(compiled: false, target: "TC3.1"), "Release", "main", "TC3.1", null, false).GetAwaiter().GetResult(); + + return 0; + }, + (DumpOptions opts) => + { + foreach(var file in Directory.GetFiles(opts.Path)) + { + try + { + using (var memoryStream = new MemoryStream(File.ReadAllBytes(file))) + using (var zipArchive = new ZipArchive(memoryStream)) + { + var libraryInfo = LibraryReader.Read(File.ReadAllBytes(file), dumpFilenamePrefix: file); + } + } catch(Exception) { } + } return 0; }, errs => 1); diff --git a/TwinpackRegistry/TwinpackRegistry.cs b/TwinpackRegistry/TwinpackRegistry.cs index f3c9692..2dd33c8 100644 --- a/TwinpackRegistry/TwinpackRegistry.cs +++ b/TwinpackRegistry/TwinpackRegistry.cs @@ -75,7 +75,7 @@ async Task DownloadAsync(string url) } } - public async Task DownloadAsync(string repositoryOwner, string repositoryName, string cachePath = null) + public async Task DownloadAsync(string repositoryOwner, string repositoryName, bool dump=false) { var config = new Config() { @@ -98,7 +98,7 @@ public async Task DownloadAsync(string repositoryOwner, string repositoryName, s { var license = await RetrieveLicenseAsync(client, owner, repo); var library = await DownloadAsync(asset.BrowserDownloadUrl); - var libraryInfo = LibraryPropertyReader.Read(library); + var libraryInfo = LibraryReader.Read(library, dumpFilenamePrefix: $"{repositoryOwner}_{repositoryName}_{asset.Name}.library"); var filePath = $@"{TwinpackServer.DefaultLibraryCachePath}\{target}"; var iconFileName = $@"{filePath}\{libraryInfo.Title}_{libraryInfo.Version}.png"; var libraryFileName = $@"{filePath}\{libraryInfo.Title}_{libraryInfo.Version}.library"; diff --git a/TwinpackShared/Exceptions/Exceptions.cs b/TwinpackShared/Exceptions/Exceptions.cs index 7150f6c..2c0570a 100644 --- a/TwinpackShared/Exceptions/Exceptions.cs +++ b/TwinpackShared/Exceptions/Exceptions.cs @@ -39,6 +39,17 @@ public LibraryNotFoundException(string reference, string version, string message } } + public class LibraryInvalid : Exception + { + public LibraryInvalid(string message) : base(message) + { + } + + public LibraryInvalid(string fileName, string message) : base(fileName + ", " +message) + { + } + } + public class LicenseFileNotFoundException : Exception { public string Reference { get; private set; } diff --git a/TwinpackShared/LibraryPropertyReader.cs b/TwinpackShared/LibraryPropertyReader.cs deleted file mode 100644 index 26ee3ee..0000000 --- a/TwinpackShared/LibraryPropertyReader.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2023 Andrew Burks - * - * 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 beincluded 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 NLog; -using NLog.LayoutRenderers; -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.Remoting.Messaging; -using System.Text; -using System.Text.RegularExpressions; -using Twinpack.Models; -using static Microsoft.VisualStudio.Shell.RegistrationAttribute; - -namespace Twinpack -{ - public class LibraryPropertyReader - { - private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); - - public class LibraryInfo - { - public string DefaultNamespace { get; set; } - public string Title { get; set; } - public string Description { get; set; } - public string Author { get; set; } - public string Company { get; set; } - public string Version { get; set; } - public List Dependencies { get; set; } - } - - static List _identifiers = new List () { - "DefaultNamespace", "Project", "Company", "Title", "Description", - "Author", "Version", "Placeholder", "Released" }; - public static LibraryInfo Read(byte[] libraryBinary) - { - var values = new List(); - - int ReadLength(BinaryReader reader) - { - byte lengthByte = reader.ReadByte(); - int length = lengthByte; - if (length > 128) // check if last bit is set - { - lengthByte = reader.ReadByte(); - length = (length - 128) + lengthByte * 128; - } - - return length; - } - - using (var memoryStream = new MemoryStream(libraryBinary)) - using(var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read)) - { - var stream = zipArchive.Entries.Where(x => x.Name == "__shared_data_storage_string_table__.auxiliary")?.FirstOrDefault().Open(); - - try - { - using (var reader = new BinaryReader(stream)) - { - int objects = ReadLength(reader); - var index = reader.ReadByte(); - while (index < objects && index < 128) - { - var length = ReadLength(reader); - byte[] data = reader.ReadBytes(length); - string str = Encoding.UTF8.GetString(data); - values.Add(str); - - var nextIndex = reader.ReadByte(); - - // we reached the last string? - if (nextIndex - 1 != index) - break; - - index = nextIndex; - } - - } - } - catch(Exception ex) - { - _logger.Trace(ex); - _logger.Warn(ex.Message); - } - - } - - var dependencies = values.Select(x => Regex.Match(x, @"^([A-Za-z].*?),\s*(.*?)\s*\(([A-Za-z].*)\)$")) - .Where(x => x.Success) - .Select(x => new PlcLibrary() { Name = x.Groups[1].Value, Version = x.Groups[2].Value, DistributorName = x.Groups[3].Value }) - .ToList(); - - // yes, this is needed ... not sure how Codesys parses this stuff - var title = Value(values, "Title"); - if(string.IsNullOrEmpty(title) || Guid.TryParse(title, out _) || _identifiers.Contains(title)) - { - title = Value(values, "Placeholder"); - if (string.IsNullOrEmpty(title) || Guid.TryParse(title, out _) || _identifiers.Contains(title)) - { - title = Value(values, "DefaultNamespace"); - } - } - - return new LibraryInfo() - { - DefaultNamespace = Value(values, "DefaultNamespace"), - Company = Value(values, "Company"), - Version = Value(values, "Version"), - Title = title, - Description = Value(values, "Description"), - Author = Value(values, "Author"), - Dependencies = dependencies - }; - } - - private static string Value(List values, string key) - { - var idx = values.FindIndex(x => string.Equals(x, key, StringComparison.CurrentCultureIgnoreCase)); - return idx < 0 ? "" : values[idx+1]; - } - } -} diff --git a/TwinpackShared/LibraryReader.cs b/TwinpackShared/LibraryReader.cs new file mode 100644 index 0000000..5fe019a --- /dev/null +++ b/TwinpackShared/LibraryReader.cs @@ -0,0 +1,268 @@ +using NLog; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using Twinpack.Models; + +namespace Twinpack +{ + public class LibraryReader + { + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public class LibraryInfo + { + public string DefaultNamespace { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public string Company { get; set; } + public string Version { get; set; } + public List Dependencies { get; set; } + } + + enum PropertyType + { + Eof = 0x00, + Boolean = 0x01, + //Number = 0x03, + //Date = ?, + Text = 0x0E, + Version = 0x0F, + LibraryCategories = 0x81, + } + + static int ReadLength(BinaryReader reader) + { + return ReadLength(reader, reader.ReadByte()); + } + + static int ReadLength(BinaryReader reader, byte currentByte) + { + int length = currentByte; + if (length > 128) // check if last bit is set + { + currentByte = reader.ReadByte(); + length = (length - 128) + currentByte * 128; + } + + return length; + } + + public static List ReadStringTable(ZipArchive archive, string dumpFilenamePrefix = null) + { + _logger.Info("Reading string table"); + + var stringTable = new List(); + var stream = archive.Entries.Where(x => x.Name == "__shared_data_storage_string_table__.auxiliary")?.FirstOrDefault().Open(); + + var objects = 0; + var index = 0; + try + { + using (var reader = new BinaryReader(stream)) + { + objects = ReadLength(reader); + _logger.Info($"String table contains {objects} strings"); + index = reader.ReadByte(); + while (index < objects-1 && index < 128) + { + var length = ReadLength(reader); + byte[] data = reader.ReadBytes(length); + string str = Encoding.UTF8.GetString(data); + stringTable.Add(str); + + var nextIndex = reader.ReadByte(); + + // we reached the last string? + if (nextIndex - 1 != index) + { + break; + } + + index = nextIndex; + } + + } + } + catch(Exception ex) + { + _logger.Trace(ex); + _logger.Warn(ex.Message); + } + + + if (dumpFilenamePrefix != null) + { + using (var streamWriter = new StreamWriter(dumpFilenamePrefix + ".stringtable")) + { + index = 0; + foreach (var key in stringTable) + { + streamWriter.WriteLine($"{index.ToString("X")}: {key}"); + index++; + } + } + } + + return stringTable; + } + + public static LibraryInfo ReadProjectInformationXml(ZipArchive archive, List stringTable, string dumpFilenamePrefix) + { + var entry = archive.Entries.Where(x => x.Name == "projectinformations.auxiliary")?.FirstOrDefault(); + if (entry == null) + return null; + + _logger.Info("Reading Project Information from xml"); + + var stream = entry.Open(); + if (dumpFilenamePrefix != null) + { + _logger.Trace($"Dumping project information file {entry.Name}"); + using (var fileStream = File.Create(dumpFilenamePrefix + ".projectinfo.xml")) + stream.CopyTo(fileStream); + + stream = entry.Open(); + } + + var xdoc = XDocument.Load(stream); + var properties = xdoc.Root.Element("Properties") ?? xdoc.Root.Element("properties"); + if (properties == null) + return null; + + return new LibraryInfo() + { + Company = properties?.Element("Company")?.Value ?? "", + DefaultNamespace = properties?.Element("DefaultNamespace")?.Value ?? "", + Version = properties?.Element("Version")?.Value ?? "", + Title = properties?.Element("Title")?.Value ?? "", + Author = properties?.Element("Author")?.Value ?? "", + Description = properties?.Element("Description")?.Value ?? "", + }; + } + + public static LibraryInfo ReadProjectInformationBin(ZipArchive archive, List stringTable, string dumpFilenamePrefix) + { + var entry = archive.Entries.Where(x => x.Name == "11c0fc3a-9bcf-4dd8-ac38-efb93363e521.object")?.FirstOrDefault(); + if(entry == null ) + return null; + + _logger.Info("Reading Project Information from binary"); + + var stream = entry.Open(); + if (dumpFilenamePrefix != null) + { + _logger.Trace($"Dumping project information file {entry.Name}"); + using (var fileStream = File.Create(dumpFilenamePrefix + ".projectinfo.bin")) + stream.CopyTo(fileStream); + + stream = entry.Open(); + } + + var properties = new Dictionary(); + using (var reader = new BinaryReader(stream)) + { + + var header = reader.ReadBytes(16); + _logger.Trace($"Read header " + BitConverter.ToString(header)); + + var length = ReadLength(reader); + _logger.Trace($"Payload contains {length} bytes"); + + var section_header = reader.ReadBytes(7); + _logger.Trace($"Read section " + BitConverter.ToString(header)); + + while (true) + { + var nameIdx = reader.ReadByte(); + var name = stringTable[nameIdx]; + var type = reader.ReadByte(); + + if ((PropertyType)type == PropertyType.Eof) + { + _logger.Trace("EOF"); + break; + } + + _logger.Trace($"Reading property '{name}' (type: {(Enum.IsDefined(typeof(PropertyType), (Int32)type) ? ((PropertyType)type).ToString() : type.ToString())})"); + switch ((PropertyType)type) + { + case PropertyType.Boolean: + properties[name] = (reader.ReadByte() > 0).ToString(); + break; + //case PropertyType.Number: + // properties[name] = reader.ReadUInt16().ToString(); + // break; + case PropertyType.Text: + properties[name] = stringTable[reader.ReadByte()]; + break; + case PropertyType.Version: + var parts = reader.ReadByte() + 1; // not sure what this is + properties[name] = stringTable[reader.ReadByte()]; + break; + + // here is still something wrong ... + case PropertyType.LibraryCategories: + + var guid = stringTable[reader.ReadByte()]; // For LibraryCategories this is System.Guid + var count = reader.ReadByte(); + + // this is weird, but kinda works ... + if(guid == "System.Guid") + { + var pad2 = reader.ReadBytes(2); + var libCatGuidIndices = reader.ReadBytes(count); // sequence of guids to the libcats + } + else + { + var pad2 = reader.ReadBytes(4); + var pad3 = reader.ReadBytes(7 * count); + } + + break; + } + } + } + + if(!properties.TryGetValue("Title", out string v) || string.IsNullOrEmpty(v)) + _logger.Warn("Title was not parsed correctly"); + + return new LibraryInfo() + { + Company = properties.TryGetValue("Company", out v) ? v : "", + DefaultNamespace = properties.TryGetValue("DefaultNamespace", out v) ? v : "", + Version = properties.TryGetValue("Version", out v) ? v : "", + Title = properties.TryGetValue("Title", out v) ? v : (properties.TryGetValue("Placeholder", out v) ? v : ""), + Author = properties.TryGetValue("Author", out v) ? v : "", + Description = properties.TryGetValue("Description", out v) ? v : "", + }; + } + + public static LibraryInfo Read(byte[] libraryBinary, string dumpFilenamePrefix=null) + { + using (var memoryStream = new MemoryStream(libraryBinary)) + using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Read)) + { + var stringTable = ReadStringTable(zipArchive, dumpFilenamePrefix); + var libraryInfo = ReadProjectInformationXml(zipArchive, stringTable, dumpFilenamePrefix) ?? + ReadProjectInformationBin(zipArchive, stringTable, dumpFilenamePrefix); + + if (libraryInfo == null) + throw new Exceptions.LibraryInvalid("Fileformat is not supported, project information could not be extracted"); + + var dependencies = stringTable.Select(x => Regex.Match(x, @"^([A-Za-z].*?),\s*(.*?)\s*\(([A-Za-z].*)\)$")) + .Where(x => x.Success) + .Select(x => new PlcLibrary() { Name = x.Groups[1].Value, Version = x.Groups[2].Value, DistributorName = x.Groups[3].Value }) + .ToList(); + + return libraryInfo; + } + } + } +} diff --git a/TwinpackShared/TwinpackShared.projitems b/TwinpackShared/TwinpackShared.projitems index a2c0bb9..50ff823 100644 --- a/TwinpackShared/TwinpackShared.projitems +++ b/TwinpackShared/TwinpackShared.projitems @@ -13,7 +13,7 @@ - + diff --git a/TwinpackShared/TwinpackUtils.cs b/TwinpackShared/TwinpackUtils.cs index 7c492da..caa92a5 100644 --- a/TwinpackShared/TwinpackUtils.cs +++ b/TwinpackShared/TwinpackUtils.cs @@ -431,7 +431,7 @@ public static IEnumerable PlcProjectsFromPath(string rootPath { foreach(var libraryFile in Directory.GetFiles(rootPath, "*.library")) { - var libraryInfo = LibraryPropertyReader.Read(File.ReadAllBytes(libraryFile)); + var libraryInfo = LibraryReader.Read(File.ReadAllBytes(libraryFile)); var plc = new ConfigPlcProject() { Name = libraryInfo.Title, diff --git a/TwinpackTests/LibraryPropertyReaderTest.cs b/TwinpackTests/LibraryPropertyReaderTest.cs deleted file mode 100644 index 25b5009..0000000 --- a/TwinpackTests/LibraryPropertyReaderTest.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.IO; - -namespace TwinpackTests -{ - [TestClass] - public class LibraryPropertyReaderTest - { - [TestMethod] - public void TestWithoutPlaceholder() - { - var library = File.ReadAllBytes(@"assets\Untitled1_WithoutPlaceholder.library"); - var libraryInfo = Twinpack.LibraryPropertyReader.Read(library); - - Assert.IsNotNull(library); - Assert.AreEqual("MyCompany", libraryInfo.Company); - Assert.AreEqual("MyLibrary", libraryInfo.Title); - Assert.AreEqual("6.7.8.9", libraryInfo.Version); - Assert.AreEqual("MyDescription", libraryInfo.Description); - Assert.AreEqual("MyAuthor", libraryInfo.Author); - Assert.AreEqual("MyDefaultNamespace", libraryInfo.DefaultNamespace); - } - - [TestMethod] - public void TestWithPlaceholder() - { - var library = File.ReadAllBytes(@"assets\Untitled1_WithPlaceholder.library"); - var libraryInfo = Twinpack.LibraryPropertyReader.Read(library); - - Assert.IsNotNull(library); - Assert.AreEqual("MyCompany", libraryInfo.Company); - Assert.AreEqual("MyLibrary", libraryInfo.Title); - Assert.AreEqual("6.7.8.9", libraryInfo.Version); - Assert.AreEqual("MyDescription", libraryInfo.Description); - Assert.AreEqual("MyAuthor", libraryInfo.Author); - Assert.AreEqual("MyDefaultNamespace", libraryInfo.DefaultNamespace); - Assert.AreEqual(9, libraryInfo.Dependencies.Count); - Assert.AreEqual("Beckhoff Automation GmbH", libraryInfo.Dependencies[3].DistributorName); - Assert.AreEqual("*", libraryInfo.Dependencies[3].Version); - Assert.AreEqual("Tc3_Module", libraryInfo.Dependencies[3].Name); - } - - [TestMethod] - public void TestWithLongDescription() - { - var library = File.ReadAllBytes(@"assets\Untitled1.library"); - var libraryInfo = Twinpack.LibraryPropertyReader.Read(library); - - Assert.IsNotNull(library); - Assert.AreEqual("XY", libraryInfo.Company); - Assert.AreEqual("XY", libraryInfo.Title); - Assert.AreEqual("1.0.0.0", libraryInfo.Version); - Assert.AreEqual(@"123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz 123456790abcdefghijklmnopqrstuvwxyz ", libraryInfo.Description); - Assert.AreEqual("", libraryInfo.Author); - Assert.AreEqual("XY", libraryInfo.DefaultNamespace); - Assert.AreEqual(1, libraryInfo.Dependencies.Count); - Assert.AreEqual("Beckhoff Automation GmbH", libraryInfo.Dependencies[3].DistributorName); - Assert.AreEqual("*", libraryInfo.Dependencies[3].Version); - Assert.AreEqual("Tc3_Module", libraryInfo.Dependencies[3].Name); - } - } -} diff --git a/TwinpackTests/LibraryReaderTest.cs b/TwinpackTests/LibraryReaderTest.cs new file mode 100644 index 0000000..1f9ccb8 --- /dev/null +++ b/TwinpackTests/LibraryReaderTest.cs @@ -0,0 +1,95 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.IO; +using System.IO.Compression; + +namespace TwinpackTests +{ + [TestClass] + public class LibraryReaderTest + { + const string _loremIpsum = @"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. END"; + + [DataTestMethod] + [DataRow(@"assets\Untitled2_libcat.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "MyAuthor", _loremIpsum)] + [DataRow(@"assets\Untitled2_minimal_infos_libcat_mine_theirs_yours_1234.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled2_minimal_infos_libcat_1234.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled1_libcat_child.library", "MyCompany", "MyTitle", "1.0.2.4", "", "", "")] + [DataRow(@"assets\Untitled1_libcat_child2.library", "MyCompany", "MyTitle", "1.0.2.4", "MyDefaultNamespace", "MyAuthor", "MyDescription")] + [DataRow(@"assets\Untitled1_libcat_onlychild_selected.library", "MyCompany", "MyTitle", "1.0.2.4", "MyDefaultNamespace", "MyAuthor", "MyDescription")] + [DataRow(@"assets\Untitled2_minimal_infos_libcat_mine_1234.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled2_minimal_infos_libcat_mine_theirs_1234.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled2_libcat_1234.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "MyAuthor", _loremIpsum)] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_1234.library", "MyCompany", "MyTitle", "1.2.3.4", "", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_n.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_np.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_npa.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "MyAuthor", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_npad.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "MyAuthor", _loremIpsum)] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_rnpad.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "MyAuthor", _loremIpsum)] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_12.library", "MyCompany", "MyTitle", "1.2", "", "", "")] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_123.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_1234.library", "MyCompany", "MyTitle", "1.2.3.4", "", "", "")] + [DataRow(@"assets\Untitled1_4026_00_minimal_infos_123.library", "MyCompany", "MyTitle", "1.0.0", "", "", "")] + public void TestRead(string file, string company, string title, string version, string defaultNamespace, string author, string description) + { + var library = File.ReadAllBytes(file); + var libraryInfo = Twinpack.LibraryReader.Read(library, file); + + Assert.IsNotNull(library); + Assert.AreEqual(company, libraryInfo.Company); + Assert.AreEqual(title, libraryInfo.Title); + Assert.AreEqual(version, libraryInfo.Version); + Assert.AreEqual(defaultNamespace, libraryInfo.DefaultNamespace); + Assert.AreEqual(author, libraryInfo.Author); + Assert.AreEqual(description, libraryInfo.Description); + } + + [DataTestMethod] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_1234.library", "MyCompany", "MyTitle", "1.2.3.4", "", "", "")] + [DataRow(@"assets\Untitled1_4024_35_minimal_infos_123_n.library", "MyCompany", "MyTitle", "1.2.3", "MyDefaultNamespace", "", "")] + public void ReadProjectInformationBin(string file, string company, string title, string version, string defaultNamespace, string author, string description) + { + var library = File.ReadAllBytes(file); + using (var memoryStream = new MemoryStream(library)) + using (var archive = new ZipArchive(memoryStream)) + { + var stringTable = Twinpack.LibraryReader.ReadStringTable(archive, file); + var libraryInfo = Twinpack.LibraryReader.ReadProjectInformationBin(archive, stringTable, file); + + Assert.IsNotNull(library); + Assert.AreEqual(company, libraryInfo.Company); + Assert.AreEqual(title, libraryInfo.Title); + Assert.AreEqual(version, libraryInfo.Version); + Assert.AreEqual(defaultNamespace, libraryInfo.DefaultNamespace); + Assert.AreEqual(author, libraryInfo.Author); + Assert.AreEqual(description, libraryInfo.Description); + } + } + + [DataTestMethod] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_12.library", "MyCompany", "MyTitle", "1.2", "", "", "")] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_123.library", "MyCompany", "MyTitle", "1.2.3", "", "", "")] + [DataRow(@"assets\Untitled1_4024_53_minimal_infos_1234.library", "MyCompany", "MyTitle", "1.2.3.4", "", "", "")] + [DataRow(@"assets\Untitled1_4026_00_minimal_infos_123.library", "MyCompany", "MyTitle", "1.0.0", "", "", "")] + public void ReadProjectInformationXml(string file, string company, string title, string version, string defaultNamespace, string author, string description) + { + var library = File.ReadAllBytes(file); + using (var memoryStream = new MemoryStream(library)) + using (var archive = new ZipArchive(memoryStream)) + { + var stringTable = Twinpack.LibraryReader.ReadStringTable(archive, file); + var libraryInfo = Twinpack.LibraryReader.ReadProjectInformationXml(archive, stringTable, file); + + Assert.IsNotNull(library); + Assert.AreEqual(company, libraryInfo.Company); + Assert.AreEqual(title, libraryInfo.Title); + Assert.AreEqual(version, libraryInfo.Version); + Assert.AreEqual(defaultNamespace, libraryInfo.DefaultNamespace); + Assert.AreEqual(author, libraryInfo.Author); + Assert.AreEqual(description, libraryInfo.Description); + } + } + } +} diff --git a/TwinpackTests/TwinpackTests.csproj b/TwinpackTests/TwinpackTests.csproj index 5b234c6..7c68f11 100644 --- a/TwinpackTests/TwinpackTests.csproj +++ b/TwinpackTests/TwinpackTests.csproj @@ -53,7 +53,7 @@ - + @@ -97,18 +97,87 @@ - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest - + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + Always + + diff --git a/TwinpackTests/assets/Untitled1.library b/TwinpackTests/assets/Untitled1.library deleted file mode 100644 index 1b462f8..0000000 Binary files a/TwinpackTests/assets/Untitled1.library and /dev/null differ diff --git a/TwinpackTests/assets/Untitled1_4024_26_minimal_infos.library b/TwinpackTests/assets/Untitled1_4024_26_minimal_infos.library deleted file mode 100644 index 63c144c..0000000 Binary files a/TwinpackTests/assets/Untitled1_4024_26_minimal_infos.library and /dev/null differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123.library new file mode 100644 index 0000000..fbb8584 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_1234.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_1234.library new file mode 100644 index 0000000..d10f960 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_1234.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_n.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_n.library new file mode 100644 index 0000000..69d3e0f Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_n.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_np.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_np.library new file mode 100644 index 0000000..968f34c Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_np.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npa.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npa.library new file mode 100644 index 0000000..b1fb11d Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npa.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npad.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npad.library new file mode 100644 index 0000000..a2e7863 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_npad.library differ diff --git a/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_rnpad.library b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_rnpad.library new file mode 100644 index 0000000..e0d60f3 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_4024_35_minimal_infos_123_rnpad.library differ diff --git a/TwinpackTests/assets/Untitled1_WithPlaceholder.library b/TwinpackTests/assets/Untitled1_WithPlaceholder.library deleted file mode 100644 index f647b42..0000000 Binary files a/TwinpackTests/assets/Untitled1_WithPlaceholder.library and /dev/null differ diff --git a/TwinpackTests/assets/Untitled1_WithoutPlaceholder.library b/TwinpackTests/assets/Untitled1_WithoutPlaceholder.library deleted file mode 100644 index 6063705..0000000 Binary files a/TwinpackTests/assets/Untitled1_WithoutPlaceholder.library and /dev/null differ diff --git a/TwinpackTests/assets/Untitled1_libcat_child.library b/TwinpackTests/assets/Untitled1_libcat_child.library new file mode 100644 index 0000000..76dc224 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_libcat_child.library differ diff --git a/TwinpackTests/assets/Untitled1_libcat_child2.library b/TwinpackTests/assets/Untitled1_libcat_child2.library new file mode 100644 index 0000000..7b5ea73 Binary files /dev/null and b/TwinpackTests/assets/Untitled1_libcat_child2.library differ diff --git a/TwinpackTests/assets/Untitled1_libcat_onlychild_selected.library b/TwinpackTests/assets/Untitled1_libcat_onlychild_selected.library new file mode 100644 index 0000000..06398ee Binary files /dev/null and b/TwinpackTests/assets/Untitled1_libcat_onlychild_selected.library differ diff --git a/TwinpackTests/assets/Untitled2.libcat.xml b/TwinpackTests/assets/Untitled2.libcat.xml new file mode 100644 index 0000000..fa28170 --- /dev/null +++ b/TwinpackTests/assets/Untitled2.libcat.xml @@ -0,0 +1,16 @@ + + + + d5875a42-817d-44f3-8af7-6c59eaddc95f + 1.1.2.3 + MyParent + + + 426a88ee-bb19-4918-8554-e1c9d24621f9 + 1.1.2.4 + + d5875a42-817d-44f3-8af7-6c59eaddc95f + + MySub + + \ No newline at end of file diff --git a/TwinpackTests/assets/Untitled2_libcat.library b/TwinpackTests/assets/Untitled2_libcat.library new file mode 100644 index 0000000..e9cdafe Binary files /dev/null and b/TwinpackTests/assets/Untitled2_libcat.library differ diff --git a/TwinpackTests/assets/Untitled2_libcat_1234.library b/TwinpackTests/assets/Untitled2_libcat_1234.library new file mode 100644 index 0000000..c8ccadb Binary files /dev/null and b/TwinpackTests/assets/Untitled2_libcat_1234.library differ diff --git a/TwinpackTests/assets/Untitled2_libcat_sub.library b/TwinpackTests/assets/Untitled2_libcat_sub.library new file mode 100644 index 0000000..090a8cd Binary files /dev/null and b/TwinpackTests/assets/Untitled2_libcat_sub.library differ diff --git a/TwinpackTests/assets/Untitled2_minimal_infos_libcat_1234.library b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_1234.library new file mode 100644 index 0000000..fd6d38d Binary files /dev/null and b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_1234.library differ diff --git a/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_1234.library b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_1234.library new file mode 100644 index 0000000..cdfae65 Binary files /dev/null and b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_1234.library differ diff --git a/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_1234.library b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_1234.library new file mode 100644 index 0000000..b2dc88e Binary files /dev/null and b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_1234.library differ diff --git a/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_yours_1234.library b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_yours_1234.library new file mode 100644 index 0000000..52e3da3 Binary files /dev/null and b/TwinpackTests/assets/Untitled2_minimal_infos_libcat_mine_theirs_yours_1234.library differ