krivetko-man
Member
- Joined
- Nov 22, 2008
- Messages
- 53
- Reaction score
- 62
- Banned
- #1
Code:
using Nemerle.Utility;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
namespace Stalker_Mod_Manager
{
public class StalkerDB : GameDB
{
#region nested types
public enum Type
{
| CS;
| SocEn;
| SocRu;
}
[ Record ]
private class FileEntry
{
[ Accessor ] private _offset : int;
[ Accessor ] private _size : int;
[ Accessor ] private _file : string;
}
private class BitStack
{
private _bits : BitArray;
private mutable _iter : int;
public this(data : array[byte], start : int, length : int)
{
when (start < 0 || start > data.Length)
throw ArgumentOutOfRangeException("The specified start is not inside the array.");
when (length < 0)
throw ArgumentOutOfRangeException("Length must be non-negative.");
when (start + length > data.Length)
throw ArgumentOutOfRangeException("The specified range is not inside the array.");
_bits = BitArray(length * 8);
_iter = 0;
for (mutable i = start; i != start + length; ++i)
{
mutable n : int = data[i];
repeat (8)
{
_bits.Set(_iter, n & 0x80 != 0);
n <<= 1;
++_iter;
}
}
_iter = 0;
}
public PopByte() : byte
{
mutable n = 0;
when (_bits.Get(_iter))
n |= 1;
++_iter;
repeat (7)
{
n <<= 1;
when (_bits.Get(_iter))
n |= 1;
++_iter;
}
n :> byte;
}
public PopBit() : int
{
def result = if(_bits[_iter]) 1 else 0;
++_iter;
result;
}
}
#endregion
#region state
private _fileEntries : Dictionary.[string, FileEntry];
private _dbPath : string;
#endregion
#region interface
public this(dbPath : string, dbType : StalkerDB.Type)
{
def ForEachDbCs(Do)
{
foreach (dir in [ "levels", "localization", "mp", "resources", "patches" ])
{
def dbs = Directory.GetFiles(Path.Combine(dbPath, dir), "*.db*");
Array.Sort(dbs, StringComparer.InvariantCultureIgnoreCase);
foreach (path in dbs)
Do(path, Path.Combine(dir, Path.GetFileName(path)));
}
}
def ForEachDbSoC(Do)
{
def dbs = Directory.GetFiles(dbPath, "gamedata.db*");
Array.Sort(dbs, StringComparer.InvariantCultureIgnoreCase);
foreach (path in dbs)
Do(path, Path.GetFileName(path));
}
def ProcessDb(absolutePath, relativePath)
{
using (def reader = BinaryReader(File.OpenRead(absolutePath)))
ReadDatabase(reader, relativePath, dbType);
}
_dbPath = dbPath;
_fileEntries = Dictionary(StringComparer.OrdinalIgnoreCase);
match (dbType)
{
| SocRu | SocEn => ForEachDbSoC(ProcessDb);
| CS => ForEachDbCs(ProcessDb);
}
}
public OpenRead(filePath : string) : Stream
{
if (_fileEntries.ContainsKey(filePath))
{
def entry = _fileEntries[filePath];
StalkerDBStream(Path.Combine(_dbPath, entry.File), entry.Offset, entry.Size);
}
else
{
throw FileNotFoundException($"The database does not contain \"$filePath\"");
}
}
public Exists(path : string) : bool
{
_fileEntries.ContainsKey(path);
}
public GetFiles() : IEnumerable.[string]
{
foreach (entry when entry.Value.Size > 0 in _fileEntries)
yield entry.Key;
}
public override ToString() : string
{
def builder = System.Text.StringBuilder();
foreach (pair in _fileEntries)
{
_ = builder.AppendLine($"$(pair.Key) ($(pair.Value.Offset), $(pair.Value.Size))");
}
builder.ToString();
}
#endregion
#region implementation
private ReadDatabase
( reader : BinaryReader
, dbFile : string
, dbType : StalkerDB.Type
) : void
{
mutable indexFound = false;
while (!indexFound)
{
def flag = reader.ReadUInt32();
def offset = reader.ReadInt32();
if (flag & 0x7FFFFFFF == 1)
{
indexFound = true;
def data = reader.ReadBytes(offset);
match (dbType)
{
| SocRu => DecryptRu(data);
| SocEn => DecryptEn(data);
| CS => ()
}
def index_size : int
= (data[3] << 0x18)
| (data[2] << 0x10)
| (data[1] << 0x08)
| (data[0] << 0x00);
def result = Decompress(BitStack(data, 4, offset - 4), index_size);
foreach ((size, _, _, path, offset) in ParseIndex(result))
{
if (_fileEntries.ContainsKey(path))
_fileEntries[path] = FileEntry(offset, size, dbFile);
else
_fileEntries.Add(path, FileEntry(offset, size, dbFile));
}
}
else
{
_ = reader.BaseStream.Seek(offset, SeekOrigin.Current);
}
}
}
private static ParseIndex(index : IEnumerable.[byte]) : IEnumerable.[int * int * int * string * int]
{
def i = index.GetEnumerator();
// iteration
mutable dataRemains;
def MoveNext() : void
{
dataRemains = i.MoveNext();
}
// general parsing
def ParseChar() : char
{
def c = i.Current :> char;
MoveNext();
c;
}
def ParseString(length) : string
{
def chars = array(length);
foreach (i in [0 .. length - 1])
chars[i] = ParseChar();
string(chars);
}
def ParseHalfWord() : int
{
def lw = i.Current;
MoveNext();
def hw = i.Current;
MoveNext();
(hw << 0x8) | lw;
}
def ParseWord() : int
{
mutable n = 0;
mutable shift = 0;
repeat (4)
{
n |= i.Current << shift;
shift += 0x8;
MoveNext();
}
n;
}
// main loop
MoveNext();
while (dataRemains)
{
def entryLength = ParseHalfWord();
yield
( ParseWord()
, ParseWord()
, ParseWord()
, ParseString(entryLength - 0x10)
, ParseWord()
);
}
}
private static DecryptEn(data : array[byte]) : void
{
unchecked
{
def a1 : array[byte] = array(0x100);
def a2 : array[byte] = array(0x100);
for (mutable i = 0; i != 0x100; ++i)
{
a1[i] = i :> byte;
}
mutable seed : uint = 0x5BBC4B;
for (mutable i = 0; i != 0x400; ++i)
{
seed = seed * 0x8088405 + 1;
mutable v1 : uint = seed >> 0x18;
seed = seed * 0x8088405 + 1;
mutable v2 : uint = seed >> 0x18;
while (v1 == v2)
{
seed = seed * 0x8088405 + 1;
v2 = seed >> 0x18;
}
a1[v1 :> int] <-> a1[v2 :> int];
}
for (mutable i = 0; i != 0x100; ++i)
{
a2[a1[i] :> int] = i :> byte;
}
seed = 0x16EB2EB;
for (mutable i = 0; i != data.Length; ++i)
{
seed = seed * 0x8088405 + 1;
def index = data[i] ^ (seed >> 0x18);
data[i] = a2[index :> int];
}
}
}
private static DecryptRu(data : array[byte]) : void
{
unchecked
{
def a1 : array[byte] = array(0x100);
def a2 : array[byte] = array(0x100);
for (mutable i = 0; i != 0x100; ++i)
{
a1[i] = i :> byte;
}
mutable seed : uint = 0x1329436;
for (mutable i = 0; i != 0x800; ++i)
{
seed = seed * 0x8088405 + 1;
mutable v1 : uint = seed >> 0x18;
seed = seed * 0x8088405 + 1;
mutable v2 : uint = seed >> 0x18;
while (v1 == v2)
{
seed = seed * 0x8088405 + 1;
v2 = seed >> 0x18;
}
a1[v1 :> int] <-> a1[v2 :> int];
}
for (mutable i = 0; i != 0x100; ++i)
{
a2[a1[i] :> int] = i :> byte;
}
seed = 0x131A9D3;
for (mutable i = 0; i != data.Length; ++i)
{
seed = seed * 0x8088405 + 1;
def index = data[i] ^ (seed >> 0x18);
data[i] = a2[index :> int];
}
}
}
private static Decompress(data : BitStack, index_size : int) : IEnumerable.[byte]
{
// declare arrays
def weights : array[int] = array(0x274);
def parents : array[int] = array(0x3AD);
def children : array[int] = array(0x273);
def buffer : array[byte] = array(0x103B);
def table : array[int] = array
[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09
, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B
, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F
, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13
, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17
, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F
, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27
, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F
, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04
, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06
, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
];
// initialize arrays
foreach (i in [0 .. 0x139])
{
weights[i] = 1;
parents[i+0x273] = i;
children[i] = i + 0x273;
}
foreach (j in [0x13A .. 0x272])
{
def i = (j - 0x13A) * 2;
weights[j] = weights[i] + weights[i + 1];
parents[i] = j;
parents[i + 1] = j;
children[j] = i;
}
weights[0x273] = 0xFFFF;
parents[0x272] = 0x0000;
// decode
mutable SI : int = 0xFC4;
foreach (i in [0 .. SI-1])
{
buffer[i] = 0x20;
}
def decoded = Queue.[byte]();
while (decoded.Count < index_size)
{
mutable leaf = children[0x272];
while (leaf < 0x273)
{
leaf += data.PopBit();
leaf = children[leaf];
}
leaf = leaf - 0x273;
when (weights[0x272] == 0x4000)
{
// half all child weights amd move children together
{
mutable j = 0;
foreach (i in [0 .. 0x272])
{
when (children[i] >= 0x273)
{
weights[j] = (weights[i] + 1) / 2;
children[j] = children[i];
++j;
}
}
}
// recalculate branches
foreach (j in [0x13A .. 0x272])
{
def i = (j - 0x13A) * 2;
// reset branch weight
def branchWeight = weights[i] + weights[i + 1];
weights[j] = branchWeight;
// keep branches sorted
mutable start = j - 1;
while (weights[start] > branchWeight)
{
--start;
}
++start;
Array.Copy(weights, start, weights, start + 1, j - start);
weights[start] = branchWeight;
Array.Copy(children, start, children, start + 1, j - start);
children[start] = i;
}
// sync parents
foreach (i in [0 .. 0x272])
{
def child = children[i];
parents[child] = i;
when (child < 0x273)
parents[child + 1] = i;
}
}
// update the tree
{
mutable first = parents[leaf + 0x273];
do
{
++weights[first]; // increment the leaf's weight
mutable firstWeight = weights[first]; // new weight
mutable last = first + 1; // next node
when (weights[last] < firstWeight)
{
while (weights[last] < firstWeight)
++last;
--last;
// switch weights
weights[first] <-> weights[last];
// switch children
def firstChild = children[first];
def lastChild = children[last];
children[first] <-> children[last];
// switch parents
parents[firstChild] = last;
when (firstChild < 0x273)
parents[firstChild + 1] = last;
parents[lastChild] = first;
when (lastChild < 0x273)
parents[lastChild + 1] = first;
// switch iterators
first = last;
}
first = parents[first];
} while (first != 0);
}
if (leaf < 0x100)
{
decoded.Enqueue(leaf :> byte);
buffer[SI] = leaf :> byte;
SI = (SI + 1) & 0x0FFF;
}
else
{
mutable offset = data.PopByte() :> int;
def high_bits = table[offset] << 6;
def count = table[offset + 0x100];
repeat (count - 2)
{
offset = (offset << 1) | data.PopBit();
}
def _tempOffset = offset;
offset = (high_bits | (offset & 0x3F)) + 1;
def EBP_E = 0xFFF & (SI - offset);
foreach (i in [0 .. leaf - 0xFE])
{
def value = buffer[0x0FFF & (EBP_E + i)];
decoded.Enqueue(value);
buffer[SI] = value;
SI = (SI + 1) & 0x0FFF;
}
}
}
decoded;
}
#endregion
}
Особенно важны:
private static DecryptEn(data : array[byte]) : void
private static DecryptRu(data : array[byte]) : void
private static Decompress(data : BitStack, index_size : int) : IEnumerable.[byte]
Очень очень надо!!! Сколько ни пытаюсь понять что здесь происходить, не понимаю!!!