Lesen Sie falsche Daten mit C# (benutzerdefinierte PAK -Datei)C#

Ein Treffpunkt für C#-Programmierer
Anonymous
 Lesen Sie falsche Daten mit C# (benutzerdefinierte PAK -Datei)

Post by Anonymous »

Ich versuche, meine eigene Game Engine zu schreiben. Ich habe die Dateien wie Vermögenswerte der Spiele verpackt, damit die Engine sie schneller und einfacher lesen kann. Ich habe jedoch auf ein Problem gestoßen. Ich konnte die Quelle des Problems nicht finden. Wenn ich versuche, Daten aus der von mir erstellten PAK -Datei zu lesen, gibt es eine Abweichung in den von mir gelesenen Daten. Ich kann die Daten nicht richtig lesen. < /P>
Dateistruktur: < /p>

Code: Select all

[Header]
[Index Table]
[Asset Data]
< /code>
Codes: < /p>
namespace EngineCore
{
public class PakEntry
{
public string Name { get; set; }
public byte Type { get; set; }
public uint Offset { get; set; }
public uint Size { get; set; }
}
}
< /code>
namespace EngineCore
{
public interface IPakReaderBackend
{
byte[] Read(PakEntry entry);
void Dispose();
}
}
< /code>
using System;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace EngineCore
{
public class MemoryMappedBackend : IPakReaderBackend, IDisposable
{
private readonly MemoryMappedFile mmf;
private MemoryMappedViewAccessor accessor;

public MemoryMappedBackend(string path)
{
mmf = MemoryMappedFile.CreateFromFile(path, FileMode.Open);
}

public byte[] Read(PakEntry entry)
{
using var accessor = mmf.CreateViewAccessor(entry.Offset, entry.Size, MemoryMappedFileAccess.Read);
byte[] buffer = new byte[entry.Size];
accessor.ReadArray(0, buffer, 0, buffer.Length);
return buffer;
}

public void Dispose()
{
accessor?.Dispose();
mmf?.Dispose();
GC.SuppressFinalize(this);
}
}
}
< /code>
using System.IO;

namespace EngineCore
{
public class SeekAndReadBackend : IPakReaderBackend
{
private readonly string pakFilePath;

public SeekAndReadBackend(string path)
{
pakFilePath = path;
}

public byte[] Read(PakEntry entry)
{
byte[] buffer = new byte[entry.Size];
using (FileStream fs = new FileStream(pakFilePath, FileMode.Open, FileAccess.Read))
{
fs.Seek(entry.Offset, SeekOrigin.Current);
fs.Read(buffer, 0, buffer.Length);
}
return buffer;
}

public void Dispose() { }
}
}
< /code>
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace EngineCore
{
public class PakWriter : IDisposable
{
private const string Magic = "TGPAK";
private const ushort Version = 1;
private readonly List  entries;
private readonly MemoryStream dataStream;

public PakWriter()
{
entries = new List();
dataStream = new MemoryStream();
}

public void AddFile(string filePath, byte type)
{
byte[] fileData = File.ReadAllBytes(filePath);
uint offset = (uint)dataStream.Position;

dataStream.Write(fileData, 0, fileData.Length);

entries.Add(new PakEntry
{
Name = Path.GetFileName(filePath),
Type = type,
Offset = offset,
Size = (uint)fileData.Length
});
}

public void Save(string outputPath)
{
using (FileStream fs = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
bw.Write(Encoding.ASCII.GetBytes(Magic.PadRight(6, '\0')));
bw.Write(Version);
bw.Write((uint)entries.Count);
long indexOffsetPos = fs.Position;
bw.Write((uint)0);

dataStream.Seek(0, SeekOrigin.Begin);
dataStream.CopyTo(fs);

long indexOffset = fs.Position;

foreach (var entry in entries)
{
byte[] nameBytes = Encoding.UTF8.GetBytes(entry.Name);
bw.Write((byte)nameBytes.Length);
bw.Write(nameBytes);
bw.Write(entry.Type);
bw.Write(entry.Offset);
bw.Write(entry.Size);
}

fs.Seek(indexOffsetPos, SeekOrigin.Begin);
bw.Write((uint)indexOffset);
}
}
}

public void Dispose()
{
entries.Clear();
dataStream?.Dispose();
GC.SuppressFinalize(this);
}
}
}
< /code>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace EngineCore
{
public class PakReader : IDisposable
{
public List Entries { get; private set; } = new List();
private readonly IPakReaderBackend backend;

public PakReader(string filePath, bool useMemoryMapping = false)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader br = new BinaryReader(fs))
{
string magic = Encoding.ASCII.GetString(br.ReadBytes(6)).TrimEnd('\0');
if (magic != "TGPAK") throw new Exception("Invalid pak");

ushort version = br.ReadUInt16();
uint entryCount = br.ReadUInt32();
uint indexOffset = br.ReadUInt32();

fs.Seek(indexOffset, SeekOrigin.Begin);
for (int i = 0; i < entryCount; i++)
{
byte nameLen = br.ReadByte();
string name = Encoding.UTF8.GetString(br.ReadBytes(nameLen));
byte type = br.ReadByte();
uint offset = br.ReadUInt32();
uint size = br.ReadUInt32();

Entries.Add(new PakEntry
{
Name = name,
Type = type,
Offset = offset,
Size = size
});
}
}
}
backend = useMemoryMapping ? new MemoryMappedBackend(filePath) : new SeekAndReadBackend(filePath);
}

public byte[] Read(string name)
{
PakEntry entry = Entries.FirstOrDefault(e =>  e.Name == name);
if (entry == null)
{
return null;
}
return backend.Read(entry);
}

public void Dispose()
{
backend.Dispose();
GC.SuppressFinalize(this);
}
}
}
< /code>
Test < /p>
// Write
PakWriter pakW = new PakWriter();
pakW.AddFile("Assets/Test1.txt", 7);
pakW.AddFile("Assets/Test2.txt", 7);
pakW.AddFile("Assets/Player.fbx", 3);
pakW.AddFile("Assets/Wall.res", 5);
pakW.Save("Bin/data.pak");
pakW.Dispose();

// Read
PakReader pakR = new PakReader("Bin/data.pak");
Console.WriteLine("Assets:");
foreach (PakEntry entry in pakR.Entries)
{
Console.WriteLine($" - {entry.Name} (Type: {entry.Type}, Size: {entry.Size} bytes)");
}
byte[] data = pakR.Read("Test2.txt");
Console.WriteLine("Test2:" + Encoding.UTF8.GetString(data));
Console.ReadLine();
pakR.Dispose();
< /code>
Ausgabe: < /p>
Assets:
- Test1.txt (Type: 7, Size: 20 bytes)
- Test2.txt (Type: 7, Size: 20 bytes)
- Player.fbx (Type: 3, Size: 759512 bytes)
- Wall.res (Type: 5, Size: 13544 bytes)
Test2:AAAAAAAAAAAAAAAABBBB

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post