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

Support for loading/editing/saving .NET Core single file publish bundles. (#16) #49

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Allow lazy loading of bunde entry data
  • Loading branch information
ElektroKill committed Jun 17, 2023
commit d3d72238f3a2406eddaf3cdca003cfb095650e91
33 changes: 24 additions & 9 deletions dnSpy/dnSpy.Contracts.DnSpy/Documents/Bundles/BundleEntry.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Threading;
using dnlib.IO;

namespace dnSpy.Contracts.Documents {
/// <summary>
/// Represents one entry in a <see cref="SingleFileBundle"/>
/// </summary>
public sealed class BundleEntry {
byte[]? data;
DataReader reader;

/// <summary>
/// Type of the entry <seealso cref="BundleFileType"/>
/// </summary>
Expand All @@ -31,12 +35,25 @@ public sealed class BundleEntry {
/// <summary>
/// The raw data of the entry.
/// </summary>
public byte[] Data { get; }
public byte[] Data {
get {
if (data is not null)
return data;
Interlocked.CompareExchange(ref data, reader.ReadRemainingBytes(), null);
return data;
}
}

BundleEntry(BundleFileType type, string relativePath, byte[] data) {
Type = type;
RelativePath = relativePath.Replace('/', '\\');
Data = data;
this.data = data;
}

BundleEntry(BundleFileType type, string relativePath, DataReader reader) {
Type = type;
RelativePath = relativePath.Replace('/', '\\');
this.reader = reader;
}

internal static IReadOnlyList<BundleEntry> ReadEntries(DataReader reader, int count, bool allowCompression) {
Expand All @@ -49,18 +66,16 @@ internal static IReadOnlyList<BundleEntry> ReadEntries(DataReader reader, int co
var type = (BundleFileType)reader.ReadByte();
string path = reader.ReadSerializedString();

res[i] = new BundleEntry(type, path, ReadEntryData(reader, offset, size, compSize));
if (compSize == 0)
res[i] = new BundleEntry(type, path, reader.Slice((uint)offset, (uint)size));
else
res[i] = new BundleEntry(type, path, ReadCompressedEntryData(reader, offset, size, compSize));
}

return res;
}

static byte[] ReadEntryData(DataReader reader, long offset, long size, long compSize) {
if (compSize == 0) {
reader.Position = (uint)offset;
return reader.ReadBytes((int)size);
}

static byte[] ReadCompressedEntryData(DataReader reader, long offset, long size, long compSize) {
using (var decompressedStream = new MemoryStream((int)size)) {
using (var compressedStream = reader.Slice((uint)offset, (uint)compSize).AsStream()) {
using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) {
Expand Down