458 lines
12 KiB
C#
458 lines
12 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace Intelix.Helper.Sql;
|
|
|
|
public class SqLite
|
|
{
|
|
private struct RecordHeaderField
|
|
{
|
|
public long Size;
|
|
|
|
public long Type;
|
|
}
|
|
|
|
private struct TableEntry
|
|
{
|
|
public string[] Content;
|
|
}
|
|
|
|
private struct SqliteMasterEntry
|
|
{
|
|
public string ItemName;
|
|
|
|
public long RootNum;
|
|
|
|
public string SqlStatement;
|
|
}
|
|
|
|
private readonly ulong _dbEncoding;
|
|
|
|
private readonly byte[] _fileBytes;
|
|
|
|
private readonly ulong _pageSize;
|
|
|
|
private readonly byte[] _sqlDataTypeSize = new byte[10] { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0 };
|
|
|
|
private string[] _fieldNames;
|
|
|
|
private SqliteMasterEntry[] _masterTableEntries;
|
|
|
|
private TableEntry[] _tableEntries;
|
|
|
|
public SqLite(string fileName)
|
|
{
|
|
_fileBytes = File.ReadAllBytes(fileName);
|
|
_pageSize = ConvertToULong(16, 2);
|
|
_dbEncoding = ConvertToULong(56, 4);
|
|
ReadMasterTable(100L);
|
|
}
|
|
|
|
public SqLite(byte[] basedata)
|
|
{
|
|
_fileBytes = basedata;
|
|
_pageSize = ConvertToULong(16, 2);
|
|
_dbEncoding = ConvertToULong(56, 4);
|
|
ReadMasterTable(100L);
|
|
}
|
|
|
|
public string GetValue(int rowNum, int field)
|
|
{
|
|
try
|
|
{
|
|
if (rowNum >= _tableEntries.Length)
|
|
{
|
|
return null;
|
|
}
|
|
return (field >= _tableEntries[rowNum].Content.Length) ? null : _tableEntries[rowNum].Content[field];
|
|
}
|
|
catch
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
|
|
public int GetRowCount()
|
|
{
|
|
return _tableEntries.Length;
|
|
}
|
|
|
|
private bool ReadTableFromOffset(ulong offset)
|
|
{
|
|
try
|
|
{
|
|
switch (_fileBytes[offset])
|
|
{
|
|
case 13:
|
|
{
|
|
uint num4 = (uint)(ConvertToULong((int)offset + 3, 2) - 1);
|
|
int num5 = 0;
|
|
if (_tableEntries != null)
|
|
{
|
|
num5 = _tableEntries.Length;
|
|
Array.Resize(ref _tableEntries, _tableEntries.Length + (int)num4 + 1);
|
|
}
|
|
else
|
|
{
|
|
_tableEntries = new TableEntry[num4 + 1];
|
|
}
|
|
for (uint num6 = 0u; (int)num6 <= (int)num4; num6++)
|
|
{
|
|
ulong num7 = ConvertToULong((int)offset + 8 + (int)(num6 * 2), 2);
|
|
if (offset != 100)
|
|
{
|
|
num7 += offset;
|
|
}
|
|
int num8 = Gvl((int)num7);
|
|
Cvl((int)num7, num8);
|
|
int num9 = Gvl((int)((long)num7 + ((long)num8 - (long)num7) + 1));
|
|
Cvl((int)((long)num7 + ((long)num8 - (long)num7) + 1), num9);
|
|
ulong num10 = num7 + (ulong)((long)num9 - (long)num7 + 1);
|
|
int num11 = Gvl((int)num10);
|
|
int num12 = num11;
|
|
long num13 = Cvl((int)num10, num11);
|
|
RecordHeaderField[] array = null;
|
|
long num14 = (long)num10 - (long)num11 + 1;
|
|
int num15 = 0;
|
|
while (num14 < num13)
|
|
{
|
|
Array.Resize(ref array, num15 + 1);
|
|
int num16 = num12 + 1;
|
|
num12 = Gvl(num16);
|
|
array[num15].Type = Cvl(num16, num12);
|
|
array[num15].Size = ((array[num15].Type <= 9) ? _sqlDataTypeSize[array[num15].Type] : ((!IsOdd(array[num15].Type)) ? ((array[num15].Type - 12) / 2) : ((array[num15].Type - 13) / 2)));
|
|
num14 = num14 + (num12 - num16) + 1;
|
|
num15++;
|
|
}
|
|
if (array == null)
|
|
{
|
|
continue;
|
|
}
|
|
_tableEntries[num5 + (int)num6].Content = new string[array.Length];
|
|
int num17 = 0;
|
|
for (int i = 0; i <= array.Length - 1; i++)
|
|
{
|
|
if (array[i].Type > 9)
|
|
{
|
|
if (!IsOdd(array[i].Type))
|
|
{
|
|
long dbEncoding = (long)_dbEncoding;
|
|
long num18 = dbEncoding - 1;
|
|
if ((ulong)num18 <= 2uL)
|
|
{
|
|
switch (num18)
|
|
{
|
|
case 0L:
|
|
_tableEntries[num5 + (int)num6].Content[i] = Encoding.Default.GetString(_fileBytes, (int)((long)num10 + num13 + num17), (int)array[i].Size);
|
|
break;
|
|
case 1L:
|
|
_tableEntries[num5 + (int)num6].Content[i] = Encoding.Unicode.GetString(_fileBytes, (int)((long)num10 + num13 + num17), (int)array[i].Size);
|
|
break;
|
|
case 2L:
|
|
_tableEntries[num5 + (int)num6].Content[i] = Encoding.BigEndianUnicode.GetString(_fileBytes, (int)((long)num10 + num13 + num17), (int)array[i].Size);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_tableEntries[num5 + (int)num6].Content[i] = Encoding.Default.GetString(_fileBytes, (int)((long)num10 + num13 + num17), (int)array[i].Size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_tableEntries[num5 + (int)num6].Content[i] = Convert.ToString(ConvertToULong((int)((long)num10 + num13 + num17), (int)array[i].Size));
|
|
}
|
|
num17 += (int)array[i].Size;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 5:
|
|
{
|
|
uint num = (uint)(ConvertToULong((int)(offset + 3), 2) - 1);
|
|
for (uint num2 = 0u; (int)num2 <= (int)num; num2++)
|
|
{
|
|
uint num3 = (uint)ConvertToULong((int)offset + 12 + (int)(num2 * 2), 2);
|
|
ReadTableFromOffset((ConvertToULong((int)(offset + num3), 4) - 1) * _pageSize);
|
|
}
|
|
ReadTableFromOffset((ConvertToULong((int)(offset + 8), 4) - 1) * _pageSize);
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void ReadMasterTable(long offset)
|
|
{
|
|
while (true)
|
|
{
|
|
switch (_fileBytes[offset])
|
|
{
|
|
default:
|
|
return;
|
|
case 5:
|
|
{
|
|
uint num13 = (uint)(ConvertToULong((int)offset + 3, 2) - 1);
|
|
for (int j = 0; j <= (int)num13; j++)
|
|
{
|
|
uint num14 = (uint)ConvertToULong((int)offset + 12 + j * 2, 2);
|
|
if (offset == 100)
|
|
{
|
|
ReadMasterTable((long)((ConvertToULong((int)num14, 4) - 1) * _pageSize));
|
|
}
|
|
else
|
|
{
|
|
ReadMasterTable((long)((ConvertToULong((int)(offset + num14), 4) - 1) * _pageSize));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 13:
|
|
{
|
|
ulong num = ConvertToULong((int)offset + 3, 2) - 1;
|
|
int num2 = 0;
|
|
if (_masterTableEntries != null)
|
|
{
|
|
num2 = _masterTableEntries.Length;
|
|
Array.Resize(ref _masterTableEntries, _masterTableEntries.Length + (int)num + 1);
|
|
}
|
|
else
|
|
{
|
|
checked
|
|
{
|
|
_masterTableEntries = new SqliteMasterEntry[(ulong)unchecked((long)(num + 1))];
|
|
}
|
|
}
|
|
for (ulong num3 = 0uL; num3 <= num; num3++)
|
|
{
|
|
ulong num4 = ConvertToULong((int)offset + 8 + (int)num3 * 2, 2);
|
|
if (offset != 100)
|
|
{
|
|
num4 += (ulong)offset;
|
|
}
|
|
int num5 = Gvl((int)num4);
|
|
Cvl((int)num4, num5);
|
|
int num6 = Gvl((int)((long)num4 + ((long)num5 - (long)num4) + 1));
|
|
Cvl((int)((long)num4 + ((long)num5 - (long)num4) + 1), num6);
|
|
ulong num7 = num4 + (ulong)((long)num6 - (long)num4 + 1);
|
|
int num8 = Gvl((int)num7);
|
|
int num9 = num8;
|
|
long num10 = Cvl((int)num7, num8);
|
|
long[] array = new long[5];
|
|
for (int i = 0; i <= 4; i++)
|
|
{
|
|
int startIdx = num9 + 1;
|
|
num9 = Gvl(startIdx);
|
|
array[i] = Cvl(startIdx, num9);
|
|
array[i] = ((array[i] <= 9) ? _sqlDataTypeSize[array[i]] : ((!IsOdd(array[i])) ? ((array[i] - 12) / 2) : ((array[i] - 13) / 2)));
|
|
}
|
|
long dbEncoding;
|
|
if (_dbEncoding == 1 || _dbEncoding == 2)
|
|
{
|
|
dbEncoding = (long)_dbEncoding;
|
|
long num11 = dbEncoding - 1;
|
|
if ((ulong)num11 <= 2uL)
|
|
{
|
|
switch (num11)
|
|
{
|
|
case 0L:
|
|
_masterTableEntries[num2 + (int)num3].ItemName = Encoding.Default.GetString(_fileBytes, (int)((long)num7 + num10 + array[0]), (int)array[1]);
|
|
break;
|
|
case 1L:
|
|
_masterTableEntries[num2 + (int)num3].ItemName = Encoding.Unicode.GetString(_fileBytes, (int)((long)num7 + num10 + array[0]), (int)array[1]);
|
|
break;
|
|
case 2L:
|
|
_masterTableEntries[num2 + (int)num3].ItemName = Encoding.BigEndianUnicode.GetString(_fileBytes, (int)((long)num7 + num10 + array[0]), (int)array[1]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
_masterTableEntries[num2 + (int)num3].RootNum = (long)ConvertToULong((int)((long)num7 + num10 + array[0] + array[1] + array[2]), (int)array[3]);
|
|
dbEncoding = (long)_dbEncoding;
|
|
long num12 = dbEncoding - 1;
|
|
if ((ulong)num12 <= 2uL)
|
|
{
|
|
switch (num12)
|
|
{
|
|
case 0L:
|
|
_masterTableEntries[num2 + (int)num3].SqlStatement = Encoding.Default.GetString(_fileBytes, (int)((long)num7 + num10 + array[0] + array[1] + array[2] + array[3]), (int)array[4]);
|
|
break;
|
|
case 1L:
|
|
_masterTableEntries[num2 + (int)num3].SqlStatement = Encoding.Unicode.GetString(_fileBytes, (int)((long)num7 + num10 + array[0] + array[1] + array[2] + array[3]), (int)array[4]);
|
|
break;
|
|
case 2L:
|
|
_masterTableEntries[num2 + (int)num3].SqlStatement = Encoding.BigEndianUnicode.GetString(_fileBytes, (int)((long)num7 + num10 + array[0] + array[1] + array[2] + array[3]), (int)array[4]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
offset = (long)((ConvertToULong((int)offset + 8, 4) - 1) * _pageSize);
|
|
}
|
|
}
|
|
|
|
public bool ReadTable(string tableName)
|
|
{
|
|
int num = -1;
|
|
for (int i = 0; i <= _masterTableEntries.Length; i++)
|
|
{
|
|
if (string.Compare(_masterTableEntries[i].ItemName.ToLower(), tableName.ToLower(), StringComparison.Ordinal) == 0)
|
|
{
|
|
num = i;
|
|
break;
|
|
}
|
|
}
|
|
if (num == -1)
|
|
{
|
|
return false;
|
|
}
|
|
string[] array = _masterTableEntries[num].SqlStatement.Substring(_masterTableEntries[num].SqlStatement.IndexOf("(", StringComparison.Ordinal) + 1).Split(',');
|
|
for (int j = 0; j <= array.Length - 1; j++)
|
|
{
|
|
array[j] = array[j].TrimStart();
|
|
int num2 = array[j].IndexOf(' ');
|
|
if (num2 > 0)
|
|
{
|
|
array[j] = array[j].Substring(0, num2);
|
|
}
|
|
if (array[j].IndexOf("UNIQUE", StringComparison.Ordinal) != 0)
|
|
{
|
|
Array.Resize(ref _fieldNames, j + 1);
|
|
_fieldNames[j] = array[j];
|
|
}
|
|
}
|
|
return ReadTableFromOffset((ulong)(_masterTableEntries[num].RootNum - 1) * _pageSize);
|
|
}
|
|
|
|
private ulong ConvertToULong(int startIndex, int size)
|
|
{
|
|
try
|
|
{
|
|
if (size > 8 || size == 0)
|
|
{
|
|
return 0uL;
|
|
}
|
|
ulong num = 0uL;
|
|
for (int i = 0; i <= size - 1; i++)
|
|
{
|
|
num = (num << 8) | _fileBytes[startIndex + i];
|
|
}
|
|
return num;
|
|
}
|
|
catch
|
|
{
|
|
return 0uL;
|
|
}
|
|
}
|
|
|
|
private int Gvl(int startIdx)
|
|
{
|
|
try
|
|
{
|
|
if (startIdx > _fileBytes.Length)
|
|
{
|
|
return 0;
|
|
}
|
|
for (int i = startIdx; i <= startIdx + 8; i++)
|
|
{
|
|
if (i > _fileBytes.Length - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
if ((_fileBytes[i] & 0x80) != 128)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return startIdx + 8;
|
|
}
|
|
catch
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private long Cvl(int startIdx, int endIdx)
|
|
{
|
|
try
|
|
{
|
|
endIdx++;
|
|
byte[] array = new byte[8];
|
|
int num = endIdx - startIdx;
|
|
bool flag = false;
|
|
if (num == 0 || num > 9)
|
|
{
|
|
return 0L;
|
|
}
|
|
switch (num)
|
|
{
|
|
case 1:
|
|
array[0] = (byte)(_fileBytes[startIdx] & 0x7F);
|
|
return BitConverter.ToInt64(array, 0);
|
|
case 9:
|
|
flag = true;
|
|
break;
|
|
}
|
|
int num2 = 1;
|
|
int num3 = 7;
|
|
int num4 = 0;
|
|
if (flag)
|
|
{
|
|
array[0] = _fileBytes[endIdx - 1];
|
|
endIdx--;
|
|
num4 = 1;
|
|
}
|
|
for (int i = endIdx - 1; i >= startIdx; i += -1)
|
|
{
|
|
if (i - 1 >= startIdx)
|
|
{
|
|
array[num4] = (byte)(((_fileBytes[i] >> num2 - 1) & (255 >> num2)) | (_fileBytes[i - 1] << num3));
|
|
num2++;
|
|
num4++;
|
|
num3--;
|
|
}
|
|
else if (!flag)
|
|
{
|
|
array[num4] = (byte)((_fileBytes[i] >> num2 - 1) & (255 >> num2));
|
|
}
|
|
}
|
|
return BitConverter.ToInt64(array, 0);
|
|
}
|
|
catch
|
|
{
|
|
return 0L;
|
|
}
|
|
}
|
|
|
|
private static bool IsOdd(long value)
|
|
{
|
|
return (value & 1) == 1;
|
|
}
|
|
|
|
public static SqLite ReadTable(string database, string table)
|
|
{
|
|
try
|
|
{
|
|
string text = Path.GetTempFileName() + ".tmpdb";
|
|
File.Copy(database, text);
|
|
SqLite sqLite = new SqLite(text);
|
|
sqLite.ReadTable(table);
|
|
File.Delete(text);
|
|
return (sqLite.GetRowCount() == 65536) ? null : sqLite;
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|