| 1 | unit UDBC;
|
|---|
| 2 |
|
|---|
| 3 | {$mode Delphi}{$H+}
|
|---|
| 4 |
|
|---|
| 5 | interface
|
|---|
| 6 |
|
|---|
| 7 | uses
|
|---|
| 8 | Classes, SysUtils, Strings, Variants;
|
|---|
| 9 |
|
|---|
| 10 | const
|
|---|
| 11 | HeaderSize = 20;
|
|---|
| 12 | DBCSignature = $43424457;
|
|---|
| 13 |
|
|---|
| 14 | type
|
|---|
| 15 | TDBCColumnType = (ctUInt32, ctSInt32, ctSingle, ctString, ctByte);
|
|---|
| 16 |
|
|---|
| 17 | { TDBC }
|
|---|
| 18 |
|
|---|
| 19 | TDBC = class
|
|---|
| 20 | private
|
|---|
| 21 | FileStream: TFileStream;
|
|---|
| 22 | RecordCount: Integer;
|
|---|
| 23 | FieldCount: Integer;
|
|---|
| 24 | RecordSize: Integer;
|
|---|
| 25 | StringBlockSize: Integer;
|
|---|
| 26 | public
|
|---|
| 27 | Cells: array of array of Variant;
|
|---|
| 28 | ColumnFormat: array of TDBCColumnType;
|
|---|
| 29 | function DetectColumnType(Column: Integer): TDBCColumnType;
|
|---|
| 30 | procedure LoadFromFile(FileName: string);
|
|---|
| 31 | procedure LoadColumnStrings(Column: Integer);
|
|---|
| 32 | procedure SaveToFile(FileName: string);
|
|---|
| 33 | procedure SetString(Row, Column: Integer; Text: AnsiString);
|
|---|
| 34 | end;
|
|---|
| 35 |
|
|---|
| 36 | implementation
|
|---|
| 37 |
|
|---|
| 38 | { TDBC }
|
|---|
| 39 |
|
|---|
| 40 | procedure TDBC.LoadFromFile(FileName: string);
|
|---|
| 41 | var
|
|---|
| 42 | Signature: Cardinal;
|
|---|
| 43 | Row, Col: Integer;
|
|---|
| 44 | begin
|
|---|
| 45 | FileStream := TFileStream.Create(FileName, fmOpenRead);
|
|---|
| 46 | with FileStream do begin
|
|---|
| 47 | Signature := ReadDWord;
|
|---|
| 48 | if Signature <> DBCSignature then
|
|---|
| 49 | raise Exception.Create('DBC type mismatch.');
|
|---|
| 50 |
|
|---|
| 51 | RecordCount := ReadDWord;
|
|---|
| 52 | FieldCount := ReadDWord;
|
|---|
| 53 | RecordSize := ReadDWord;
|
|---|
| 54 | StringBlockSize := ReadDWord;
|
|---|
| 55 |
|
|---|
| 56 | SetLength(Cells, RecordCount, FieldCount);
|
|---|
| 57 | for Row := 0 to RecordCount - 1 do
|
|---|
| 58 | for Col := 0 to FieldCount - 1 do begin
|
|---|
| 59 | Cells[Row, Col] := ReadDWord;
|
|---|
| 60 | end;
|
|---|
| 61 | end;
|
|---|
| 62 | end;
|
|---|
| 63 |
|
|---|
| 64 | procedure TDBC.LoadColumnStrings(Column: Integer);
|
|---|
| 65 | var
|
|---|
| 66 | Row: Integer;
|
|---|
| 67 | Offset: Integer;
|
|---|
| 68 | Text: AnsiString;
|
|---|
| 69 | C: Char;
|
|---|
| 70 | begin
|
|---|
| 71 | with FileStream do
|
|---|
| 72 | for Row := 0 to RecordCount - 1 do begin
|
|---|
| 73 | Offset := HeaderSize + RecordCount * RecordSize + Cells[Row, Column];
|
|---|
| 74 | if Position <> Offset then Seek(Offset, soBeginning);
|
|---|
| 75 |
|
|---|
| 76 | Text := '';
|
|---|
| 77 | C := ' ';
|
|---|
| 78 | while (C <> #0) do begin
|
|---|
| 79 | C := Chr(ReadByte);
|
|---|
| 80 | if C <> #0 then Text := Text + C;
|
|---|
| 81 | end;
|
|---|
| 82 | Cells[Row, Column] := Text;
|
|---|
| 83 | end;
|
|---|
| 84 | end;
|
|---|
| 85 |
|
|---|
| 86 | procedure TDBC.SaveToFile(FileName: string);
|
|---|
| 87 | var
|
|---|
| 88 | Row, Col: Integer;
|
|---|
| 89 | Offset: Integer;
|
|---|
| 90 | StringList: array of string;
|
|---|
| 91 | begin
|
|---|
| 92 | if Assigned(FileStream) then FileStream.Free;
|
|---|
| 93 | FileStream := TFileStream.Create(FileName, fmCreate);
|
|---|
| 94 | with FileStream do begin
|
|---|
| 95 | WriteDWord(DBCSignature);
|
|---|
| 96 | WriteDWord(RecordCount);
|
|---|
| 97 | WriteDWord(FieldCount);
|
|---|
| 98 | WriteDWord(RecordSize);
|
|---|
| 99 | WriteDWord(StringBlockSize);
|
|---|
| 100 |
|
|---|
| 101 | Size := RecordSize * RecordCount;
|
|---|
| 102 | SetLength(StringList, 0);
|
|---|
| 103 | Offset := 1;
|
|---|
| 104 | // Write cells
|
|---|
| 105 | for Row := 0 to RecordCount - 1 do begin
|
|---|
| 106 | for Col := 0 to FieldCount - 1 do begin
|
|---|
| 107 | if VarIsStr(Cells[Row, Col]) then begin
|
|---|
| 108 | //System.Write(IntToStr(Offset) + ': "' + Cells[Row, Col] + '", ');
|
|---|
| 109 | WriteDWord(Offset);
|
|---|
| 110 | Offset := Offset + Length(Cells[Row, Col]) + 1;
|
|---|
| 111 | SetLength(StringList, Length(StringList) + 1);
|
|---|
| 112 | StringList[High(StringList)] := Cells[Row, Col];
|
|---|
| 113 | end else begin
|
|---|
| 114 | //System.Write(IntToStr(Cells[Row, Col]) + ', ');
|
|---|
| 115 | WriteDWord(Cells[Row, Col]);
|
|---|
| 116 | end;
|
|---|
| 117 | end;
|
|---|
| 118 | //WriteLn;
|
|---|
| 119 | end;
|
|---|
| 120 |
|
|---|
| 121 | // Write strings
|
|---|
| 122 | Offset := 1;
|
|---|
| 123 | WriteByte(0);
|
|---|
| 124 | for Row := 0 to Length(StringList) - 1 do begin
|
|---|
| 125 | //WriteLn('Id: ' + IntToStr(Row) + ', Offset: ' + IntToStr(Offset) + ', "' + StringList[Row] + '"');
|
|---|
| 126 | for Col := 1 to Length(StringList[Row]) do
|
|---|
| 127 | WriteByte(Ord(StringList[Row][Col]));
|
|---|
| 128 | WriteByte(0);
|
|---|
| 129 | Offset := Offset + Length(StringList[Row]) + 1;
|
|---|
| 130 | end;
|
|---|
| 131 |
|
|---|
| 132 | // Update string block size
|
|---|
| 133 | StringBlockSize := Offset;
|
|---|
| 134 | Seek(16, soFromBeginning);
|
|---|
| 135 | WriteDWord(StringBlockSize);
|
|---|
| 136 | end;
|
|---|
| 137 | end;
|
|---|
| 138 |
|
|---|
| 139 | procedure TDBC.SetString(Row, Column: Integer; Text: AnsiString);
|
|---|
| 140 | begin
|
|---|
| 141 | if VarIsStr(Cells[Row,Column]) then begin
|
|---|
| 142 | StringBlockSize := StringBlockSize + strlen(Pchar(Text)) - strlen(Pchar(VarToStr(Cells[Row,Column])));
|
|---|
| 143 | Cells[Row,Column] := Text;
|
|---|
| 144 | end;
|
|---|
| 145 | end;
|
|---|
| 146 |
|
|---|
| 147 | function TDBC.DetectColumnType(Column: Integer): TDBCColumnType;
|
|---|
| 148 | //var
|
|---|
| 149 | // Row: Integer;
|
|---|
| 150 | begin
|
|---|
| 151 | (*
|
|---|
| 152 | Result := ctString;
|
|---|
| 153 | for Row := 0 to RecordCount - 1 do
|
|---|
| 154 | if GetStringByOffset(Cells[Row, Column]) = '' then Result := ctInt32;
|
|---|
| 155 | if Result = ctString then Exit;
|
|---|
| 156 | *)
|
|---|
| 157 | end;
|
|---|
| 158 |
|
|---|
| 159 | end.
|
|---|