hostile-takeover/SpiffLib/palmdatabase.cs
2014-07-06 17:47:28 -07:00

419 lines
9.0 KiB
C#

using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
namespace SpiffLib {
#if false
// These structs straight from Palm includes with minor editting
struct RecordEntryType {
uint localChunkID; // local chunkID of a record
byte attributes; // record attributes;
byte uniqueID; // unique ID of record; should not be 0 for a legal record.
byte uniqueID_byte1;
byte uniqueID_byte2;
}
struct RsrcEntryType {
uint type;
ushort id;
uint localChunkID;
}
struct RecordListType {
uint nextRecordListID; // local chunkID of next list
ushort numRecords; // number of records in this list
ushort firstEntry; // array of Record/Rsrc entries
// starts here
}
struct DatabaseHdrType {
char[] name; // name of database, 32 bytes
ushort attributes; // database attributes
ushort version; // version of database
uint creationDate; // creation date of database
uint modificationDate; // latest modification date
uint lastBackupDate; // latest backup date
uint modificationNumber; // modification number of database
uint appInfoID; // application specific info
uint sortInfoID; // app specific sorting info
uint type; // database type
uint creator; // database creator
uint uniqueIDSeed; // used to generate unique IDs.
// Note that only the low order
// 3 bytes of this is used (in
// RecordEntryType.uniqueID).
// We are keeping 4 bytes for
// alignment purposes.
RecordListType recordList; // first record list
}
// DatabaseHdrType - sizeof(ushort)
// followed by RecordEntryType
// followed by record data bytes
#endif
public class PdbRecord {
public PdbRecord() {
}
public byte[] Data {
get {
return m_ab;
}
set {
m_ab = value;
}
}
public uint Type {
get
{
return m_uiType;
}
set
{
m_uiType = value;
}
}
public ushort ID {
get {
return m_usID;
}
set {
m_usID = value;
}
}
public uint IbRec {
get {
return m_ibRec;
}
set {
m_ibRec = value;
}
}
byte[] m_ab;
uint m_uiType;
ushort m_usID;
uint m_ibRec;
}
public class PalmDatabase
{
ArrayList m_alsPdbRecords = new ArrayList();
string m_strName = "";
const ushort dmHdrAttrBundle = 0x0800;
const ushort dmHdrAttrBackup = 0x0008;
const ushort dmHdrAttrResDB = 0x0001;
ushort m_usAttributes = dmHdrAttrBundle | dmHdrAttrBackup;
ushort m_usVersion = 1;
uint m_uiCreationDate = GetCurrentTimePalmUnits();
uint m_uiType;
uint m_uiCreator;
static int s_cbDbName = 32;
public PalmDatabase()
{
}
public void SetRecordData(ArrayList alsRecordData)
{
m_alsPdbRecords.Clear();
foreach (byte[] abData in alsRecordData) {
PdbRecord pdbr = new PdbRecord();
pdbr.Data = (byte[])abData.Clone();
m_alsPdbRecords.Add(pdbr);
}
}
public ArrayList GetRecordData()
{
ArrayList alsRecordData = new ArrayList();
foreach (PdbRecord pdbr in m_alsPdbRecords)
alsRecordData.Add((byte[])pdbr.Data.Clone());
return alsRecordData;
}
public void Add(byte [] abData)
{
Add(abData, 0, 0);
}
public void Add(byte [] abData, ushort usID, uint uiType)
{
PdbRecord pdbr = new PdbRecord();
pdbr.Data = (byte[])abData.Clone();
pdbr.ID = usID;
pdbr.Type = uiType;
m_alsPdbRecords.Add(pdbr);
}
public PdbRecord this [int index]
{
set {
m_alsPdbRecords[index] = value;
}
get {
return (PdbRecord)m_alsPdbRecords[index];
}
}
public int Count
{
get {
return m_alsPdbRecords.Count;
}
}
static uint GetCurrentTimePalmUnits()
{
DateTime dt1904 = new DateTime(1904, 1, 1);
TimeSpan ts = DateTime.Now - dt1904;
return (uint)ts.TotalSeconds;
}
public void Load(string strFileName)
{
Stream stm = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.None);
BinaryReader brdr = new BinaryReader(stm);
// Name
m_strName = "";
for (int i = 0; i < s_cbDbName; i++)
{
char ch = brdr.ReadChar();
if (ch == 0)
break;
m_strName += ch;
}
brdr.BaseStream.Position = (long)s_cbDbName;
// attributes
m_usAttributes = Misc.SwapUShort(brdr.ReadUInt16());
// version
m_usVersion = Misc.SwapUShort(brdr.ReadUInt16());
// creationDate
m_uiCreationDate = Misc.SwapUInt(brdr.ReadUInt32());
// modificationDate
brdr.ReadUInt32();
// lastBackupDate
brdr.ReadUInt32();
// modificationNumber
brdr.ReadUInt32();
// appInfoID
uint uiAppInfoID = Misc.SwapUInt(brdr.ReadUInt32());
Debug.Assert(uiAppInfoID == 0);
// sortInfoID
uint uiSortInfoID = Misc.SwapUInt(brdr.ReadUInt32());
Debug.Assert(uiSortInfoID == 0);
// type
m_uiType = Misc.SwapUInt(brdr.ReadUInt32());
// creator
m_uiCreator = Misc.SwapUInt(brdr.ReadUInt32());
// uniqueIDSeed
brdr.ReadUInt32();
// recordList.nextRecordListID
brdr.ReadUInt32();
// recordList.numRecords
ushort crecs = Misc.SwapUShort((ushort)brdr.ReadUInt16());
// Read in records
m_alsPdbRecords = new ArrayList();
for (int irec = 0; irec < crecs; irec++) {
PdbRecord pdbr = new PdbRecord();
m_alsPdbRecords.Add(pdbr);
if ((m_usAttributes & dmHdrAttrResDB) != 0) {
pdbr.Type = Misc.SwapUInt(brdr.ReadUInt32());
pdbr.ID = Misc.SwapUShort(brdr.ReadUInt16());
pdbr.IbRec = Misc.SwapUInt(brdr.ReadUInt32());
}
else {
// localChunkId (actually an offset to the bytes for this record)
pdbr.IbRec = Misc.SwapUInt((uint)brdr.ReadUInt32());
// attributes, unique id
brdr.ReadByte();
brdr.ReadByte();
brdr.ReadByte();
brdr.ReadByte();
}
}
for (int irec = 0; irec < crecs; irec++) {
uint ibrecNext;
if (irec == crecs - 1)
ibrecNext = (uint)brdr.BaseStream.Length;
else
ibrecNext = ((PdbRecord)m_alsPdbRecords[irec+1]).IbRec;
PdbRecord pdbr = (PdbRecord)m_alsPdbRecords[irec];
brdr.BaseStream.Position = pdbr.IbRec;
pdbr.Data = brdr.ReadBytes((int)(ibrecNext - pdbr.IbRec));
}
// All done
brdr.Close();
}
public bool Save(string strFileName) {
Stream stm = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.None);
BinaryWriter bwtr = new BinaryWriter(stm);
// dbName
for (int i = 0; i < s_cbDbName; i++) {
if (i < m_strName.Length) {
bwtr.Write((byte)m_strName[i]);
continue;
}
bwtr.Write((byte)0);
}
// attributes
bwtr.Write(Misc.SwapUShort(m_usAttributes));
// version
bwtr.Write(Misc.SwapUShort(m_usVersion));
// creationDate
bwtr.Write(Misc.SwapUInt(m_uiCreationDate));
// modificationDate
uint uiDate = Misc.SwapUInt(GetCurrentTimePalmUnits());
bwtr.Write(uiDate);
// lastBackupDate
bwtr.Write(uiDate);
// modificationNumber
bwtr.Write((uint)Misc.SwapUInt(1));
// appInfoID
bwtr.Write(Misc.SwapUInt(0));
// sortInfoID
bwtr.Write(Misc.SwapUInt(0));
// type
bwtr.Write(Misc.SwapUInt(m_uiType));
// creator
bwtr.Write(Misc.SwapUInt(m_uiCreator));
// uniqueIDSeed
bwtr.Write(Misc.SwapUInt((uint)(m_alsPdbRecords.Count + 1)));
// recordList.nextRecordListID
bwtr.Write((uint)0);
// recordList.numRecords
bwtr.Write(Misc.SwapUShort((ushort)m_alsPdbRecords.Count));
// Bonus padding because the Tapwave signing tool fails unless it is there
// It is also what buildprc inserts. Devices/simulators/emulators don't need it tho.
int cbBonusPadding = 2;
// Calc where the records begin, which is after the record headers
int cbHdr = (int)bwtr.BaseStream.Position;
int ibrecNext = cbHdr + m_alsPdbRecords.Count * ((m_usAttributes & dmHdrAttrResDB) != 0 ? 10 : 8) + cbBonusPadding;
// Write out the record headers
uint id = 1;
foreach (PdbRecord pdbr in m_alsPdbRecords) {
if ((m_usAttributes & dmHdrAttrResDB) != 0) {
bwtr.Write(Misc.SwapUInt(pdbr.Type));
bwtr.Write(Misc.SwapUShort(pdbr.ID));
bwtr.Write(Misc.SwapUInt((uint)ibrecNext));
}
else {
// localChunkId (actually an offset to the bytes for this record)
bwtr.Write(Misc.SwapUInt((uint)ibrecNext));
// attributes
bwtr.Write((byte)0);
// uniqueID
bwtr.Write((byte)(id & 0xff));
bwtr.Write((byte)((id >> 8) & 0xff));
bwtr.Write((byte)((id >> 16) & 0xff));
}
ibrecNext += pdbr.Data.Length;
id++;
}
// Write bonus padding
while (cbBonusPadding-- != 0)
bwtr.Write((byte)0);
// Write out the record data
foreach (PdbRecord pdbr in m_alsPdbRecords)
bwtr.Write(pdbr.Data);
// Close & stats.
Console.WriteLine(Path.GetFileName(strFileName) + " written. " + bwtr.BaseStream.Length + " bytes.");
bwtr.Close();
return true;
}
public string Name {
get {
return m_strName;
}
set {
string strT = value;
if (strT.Length + 1 >= s_cbDbName)
strT = strT.Substring(0, s_cbDbName - 1);
m_strName = strT;
}
}
public uint CreatorId {
get {
return m_uiCreator;
}
set {
m_uiCreator = value;
}
}
public uint TypeId {
get {
return m_uiType;
}
set {
m_uiType = value;
}
}
}
}