Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pull Request] Crequency/KitX#278 #1

Merged
merged 24 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
467f0d1
📝 Chore(git): Init `.gitignore` file.
Dynesshely Feb 7, 2024
0277166
📝 Chore(Submodules): Sync.
Dynesshely Feb 7, 2024
42fa849
💾 Feat: Moving items from `KitX Rules`.
Dynesshely Feb 7, 2024
1d39850
📝 Chore(Submodules): Removed `KitX Rules`.
Dynesshely Feb 7, 2024
f87eb77
💾 Feat(FileFormats): Move encoders/decoders' codes here.
Dynesshely Feb 7, 2024
bccee06
📝 Chore(Submodules): Optimized.
Dynesshely Feb 7, 2024
29225b3
🎇 Style: Optimized.
Dynesshely Feb 7, 2024
65986d0
💾 Feat: Optimized.
Dynesshely Feb 7, 2024
04c8779
📝 Chore: Optimized.
Dynesshely Feb 8, 2024
8dc0cf2
📝 Chore(Submodules): Sync.
Dynesshely Feb 8, 2024
a33e6b5
💾 Feat(Device): Add `AppleVisionOS` (12) to `OperatingSystems`.
Dynesshely Feb 15, 2024
fa9e53c
📝 Chore(KitX.Shared): Version rule added.
Dynesshely Feb 16, 2024
335f1e7
💾 📦 Feat, Struct(KitX.Shared.Dart): Init package.
Dynesshely Feb 16, 2024
f09b937
📄 Docs(LICENSE): Init.
Dynesshely Feb 16, 2024
6868c13
💾 Feat: Implemented json models under `device` folder.
Dynesshely Feb 16, 2024
da761a1
🧩 Refactor: Rename something.
Dynesshely Feb 16, 2024
a1b978e
💾 Feat(Device): Changed `deviceMacAddress` -> `macAddress` in `Device…
Dynesshely Feb 16, 2024
4303287
💾 Feat(Shared): Added `Value` property to `Function` and `Parameter`.
Dynesshely Feb 19, 2024
ee8d67d
💾 Feat(SDK, Standard): Adapt `Loader.CSharp` and `TestPlugin.WPF.Core…
Dynesshely Feb 20, 2024
f6fe9d2
💾 Feat(SDK, Standard): Adapt `Loader.CSharp` and `TestPlugin.WPF.Core…
Dynesshely Feb 20, 2024
600d706
📝 Chore: Updated.
Dynesshely Feb 20, 2024
a9134a4
📝 Chore(Submodules): Sync.
Dynesshely Feb 20, 2024
d190b00
💾 Feat: The first time that dashboard invoke plugin function throw ne…
Dynesshely Feb 25, 2024
91f4e9e
📝 Chore(Submodules): Sync.
Dynesshely Feb 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
797 changes: 797 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

12 changes: 0 additions & 12 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
[submodule "KitX Contracts"]
path = KitX Contracts
url = git@github.com:Crequency/KitX-Contracts.git
[submodule "KitX File Formats"]
path = KitX File Formats
url = git@github.com:Crequency/KitX-File-Formats.git
[submodule "KitX Loaders"]
path = KitX Loaders
url = git@github.com:Crequency/KitX-Loaders.git
[submodule "KitX Plugins"]
path = KitX Plugins
url = git@github.com:Crequency/KitX-Plugins.git
[submodule "KitX Rules"]
path = KitX Rules
url = git@github.com:Crequency/KitX-Rules.git
[submodule "KitX Script"]
path = KitX Script
url = git@github.com:Crequency/KitX-Script.git
2 changes: 1 addition & 1 deletion KitX Contracts
1 change: 0 additions & 1 deletion KitX File Formats
Submodule KitX File Formats deleted from 50b818
1 change: 0 additions & 1 deletion KitX Loaders
Submodule KitX Loaders deleted from 49dbb6
1 change: 0 additions & 1 deletion KitX Plugins
Submodule KitX Plugins deleted from bbb51b
1 change: 0 additions & 1 deletion KitX Rules
Submodule KitX Rules deleted from 646eb4
2 changes: 1 addition & 1 deletion KitX Script
220 changes: 220 additions & 0 deletions KitX.FileFormats/ExtensionsPackage/Decoder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace KitX.FileFormats.ExtensionsPackage;

public class Decoder
{
public Decoder(string packagePath, Options? options = null)
{
PackagePath = packagePath;

Options = options ?? new();
}

public string PackagePath { get; set; }

public Options Options { get; set; }

internal struct FileMapItem
{
internal long FileNamePathLength;

internal long FileBodyLength;
}

public Tuple<string, string> GetLoaderAndPluginInfo()
{
var fs = new FileStream(PackagePath, FileMode.Open, FileAccess.Read);
var reader = new BinaryReader(fs);

var header = reader.ReadBytes(16);

if (!Header.IsKXP(ref header))
throw new InvalidDataException("It's not a KXP Package.");

_ = reader.ReadBytes(16);

long loaderStructLength, pluginStructLength;

loaderStructLength = BitConverter.ToInt64(reader.ReadBytes(8), 0);

var loaderStructString = Encoding.UTF8.GetString(reader.ReadBytes((int)loaderStructLength));

pluginStructLength = BitConverter.ToInt64(reader.ReadBytes(8), 0);

var pluginStructString = Encoding.UTF8.GetString(reader.ReadBytes((int)pluginStructLength));

var result = new Tuple<string, string>(loaderStructString, pluginStructString);

reader.Close();
fs.Close();

return result;
}

public Tuple<string, string> Decode(string releaseFolder)
{
if (!Directory.Exists(releaseFolder))
_ = Directory.CreateDirectory(releaseFolder);

var src = File.ReadAllBytes(PackagePath);

#region 获取文件表头, 验证文件是否为 KXP 文件 (0 - 15)

var header = new byte[16]; // 文件标头

for (int i = 0; i < 16; ++i) header[i] = src[i];

if (!Header.IsKXP(ref header))
throw new Exception("It's not a KXP Package.");

#endregion

#region 获取哈希校验值 (16 - 31)

var hash = new byte[16]; // 哈希部分

var cursor = 16; // 文件流指针

for (; cursor < 32; ++cursor) // 取出哈希部分的字节
hash[cursor - 16] = src[cursor];

if (Options.Verbose)
Console.WriteLine($"Hash Code: {Encoding.UTF8.GetString(hash)}");

#endregion

#region 获取 LoaderStruct 部分

var loaderStructLengthByte = new byte[8];

for (int i = 0; i < 8; ++i, ++cursor) loaderStructLengthByte[i] = src[cursor];

var loaderStructLength = BitConverter.ToInt64(loaderStructLengthByte, 0);

if (Options.Verbose)
Console.WriteLine($"Loader Struct Length: {loaderStructLength}");

var loaderStructByte = new byte[loaderStructLength]; // Loader Struct 的 Byte 数组

for (int i = 0; i < loaderStructLength; ++i, ++cursor) loaderStructByte[i] = src[cursor];

#endregion

#region 获取 PluginStruct 部分

var pluginStructLengthByte = new byte[8];

for (int i = 0; i < 8; ++i, ++cursor) pluginStructLengthByte[i] = src[cursor];

var pluginStructLength = BitConverter.ToInt64(pluginStructLengthByte, 0);

if (Options.Verbose)
Console.WriteLine($"Plugin Struct Length: {pluginStructLength}");

var pluginStructByte = new byte[pluginStructLength]; // Plugin Struct 的 Byte 数组

for (int i = 0; i < pluginStructLength; ++i, ++cursor) pluginStructByte[i] = src[cursor];

#endregion

#region 获取 LoaderStruct 和 PluginStruct 字符串

var loaderStruct = Encoding.UTF8.GetString(loaderStructByte);
var pluginStruct = Encoding.UTF8.GetString(pluginStructByte);

if (Options.Verbose)
{
Console.WriteLine($"Loader Struct: {loaderStruct}");
Console.WriteLine($"Plugin Struct: {pluginStruct}");
}

#endregion

#region 获取文件地图

var fileMapLengthByte = new byte[8]; // 文件地图长度

for (int i = 0; i < 8; ++i, ++cursor) fileMapLengthByte[i] = src[cursor];

var fileMapLength = BitConverter.ToInt64(fileMapLengthByte, 0);

if (Options.Verbose)
Console.WriteLine($"File Map Length: {fileMapLength}");

var FileMap = new List<FileMapItem>(); // 文件地图

for (long i = 0; i < fileMapLength; ++i)
{
var fileNameLength = new byte[8]; // 文件名长度
var fileBodyLength = new byte[8]; // 文件体长度
for (int j = 0; j < 8; ++j, ++cursor) fileNameLength[j] = src[cursor];
for (int j = 0; j < 8; ++j, ++cursor) fileBodyLength[j] = src[cursor];

FileMap.Add(new FileMapItem()
{
FileNamePathLength = BitConverter.ToInt64(fileNameLength, 0),
FileBodyLength = BitConverter.ToInt64(fileBodyLength, 0)
});

if (Options.Verbose)
{
Console.WriteLine($"File Name Length: {BitConverter.ToInt64(fileNameLength, 0)}");
Console.WriteLine($"File Body Length: {BitConverter.ToInt64(fileBodyLength, 0)}");
}
}

#endregion

#region 获取源文件文件名与文件体并立即写回释放文件夹

foreach (var item in FileMap)
{
var fn = new byte[item.FileNamePathLength];
var fb = new byte[item.FileBodyLength];

for (int i = 0; i < item.FileNamePathLength; ++i, ++cursor)
fn[i] = src[cursor];

for (int i = 0; i < item.FileBodyLength; ++i, ++cursor)
fb[i] = src[cursor];

var fileName = Encoding.UTF8.GetString(fn);
var dirPath = Path.GetDirectoryName(
Path.GetFullPath($"{releaseFolder}/{fileName}")
);

if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);

File.WriteAllBytes($"{releaseFolder}/{fileName}", fb);
}

#endregion

#region 计算哈希校验值

using var md5 = MD5.Create();

var localHash = md5.ComputeHash(src, 32, src.Length - 32);

if (Options.Verbose)
Console.WriteLine($"Local Hash Code: {Encoding.UTF8.GetString(localHash)}");

#endregion

#region 哈希校验不一样时抛出异常

for (var i = 0; i < 16; ++i)
if (!hash[i].Equals(localHash[i]))
throw new Exception("MD5 Hash Error.");

#endregion

return Tuple.Create(loaderStruct, pluginStruct);
}
}
Loading