Example #1
0
        public async ValueTask <DataSegment> ReadEntryAsync(PakEntry entry, CancellationToken cancellationToken = default)
        {
            var firstSegment = new DataSegment(await ProcessEntryAsync(entry).ConfigureAwait(false));
            var segments     = firstSegment;

            for (var ent = entry.LinkedEntry; ent is not null; ent = ent.LinkedEntry)
            {
                segments = segments.Append(await ProcessEntryAsync(ent).ConfigureAwait(false));
            }
            return(firstSegment);
        }
Example #2
0
        private async ValueTask <IMemoryOwner <byte> > ProcessEntryAsync(PakEntry entry, CancellationToken cancellationToken = default)
        {
            var data = await entry.ReadAsync(SourceStream, cancellationToken);

            if (entry.IsEncrypted)
            {
                if (_aesProvider is null)
                {
                    throw new PakEncryptedException("Pak file contains encrypted entries. AES encryption key is necessary for reading this asset.");
                }

                _aesProvider.Decrypt(data.Memory);
            }
            return(entry.IsCompressed ? await UnrealCompression.DecompressAsync(data, entry) : data);
        }
Example #3
0
        public static IMemoryOwner <byte> Decompress(Memory <byte> compressed, PakEntry entry)
        {
            var decompressed = PakMemoryPool.Shared.Rent((int)entry.UncompressedSize);

            if (MemoryMarshal.TryGetArray <byte>(compressed, out var src) && MemoryMarshal.TryGetArray <byte>(decompressed.Memory, out var dst))
            {
                Decompress(src.Array !, src.Offset, src.Count, dst.Array !, dst.Offset, dst.Count, entry);
            }
            else
            {
                decompressed.Dispose();
                throw new NotImplementedException();
                //Decompress(data.Memory.ToArray(), 0, data.Memory.Length, buffer, compressionBlocks);
            }
            return(decompressed);
        }
Example #4
0
        private IMemoryOwner <byte> ProcessEntry(PakEntry entry)
        {
            var data = entry.Read(SourceStream);

            if (entry.IsEncrypted)
            {
                if (_aesProvider is null)
                {
                    throw new PakEncryptedException("Pak file contains encrypted entries. AES encryption key is necessary for reading this asset.");
                }

                // decrypts data inplace
                _aesProvider.Decrypt(data.Memory);
            }
            return(entry.IsCompressed ? UnrealCompression.Decompress(data, entry) : data);
        }
Example #5
0
        private void ProcessIndex(FArchive reader)
        {
            FString?mountPoint = default;
            int     entryCount = 0;

            reader.Read(ref mountPoint)
            .Read(ref entryCount);
            MountPoint    = mountPoint.ToString().Replace("../../../", null);
            AbsoluteIndex = new Dictionary <string, PakEntry>(entryCount);

            for (var i = 0; i < entryCount; i++)
            {
                FString?fileName = default;
                reader.Read(ref fileName);
                var filePath = Path.Combine(MountPoint, fileName.ToString());
                var entry    = new PakEntry(this, Path.GetFileName(filePath));
                entry.Serialize(reader);
                AbsoluteIndex.Add(filePath, entry);
            }

            // TODO: Change this to something working better
            foreach (var kv in AbsoluteIndex)
            {
                var val = kv.Value;
                if (kv.Value.IsCompressed)
                {
                    val.CompressionBlocks.OffsetBy((int)val.EntryHeaderSize);
                }

                if (kv.Key.EndsWith(".uasset"))
                {
                    var expPath = Path.ChangeExtension(kv.Key, ".uexp");
                    if (AbsoluteIndex.TryGetValue(expPath, out var exports))
                    {
                        val.LinkedEntry = exports;
                        var bulkPath = Path.ChangeExtension(kv.Key, ".ubulk");
                        if (AbsoluteIndex.TryGetValue(bulkPath, out var bulk))
                        {
                            exports.LinkedEntry = bulk;
                        }
                    }
                }
            }
        }
Example #6
0
        public DataSegment ReadEntry(PakEntry entry)
        {
            DataSegment firstSegment = null !, segments = null;

            for (var ent = entry; ent is not null; ent = ent.LinkedEntry)
            {
                var entryData = ProcessEntry(ent);
                if (segments is null)
                {
                    segments = firstSegment = new DataSegment(entryData);
                }
                else
                {
                    segments = segments.Append(entryData);
                }
                segments.Tag(Path.GetExtension(ent.FileName));
            }
            return(firstSegment);
        }
Example #7
0
        private static async ValueTask DecompressEntryAsync(MemoryStream mem, byte[] destination, int dstOffset, int dstCount, PakEntry entry, int progress = 0, CancellationToken cancellationToken = default)
        {
            foreach (var block in entry.CompressionBlocks)
            {
                mem.Seek(block.Start, SeekOrigin.Begin);
                using var stream = GetDecompressStream(mem, entry.CompressionMethod);
                var read = 0;
                do
                {
                    read = await stream.ReadAsync(destination, dstOffset + progress, dstCount - progress, cancellationToken).ConfigureAwait(false);

                    progress += read;
                } while (read > 0);
            }
        }
Example #8
0
 public static async ValueTask DecompressAsync(byte[] source, int srcOffset, int srcCount, byte[] destination, int dstOffset, int dstCount, PakEntry entry, CancellationToken cancellationToken = default)
 {
     using var mem = new MemoryStream(source, srcOffset, srcCount);
     await DecompressEntryAsync(mem, destination, dstOffset, dstCount, entry, cancellationToken : cancellationToken).ConfigureAwait(false);
 }
Example #9
0
        public static async ValueTask <IMemoryOwner <byte> > DecompressAsync(Memory <byte> compressed, PakEntry entry, CancellationToken cancellationToken = default)
        {
            var decompressed = PakMemoryPool.Shared.Rent((int)entry.UncompressedSize);

            if (MemoryMarshal.TryGetArray <byte>(compressed, out var src) && MemoryMarshal.TryGetArray <byte>(decompressed.Memory, out var dst))
            {
                await DecompressAsync(src.Array !, src.Offset, src.Count, dst.Array !, dst.Offset, dst.Count, entry, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                decompressed.Dispose();
                throw new NotImplementedException();
            }
            return(decompressed);
        }
Example #10
0
 public static async ValueTask <IMemoryOwner <byte> > DecompressAsync(IMemoryOwner <byte> compressedData, PakEntry entry)
 {
     using var data = compressedData;
     return(await DecompressAsync(data.Memory, entry));
 }
Example #11
0
 private static void DecompressEntry(MemoryStream mem, byte[] destination, int dstOffset, int dstCount, PakEntry entry, int progress = 0)
 {
     foreach (var block in entry.CompressionBlocks)
     {
         mem.Seek(block.Start, SeekOrigin.Begin);
         using var stream = GetDecompressStream(mem, entry.CompressionMethod);
         var read = 0;
         do
         {
             read      = stream.Read(destination, dstOffset + progress, dstCount - progress);
             progress += read;
         } while (read > 0);
     }
 }
Example #12
0
 public static void Decompress(byte[] source, int srcOffset, int srcCount, byte[] destination, int dstOffset, int dstCount, PakEntry entry)
 {
     using var mem = new MemoryStream(source, srcOffset, srcCount);
     DecompressEntry(mem, destination, dstOffset, dstCount, entry);
 }
Example #13
0
 public static void Decompress(byte[] source, byte[] destination, PakEntry entry) => Decompress(source, 0, source.Length, destination, 0, destination.Length, entry);
Example #14
0
 public static IMemoryOwner <byte> Decompress(IMemoryOwner <byte> compressedData, PakEntry entry)
 {
     using var data = compressedData;
     return(Decompress(data.Memory, entry));
 }