-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathuFlagManager.pas
More file actions
169 lines (140 loc) · 4.68 KB
/
uFlagManager.pas
File metadata and controls
169 lines (140 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
unit uFlagManager;
interface
uses
Classes, SysUtils, uStructs;
type
TDatabaseFlags = record
ActiveShadow: Boolean; // hdr_active_shadow 0x01 (bit 0)
ForceWrite: Boolean; // hdr_force_write 0x02 (bit 1)
NoChecksums: Boolean; // hdr_no_checksums 0x10 (bit 4)
NoReserve: Boolean; // hdr_no_reserve 0x20 (bit 5)
SqlDialect3: Boolean; // hdr_sql_dialect_3 0x100 (bit 8)
ReadOnly: Boolean; // hdr_read_only 0x200 (bit 9)
end;
TFlagManager = class
private
FFileName: string;
FHeaderPageBuffer: TBytes;
FHeaderPageSize: Integer;
procedure LoadHeaderPage;
procedure SaveHeaderPage;
function FlagsToUShort(const Flags: TDatabaseFlags): UShort;
function UShortToFlags(FlagsValue: UShort): TDatabaseFlags;
public
constructor Create(const AFileName: string);
destructor Destroy; override;
function GetFlags: TDatabaseFlags;
procedure SetFlags(const NewFlags: TDatabaseFlags);
procedure SetForceWrite(Value: Boolean);
procedure SetReadOnly(Value: Boolean);
end;
implementation
uses
uPageAnalyzer;
constructor TFlagManager.Create(const AFileName: string);
begin
inherited Create;
FFileName := AFileName;
LoadHeaderPage;
end;
destructor TFlagManager.Destroy;
begin
inherited;
end;
procedure TFlagManager.LoadHeaderPage;
var
FileStream: TFileStream;
HeaderPageStruct: THdrPage;
PageSize: Integer;
begin
if not FileExists(FFileName) then
raise Exception.Create('File does not exist: ' + FFileName);
FileStream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite);
try
SetLength(FHeaderPageBuffer, MIN_PAGE_SIZE); // ×èòàåì ìèíèìóì äëÿ ïîëó÷åíèÿ hdr_page_size
if FileStream.Read(FHeaderPageBuffer[0], MIN_PAGE_SIZE) <> MIN_PAGE_SIZE then
raise Exception.Create('Cannot read header page.');
if FHeaderPageBuffer[0] <> pag_header then
raise Exception.Create('File does not start with a Header Page (type 0x01).');
Move(FHeaderPageBuffer[0], HeaderPageStruct, SizeOf(THdr));
PageSize := HeaderPageStruct.fix_data.hdr_page_size;
if (PageSize < MIN_PAGE_SIZE) or (PageSize > MAX_PAGE_SIZE) then
raise Exception.Create('Invalid page size in header: ' + IntToStr(PageSize));
SetLength(FHeaderPageBuffer, PageSize);
FileStream.Seek(0, soFromBeginning);
if FileStream.Read(FHeaderPageBuffer[0], PageSize) <> PageSize then
raise Exception.Create('Cannot read full header page.');
FHeaderPageSize := PageSize;
finally
FileStream.Free;
end;
end;
procedure TFlagManager.SaveHeaderPage;
var
FileStream: TFileStream;
begin
FileStream := TFileStream.Create(FFileName, fmOpenReadWrite or fmShareExclusive);
try
FileStream.Seek(0, soFromBeginning);
if FileStream.Write(FHeaderPageBuffer[0], FHeaderPageSize) <> FHeaderPageSize then
raise Exception.Create('Cannot write header page.');
finally
FileStream.Free;
end;
end;
function TFlagManager.FlagsToUShort(const Flags: TDatabaseFlags): UShort;
begin
Result := 0;
if Flags.ActiveShadow then Result := Result or $01;
if Flags.ForceWrite then Result := Result or $02;
if Flags.NoChecksums then Result := Result or $10;
if Flags.NoReserve then Result := Result or $20;
if Flags.SqlDialect3 then Result := Result or $100;
if Flags.ReadOnly then Result := Result or $200;
end;
function TFlagManager.UShortToFlags(FlagsValue: UShort): TDatabaseFlags;
begin
Result.ActiveShadow := (FlagsValue and $01) <> 0;
Result.ForceWrite := (FlagsValue and $02) <> 0;
Result.NoChecksums := (FlagsValue and $10) <> 0;
Result.NoReserve := (FlagsValue and $20) <> 0;
Result.SqlDialect3 := (FlagsValue and $100) <> 0;
Result.ReadOnly := (FlagsValue and $200) <> 0;
end;
function TFlagManager.GetFlags: TDatabaseFlags;
var
HeaderStruct: THdrPage;
FlagsValue: UShort;
begin
Move(FHeaderPageBuffer[0], HeaderStruct, SizeOf(THdr));
FlagsValue := HeaderStruct.fix_data.hdr_flags;
Result := UShortToFlags(FlagsValue);
end;
procedure TFlagManager.SetFlags(const NewFlags: TDatabaseFlags);
var
HeaderStruct: THdrPage;
NewFlagsValue: UShort;
begin
Move(FHeaderPageBuffer[0], HeaderStruct, SizeOf(THdr));
NewFlagsValue := FlagsToUShort(NewFlags);
HeaderStruct.fix_data.hdr_flags := NewFlagsValue;
Move(HeaderStruct, FHeaderPageBuffer[0], SizeOf(THdr));
SaveHeaderPage;
end;
procedure TFlagManager.SetForceWrite(Value: Boolean);
var
CurrentFlags: TDatabaseFlags;
begin
CurrentFlags := GetFlags();
CurrentFlags.ForceWrite := Value;
SetFlags(CurrentFlags);
end;
procedure TFlagManager.SetReadOnly(Value: Boolean);
var
CurrentFlags: TDatabaseFlags;
begin
CurrentFlags := GetFlags();
CurrentFlags.ReadOnly := Value;
SetFlags(CurrentFlags);
end;
end.