source: trunk/includes/dbc.php

Last change on this file was 880, checked in by chronos, 5 years ago
  • Modified: Improved code formatting.
File size: 8.3 KB
Line 
1<?php
2
3include_once('FileStream.php');
4include_once('MemoryStream.php');
5
6define('NOT_DBC_FILE', 'Není DBC soubor.');
7define('RECORD_SIZE_NOT_MATCH', 'Velikost řádku neodpovídá zadanému formátu.');
8
9define('DBC_SIGNATURE', 0x43424457);
10
11define('FORMAT_UINT32', 0);
12define('FORMAT_SINT32', 1);
13define('FORMAT_SINGLE', 2);
14define('FORMAT_STRING', 3);
15define('FORMAT_BYTE', 4);
16
17class DBCFile extends FileStream
18{
19 private $HeaderSize = 20;
20 private $Offsets;
21 private $StringOffset;
22 private $StringList = array();
23 private $StringListOffset = array();
24 private $ColumnFormat; // Array (Index => Type)
25 private $EndOffset; // Calculated RecordSize according columns type
26
27 private $RecordSize;
28 private $RecordCount;
29 private $StringBlockSize;
30 private $FieldCount;
31
32 public function OpenFile($FileName, $ColumnFormat = array())
33 {
34 parent::OpenFile($FileName);
35
36 $this->ColumnFormat = $ColumnFormat;
37 if ($this->ReadUint() != DBC_SIGNATURE) die(NOT_DBC_FILE);
38
39 $this->RecordCount = $this->ReadUint();
40 $this->FieldCount = $this->ReadUint();
41 $this->RecordSize = $this->ReadUint();
42 $this->StringBlockSize = $this->ReadUint();
43
44 $this->GenerateOffsetTable();
45 if ($this->EndOffset != $this->RecordSize)
46 die(RECORD_SIZE_NOT_MATCH.$this->EndOffset.' <> '.$this->RecordSize);
47 }
48
49 public function CreateFile($FileName, $ColumnFormat = array())
50 {
51 parent::CreateFile($FileName);
52
53 $this->WriteUint(DBC_SIGNATURE);
54
55 $this->StringList = array();
56 $this->StringOffset = 1;
57 $this->ColumnFormat = $ColumnFormat;
58 $this->FieldCount = 0;
59 $this->GenerateOffsetTable();
60 $this->RecordCount = 0;
61 $this->RecordSize = $this->EndOffset;
62 $this->StringBlockSize = 0;
63
64 $this->WriteUint($this->RecordCount);
65 $this->WriteUint($this->FieldCount);
66 $this->WriteUint($this->RecordSize);
67 $this->WriteUint($this->StringBlockSize);
68 }
69
70 private function GenerateOffsetTable()
71 {
72 // Preallocate array
73 if ($this->FieldCount > 0) $this->Offsets = array_fill(0, $this->FieldCount, 0);
74 else $this->Offsets = array();
75
76 $Offset = 0;
77 $I = 0;
78 while ($I < $this->FieldCount)
79 {
80 $this->Offsets[$I] = $Offset;
81 if (array_key_exists($I, $this->ColumnFormat)) $Format = $this->ColumnFormat[$I];
82 else $Format = FORMAT_UINT32;
83 switch ($Format)
84 {
85 case FORMAT_BYTE:
86 $Offset += 1;
87 break;
88 case FORMAT_UINT32:
89 case FORMAT_SINT32:
90 case FORMAT_SINGLE:
91 case FORMAT_STRING:
92 $Offset += 4;
93 break;
94 }
95 $I++;
96 }
97 $this->EndOffset = $Offset;
98 }
99
100 private function CellPos($Row, $Column)
101 {
102 return $this->HeaderSize + $Row * $this->RecordSize + $this->Offsets[$Column];
103 }
104
105 public function GetByte($Row, $Column)
106 {
107 $this->SetPosition($this->CellPos($Row, $Column));
108 return $this->ReadByte();
109 }
110
111 public function GetUInt($Row, $Column)
112 {
113 $this->SetPosition($this->CellPos($Row, $Column));
114 return $this->ReadUint();
115 }
116
117 public function GetInt($Row, $Column)
118 {
119 $this->SetPosition($this->CellPos($Row, $Column));
120 return $this->ReadInt();
121 }
122
123 public function GetFloat($Row, $Column)
124 {
125 $this->SetPosition($this->CellPos($Row, $Column));
126 return $this->ReadFloat();
127 }
128
129 public function SetByte($Row, $Column, $Value)
130 {
131 $this->SetPosition($this->CellPos($Row, $Column));
132 $this->WriteByte($Value);
133 }
134
135 public function SetUint($Row, $Column, $Value)
136 {
137 $this->SetPosition($this->CellPos($Row, $Column));
138 $this->WriteUint($Value);
139 }
140
141 public function SetInt($Row, $Column, $Value)
142 {
143 $this->SetPosition($this->CellPos($Row, $Column));
144 $this->WriteInt($Value);
145 }
146
147 public function SetFloat($Row, $Column, $Value)
148 {
149 $this->SetPosition($this->CellPos($Row, $Column));
150 $this->WriteFloat($Value);
151 }
152
153 public function GetString($Row, $Column)
154 {
155 $Offset = $this->GetUint($Row, $Column);
156
157 $Position = $this->HeaderSize + $this->RecordCount * $this->RecordSize + $Offset;
158 if ($Position >= $this->GetSize()) return '';
159 $this->SetPosition($Position);
160
161 $String = '';
162 while (($Char = $this->ReadChar()) != "\0")
163 {
164 $String .= $Char;
165 }
166 return $String;
167 }
168
169 public function SetString($Row, $Column, $Value)
170 {
171 if (in_array($Value, $this->StringList))
172 {
173 $this->SetUint($Row, $Column, $this->StringListOffset[array_search($Value, $this->StringList)]);
174 } else
175 {
176 $this->SetUint($Row, $Column, $this->StringOffset);
177 $this->StringList[] = $Value;
178 $this->StringListOffset[] = $this->StringOffset;
179 $this->StringOffset += strlen($Value) + 1;
180 }
181 }
182
183 public function Commit()
184 {
185 $this->SetSize($this->HeaderSize + $this->RecordSize * $this->RecordCount); // Preallocate file
186 $this->SetPosition(0);
187 $this->WriteUint(DBC_SIGNATURE);
188 $this->WriteUint($this->RecordCount);
189 $this->WriteUint($this->FieldCount);
190 $this->WriteUint($this->RecordSize);
191 $this->WriteUint($this->StringOffset);
192 $this->SetPosition($this->HeaderSize + $this->RecordCount * $this->RecordSize);
193 $this->WriteByte(0);
194 foreach ($this->StringList as $Index => $Item)
195 {
196 $this->WriteString($Item."\0");
197 }
198 }
199
200 public function GetLine($Row)
201 {
202 // Cache record data
203 $Record = new MemoryStream();
204 $this->SetPosition($this->CellPos($Row, 0));
205 $Record->Data = $this->ReadBlock($this->RecordSize);
206
207 // Preallocate array
208 if ($this->FieldCount > 0) $Line = array_fill(0, $this->FieldCount, 0);
209 else $Line = array();
210 for ($I = 0; $I < $this->FieldCount; $I++)
211 {
212 if (array_key_exists($I, $this->ColumnFormat)) $Format = $this->ColumnFormat[$I];
213 else $Format = FORMAT_UINT32;
214 $Record->SetPosition($this->Offsets[$I]);
215 switch ($Format)
216 {
217 case FORMAT_BYTE:
218 $Line[$I] = $Record->ReadByte();
219 break;
220 case FORMAT_UINT32:
221 $Line[$I] = $Record->ReadUInt();
222 break;
223 case FORMAT_SINT32:
224 $Line[$I] = $Record->ReadInt();
225 break;
226 case FORMAT_SINGLE:
227 $Line[$I] = $Record->ReadFloat();
228 break;
229 case FORMAT_STRING:
230 $Offset = $Record->ReadUint();
231
232 $Position = $this->HeaderSize + $this->RecordCount * $this->RecordSize + $Offset;
233 if ($Position >= $this->GetSize()) $String = '';
234 else
235 {
236 $this->SetPosition($Position);
237 $String = '';
238 while (($Char = $this->ReadChar()) != "\0")
239 $String .= $Char;
240 }
241 $Line[$I] = $String;
242 break;
243 default:
244 break;
245 }
246 }
247 return $Line;
248 }
249
250 public function SetLine($Row, $Line)
251 {
252 // Cache record data
253 $Record = new MemoryStream();
254
255 for ($I = 0; $I < $this->FieldCount; $I++)
256 {
257 if (array_key_exists($I, $this->ColumnFormat)) $Format = $this->ColumnFormat[$I];
258 else $Format = FORMAT_UINT32;
259 $Record->SetPosition($this->Offsets[$I]);
260 switch ($Format)
261 {
262 case FORMAT_BYTE:
263 $Record->WriteByte($Line[$I]);
264 break;
265 case FORMAT_UINT32:
266 $Record->WriteUint($Line[$I]);
267 break;
268 case FORMAT_SINT32:
269 $Record->WriteInt($Line[$I]);
270 break;
271 case FORMAT_SINGLE:
272 $Record->WriteFloat($Line[$I]);
273 break;
274 case FORMAT_STRING:
275 if (in_array($Line[$I], $this->StringList))
276 {
277 $Record->WriteUint($this->StringListOffset[array_search($Line[$I], $this->StringList)]);
278 } else
279 {
280 $Record->WriteUint($this->StringOffset);
281 $this->StringList[] = $Line[$I];
282 $this->StringListOffset[] = $this->StringOffset;
283 $this->StringOffset += strlen($Line[$I]) + 1;
284 }
285 break;
286 default:
287 break;
288 }
289 }
290
291 $this->SetPosition($this->CellPos($Row, 0));
292 $this->WriteBlock($Record->Data, $this->RecordSize);
293 return $Line;
294 }
295
296 public function GetRecordCount()
297 {
298 return $this->RecordCount;
299 }
300
301 public function SetRecordCount($Value)
302 {
303 $this->RecordCount = $Value;
304 }
305
306 public function GetFieldCount()
307 {
308 return $this->FieldCount;
309 }
310
311 public function SetFieldCount($Value)
312 {
313 $this->FieldCount = $Value;
314 $this->GenerateOffsetTable();
315 $this->RecordSize = $this->EndOffset;
316 }
317}
Note: See TracBrowser for help on using the repository browser.