529 lines
22 KiB
C#
529 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace Pillager
|
|
{
|
|
public class SQLiteHandler
|
|
{
|
|
private readonly byte[] db_bytes;
|
|
private readonly ulong encoding;
|
|
private string[] field_names = new string[1];
|
|
private sqlite_master_entry[] master_table_entries;
|
|
private readonly ushort page_size;
|
|
private readonly byte[] SQLDataTypeSize = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0 };
|
|
private table_entry[] table_entries;
|
|
|
|
public SQLiteHandler(string baseName)
|
|
{
|
|
if (File.Exists(baseName))
|
|
{
|
|
db_bytes = File.ReadAllBytes(baseName);
|
|
if (Encoding.Default.GetString(db_bytes, 0, 15).CompareTo("SQLite format 3") != 0)
|
|
{
|
|
throw new Exception("Not a valid SQLite 3 Database File");
|
|
}
|
|
|
|
if (db_bytes[0x34] != 0)
|
|
{
|
|
throw new Exception("Auto-vacuum capable database is not supported");
|
|
}
|
|
|
|
//if (decimal.Compare(new decimal(this.ConvertToInteger(0x2c, 4)), 4M) >= 0)
|
|
//{
|
|
// throw new Exception("No supported Schema layer file-format");
|
|
//}
|
|
page_size = (ushort)ConvertToInteger(0x10, 2);
|
|
encoding = ConvertToInteger(0x38, 4);
|
|
if (decimal.Compare(new decimal(encoding), decimal.Zero) == 0)
|
|
{
|
|
encoding = 1L;
|
|
}
|
|
|
|
ReadMasterTable(100L);
|
|
}
|
|
}
|
|
|
|
private ulong ConvertToInteger(int startIndex, int Size)
|
|
{
|
|
if (Size > 8 | Size == 0)
|
|
{
|
|
return 0L;
|
|
}
|
|
|
|
ulong num2 = 0L;
|
|
int num4 = Size - 1;
|
|
for (int i = 0; i <= num4; i++)
|
|
{
|
|
num2 = num2 << 8 | db_bytes[startIndex + i];
|
|
}
|
|
|
|
return num2;
|
|
}
|
|
|
|
private long CVL(int startIndex, int endIndex)
|
|
{
|
|
endIndex++;
|
|
byte[] buffer = new byte[8];
|
|
int num4 = endIndex - startIndex;
|
|
bool flag = false;
|
|
if (num4 == 0 | num4 > 9)
|
|
{
|
|
return 0L;
|
|
}
|
|
|
|
if (num4 == 1)
|
|
{
|
|
buffer[0] = (byte)(db_bytes[startIndex] & 0x7f);
|
|
return BitConverter.ToInt64(buffer, 0);
|
|
}
|
|
|
|
if (num4 == 9)
|
|
{
|
|
flag = true;
|
|
}
|
|
|
|
int num2 = 1;
|
|
int num3 = 7;
|
|
int index = 0;
|
|
if (flag)
|
|
{
|
|
buffer[0] = db_bytes[endIndex - 1];
|
|
endIndex--;
|
|
index = 1;
|
|
}
|
|
|
|
int num7 = startIndex;
|
|
for (int i = endIndex - 1; i >= num7; i += -1)
|
|
{
|
|
if (i - 1 >= startIndex)
|
|
{
|
|
buffer[index] = (byte)((byte)(db_bytes[i] >> (num2 - 1 & 7)) & 0xff >> num2 | (byte)(db_bytes[i - 1] << (num3 & 7)));
|
|
num2++;
|
|
index++;
|
|
num3--;
|
|
}
|
|
else if (!flag)
|
|
{
|
|
buffer[index] = (byte)((byte)(db_bytes[i] >> (num2 - 1 & 7)) & 0xff >> num2);
|
|
}
|
|
}
|
|
|
|
return BitConverter.ToInt64(buffer, 0);
|
|
}
|
|
|
|
public int GetRowCount()
|
|
{
|
|
return table_entries.Length;
|
|
}
|
|
|
|
public string[] GetTableNames()
|
|
{
|
|
var tableNames = new List<string>();
|
|
int num3 = master_table_entries.Length - 1;
|
|
for (int i = 0; i <= num3; i++)
|
|
{
|
|
if (master_table_entries[i].item_type == "table")
|
|
{
|
|
tableNames.Add(master_table_entries[i].item_name);
|
|
}
|
|
}
|
|
|
|
return tableNames.ToArray();
|
|
}
|
|
|
|
public string GetValue(int row_num, int field)
|
|
{
|
|
if (row_num >= table_entries.Length)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (field >= table_entries[row_num].content.Length)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return table_entries[row_num].content[field];
|
|
}
|
|
|
|
public string GetValue(int row_num, string field)
|
|
{
|
|
int num = -1;
|
|
int length = field_names.Length - 1;
|
|
for (int i = 0; i <= length; i++)
|
|
{
|
|
if (field_names[i].ToLower().CompareTo(field.ToLower()) == 0)
|
|
{
|
|
num = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (num == -1)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return GetValue(row_num, num);
|
|
}
|
|
|
|
private int GVL(int startIndex)
|
|
{
|
|
if (startIndex > db_bytes.Length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int num3 = startIndex + 8;
|
|
for (int i = startIndex; i <= num3; i++)
|
|
{
|
|
if (i > db_bytes.Length - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ((db_bytes[i] & 0x80) != 0x80)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return startIndex + 8;
|
|
}
|
|
|
|
private bool IsOdd(long value)
|
|
{
|
|
return (value & 1L) == 1L;
|
|
}
|
|
|
|
private void ReadMasterTable(ulong Offset)
|
|
{
|
|
if (db_bytes[(int)Offset] == 13)
|
|
{
|
|
ushort num2 = Convert.ToUInt16(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
|
int length = 0;
|
|
if (master_table_entries != null)
|
|
{
|
|
length = master_table_entries.Length;
|
|
Array.Resize(ref master_table_entries, master_table_entries.Length + num2 + 1);
|
|
}
|
|
else
|
|
{
|
|
master_table_entries = new sqlite_master_entry[num2 + 1];
|
|
}
|
|
|
|
int num13 = num2;
|
|
for (int i = 0; i <= num13; i++)
|
|
{
|
|
ulong num = ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 8M), new decimal(i * 2))), 2);
|
|
if (decimal.Compare(new decimal(Offset), 100M) != 0)
|
|
{
|
|
num += Offset;
|
|
}
|
|
|
|
int endIndex = GVL((int)num);
|
|
long num7 = CVL((int)num, endIndex);
|
|
int num6 = GVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)));
|
|
master_table_entries[length + i].row_id = CVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)),
|
|
num6);
|
|
num = Convert.ToUInt64(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(num6), new decimal(num))), decimal.One));
|
|
endIndex = GVL((int)num);
|
|
num6 = endIndex;
|
|
long num5 = CVL((int)num, endIndex);
|
|
long[] numArray = new long[5];
|
|
int index = 0;
|
|
do
|
|
{
|
|
endIndex = num6 + 1;
|
|
num6 = GVL(endIndex);
|
|
numArray[index] = CVL(endIndex, num6);
|
|
if (numArray[index] > 9L)
|
|
{
|
|
if (IsOdd(numArray[index]))
|
|
{
|
|
numArray[index] = (long)Math.Round((numArray[index] - 13L) / 2.0);
|
|
}
|
|
else
|
|
{
|
|
numArray[index] = (long)Math.Round((numArray[index] - 12L) / 2.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
numArray[index] = SQLDataTypeSize[(int)numArray[index]];
|
|
}
|
|
|
|
index++;
|
|
} while (index <= 4);
|
|
|
|
if (decimal.Compare(new decimal(encoding), decimal.One) == 0)
|
|
{
|
|
master_table_entries[length + i].item_type = Encoding.UTF8.GetString(db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 2M) == 0)
|
|
{
|
|
master_table_entries[length + i].item_type = Encoding.Unicode.GetString(db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 3M) == 0)
|
|
{
|
|
master_table_entries[length + i].item_type = Encoding.BigEndianUnicode.GetString(db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
|
}
|
|
|
|
if (decimal.Compare(new decimal(encoding), decimal.One) == 0)
|
|
{
|
|
master_table_entries[length + i].item_name = Encoding.Default.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 2M) == 0)
|
|
{
|
|
master_table_entries[length + i].item_name = Encoding.Unicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 3M) == 0)
|
|
{
|
|
master_table_entries[length + i].item_name = Encoding.BigEndianUnicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
|
}
|
|
|
|
master_table_entries[length + i].root_num =
|
|
(long)ConvertToInteger(
|
|
Convert.ToInt32(decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])),
|
|
new decimal(numArray[2]))), (int)numArray[3]);
|
|
if (decimal.Compare(new decimal(encoding), decimal.One) == 0)
|
|
{
|
|
master_table_entries[length + i].sql_statement = Encoding.Default.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(
|
|
decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])),
|
|
new decimal(numArray[3]))), (int)numArray[4]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 2M) == 0)
|
|
{
|
|
master_table_entries[length + i].sql_statement = Encoding.Unicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(
|
|
decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])),
|
|
new decimal(numArray[3]))), (int)numArray[4]);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 3M) == 0)
|
|
{
|
|
master_table_entries[length + i].sql_statement = Encoding.BigEndianUnicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(
|
|
decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])),
|
|
new decimal(numArray[3]))), (int)numArray[4]);
|
|
}
|
|
}
|
|
}
|
|
else if (db_bytes[(int)Offset] == 5)
|
|
{
|
|
ushort num11 = Convert.ToUInt16(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
|
int num14 = num11;
|
|
for (int j = 0; j <= num14; j++)
|
|
{
|
|
ushort startIndex = (ushort)ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 12M), new decimal(j * 2))), 2);
|
|
if (decimal.Compare(new decimal(Offset), 100M) == 0)
|
|
{
|
|
ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(ConvertToInteger(startIndex, 4)), decimal.One), new decimal(page_size))));
|
|
}
|
|
else
|
|
{
|
|
ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(ConvertToInteger((int)(Offset + startIndex), 4)), decimal.One), new decimal(page_size))));
|
|
}
|
|
}
|
|
|
|
ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 8M)), 4)), decimal.One),
|
|
new decimal(page_size))));
|
|
}
|
|
}
|
|
|
|
public bool ReadTable(string TableName)
|
|
{
|
|
int index = -1;
|
|
int length = master_table_entries.Length - 1;
|
|
for (int i = 0; i <= length; i++)
|
|
{
|
|
if (master_table_entries[i].item_name.ToLower().CompareTo(TableName.ToLower()) == 0)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index == -1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string[] strArray = master_table_entries[index].sql_statement.Substring(master_table_entries[index].sql_statement.IndexOf("(") + 1).Split(',');
|
|
int num6 = strArray.Length - 1;
|
|
for (int j = 0; j <= num6; j++)
|
|
{
|
|
strArray[j] = strArray[j].TrimStart();
|
|
int num4 = strArray[j].IndexOf(" ");
|
|
if (num4 > 0)
|
|
{
|
|
strArray[j] = strArray[j].Substring(0, num4);
|
|
}
|
|
|
|
if (strArray[j].IndexOf("UNIQUE") == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Array.Resize(ref field_names, j + 1);
|
|
field_names[j] = strArray[j];
|
|
}
|
|
|
|
return ReadTableFromOffset((ulong)((master_table_entries[index].root_num - 1L) * page_size));
|
|
}
|
|
|
|
private bool ReadTableFromOffset(ulong Offset)
|
|
{
|
|
if (db_bytes[(int)Offset] == 13)
|
|
{
|
|
int num2 = Convert.ToInt32(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
|
int length = 0;
|
|
if (table_entries != null)
|
|
{
|
|
length = table_entries.Length;
|
|
Array.Resize(ref table_entries, table_entries.Length + num2 + 1);
|
|
}
|
|
else
|
|
{
|
|
table_entries = new table_entry[num2 + 1];
|
|
}
|
|
|
|
int num16 = num2;
|
|
for (int i = 0; i <= num16; i++)
|
|
{
|
|
var _fieldArray = new record_header_field[1];
|
|
ulong num = ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 8M), new decimal(i * 2))), 2);
|
|
if (decimal.Compare(new decimal(Offset), 100M) != 0)
|
|
{
|
|
num += Offset;
|
|
}
|
|
|
|
int endIndex = GVL((int)num);
|
|
long num9 = CVL((int)num, endIndex);
|
|
int num8 = GVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)));
|
|
table_entries[length + i].row_id = CVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)), num8);
|
|
num = Convert.ToUInt64(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(num8), new decimal(num))), decimal.One));
|
|
endIndex = GVL((int)num);
|
|
num8 = endIndex;
|
|
long num7 = CVL((int)num, endIndex);
|
|
long num10 = Convert.ToInt64(decimal.Add(decimal.Subtract(new decimal(num), new decimal(endIndex)), decimal.One));
|
|
for (int j = 0; num10 < num7; j++)
|
|
{
|
|
Array.Resize(ref _fieldArray, j + 1);
|
|
endIndex = num8 + 1;
|
|
num8 = GVL(endIndex);
|
|
_fieldArray[j].type = CVL(endIndex, num8);
|
|
if (_fieldArray[j].type > 9L)
|
|
{
|
|
if (IsOdd(_fieldArray[j].type))
|
|
{
|
|
_fieldArray[j].size = (long)Math.Round((_fieldArray[j].type - 13L) / 2.0);
|
|
}
|
|
else
|
|
{
|
|
_fieldArray[j].size = (long)Math.Round((_fieldArray[j].type - 12L) / 2.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fieldArray[j].size = SQLDataTypeSize[(int)_fieldArray[j].type];
|
|
}
|
|
|
|
num10 = num10 + (num8 - endIndex) + 1L;
|
|
}
|
|
|
|
table_entries[length + i].content = new string[_fieldArray.Length - 1 + 1];
|
|
int num4 = 0;
|
|
int num17 = _fieldArray.Length - 1;
|
|
for (int k = 0; k <= num17; k++)
|
|
{
|
|
if (_fieldArray[k].type > 9L)
|
|
{
|
|
if (!IsOdd(_fieldArray[k].type))
|
|
{
|
|
if (decimal.Compare(new decimal(encoding), decimal.One) == 0)
|
|
{
|
|
|
|
byte[] bytes = new byte[_fieldArray[k].size];
|
|
Array.Copy(db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), bytes, 0, _fieldArray[k].size);
|
|
|
|
table_entries[length + i].content[k] = Convert.ToBase64String(bytes);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 2M) == 0)
|
|
{
|
|
table_entries[length + i].content[k] = Encoding.Unicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
|
}
|
|
else if (decimal.Compare(new decimal(encoding), 3M) == 0)
|
|
{
|
|
table_entries[length + i].content[k] = Encoding.BigEndianUnicode.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
table_entries[length + i].content[k] = Encoding.Default.GetString(db_bytes,
|
|
Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
table_entries[length + i].content[k] = Convert.ToString(ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))),
|
|
(int)_fieldArray[k].size));
|
|
}
|
|
|
|
num4 += (int)_fieldArray[k].size;
|
|
}
|
|
}
|
|
}
|
|
else if (db_bytes[(int)Offset] == 5)
|
|
{
|
|
ushort num14 = Convert.ToUInt16(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
|
int num18 = num14;
|
|
for (int m = 0; m <= num18; m++)
|
|
{
|
|
ushort num13 = (ushort)ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 12M), new decimal(m * 2))), 2);
|
|
ReadTableFromOffset(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(ConvertToInteger((int)(Offset + num13), 4)), decimal.One), new decimal(page_size))));
|
|
}
|
|
|
|
ReadTableFromOffset(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 8M)), 4)), decimal.One),
|
|
new decimal(page_size))));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct record_header_field
|
|
{
|
|
public long size;
|
|
public long type;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct sqlite_master_entry
|
|
{
|
|
public long row_id;
|
|
public string item_type;
|
|
public string item_name;
|
|
public readonly string astable_name;
|
|
public long root_num;
|
|
public string sql_statement;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct table_entry
|
|
{
|
|
public long row_id;
|
|
public string[] content;
|
|
}
|
|
}
|
|
}
|