Fixed audio playing
[kvidha.git] / fileio.c
CommitLineData
02f87e18
FT
1#include <stdio.h>\r
2#include <string.h>\r
3#include <time.h>\r
4\r
5#define DAT_START 7\r
6\r
7typedef struct KvidFileType\r
8{\r
9 FILE *FilePtr;\r
10 unsigned char AtEOF;\r
11 struct KvidFileType *Parent;\r
12 unsigned char DataFile;\r
13 unsigned char ReSeek;\r
14 unsigned char CanWrite;\r
15 unsigned long CurFAT;\r
16 unsigned long CurAU;\r
17 unsigned short Offset;\r
18 unsigned short AUSize;\r
19 unsigned char LastOp;\r
20 unsigned char CurBit, CurChar;\r
21} KvidFile;\r
22\r
23KvidFile *MainDat;\r
24\r
25static unsigned long GetFAT(KvidFile *FileStr, unsigned long AU)\r
26{\r
27 unsigned long CurFAT, i, TargetFAT;\r
28\r
29 CurFAT = 0;\r
30 TargetFAT = AU / ((FileStr->AUSize >> 2) - 1);\r
31 for(i = 0; i < TargetFAT; i++)\r
32 {\r
33 fseek(FileStr->FilePtr, DAT_START + (CurFAT * FileStr->AUSize), SEEK_SET);\r
34 fread((void *)&CurFAT, 4, 1, FileStr->FilePtr);\r
35 }\r
36 return(CurFAT);\r
37}\r
38\r
39static void SetFATEntry(KvidFile *FileStr, unsigned long AU, unsigned long Entry)\r
40{\r
41 unsigned long CurFAT, i, TargetFAT;\r
42\r
43 CurFAT = 0;\r
44 TargetFAT = AU / ((FileStr->AUSize >> 2) - 1);\r
45 for(i = 0; i < TargetFAT; i++)\r
46 {\r
47 fseek(FileStr->FilePtr, DAT_START + (CurFAT * FileStr->AUSize), SEEK_SET);\r
48 fread((void *)&CurFAT, 4, 1, FileStr->FilePtr);\r
49 if(CurFAT >= 0x80000000)\r
50 return;\r
51 }\r
52 fseek(FileStr->FilePtr, DAT_START + (CurFAT * FileStr->AUSize) + (((AU % ((FileStr->AUSize >> 2) - 1)) + 1) << 2), SEEK_SET);\r
53 fwrite((void *)&Entry, 4, 1, FileStr->FilePtr);\r
54}\r
55\r
56static unsigned long FindFreeAU(KvidFile *FileStr, unsigned char InhibitCreation)\r
57{\r
58 unsigned long OldFAT, CurFAT, NumEntries, Entry, i, FATNum;\r
59\r
60 CurFAT = 0;\r
61 FATNum = 0;\r
62 NumEntries = (FileStr->AUSize >> 2) - 1;\r
63 while(CurFAT < 0x80000000)\r
64 {\r
65 OldFAT = CurFAT;\r
66 fseek(FileStr->FilePtr, DAT_START + (CurFAT * FileStr->AUSize), SEEK_SET);\r
67 fread((void *)&CurFAT, 4, 1, FileStr->FilePtr);\r
68 for(i = 0; i < NumEntries; i++)\r
69 {\r
70 fread((void *)&Entry, 4, 1, FileStr->FilePtr);\r
71 if(Entry == 0)\r
72 return((FATNum * NumEntries) + i);\r
73 }\r
74 FATNum++;\r
75 }\r
76 if(InhibitCreation == 1)\r
77 return(0xFFFFFFFF);\r
78 fseek(FileStr->FilePtr, DAT_START + (OldFAT * FileStr->AUSize), SEEK_SET);\r
79 CurFAT = NumEntries * FATNum;\r
80 fwrite((void *)&CurFAT, 4, 1, FileStr->FilePtr);\r
81 fseek(FileStr->FilePtr, DAT_START + (CurFAT * FileStr->AUSize), SEEK_SET);\r
82 Entry = 0xFFFFFFFF;\r
83 fwrite((void *)&Entry, 4, 1, FileStr->FilePtr);\r
84 Entry = 0;\r
85 for(i = 0; i < NumEntries; i++)\r
86 {\r
87 fwrite((void *)&Entry, 4, 1, FileStr->FilePtr);\r
88 }\r
89 SetFATEntry(FileStr, CurFAT, 0xFFFFFFFE);\r
90 return(FindFreeAU(FileStr, 1));\r
91}\r
92\r
93static unsigned char GetDatChar(KvidFile *FileStr)\r
94{\r
95 unsigned char RetVal;\r
96 unsigned short OldAU;\r
97 unsigned short NumEntries;\r
98 KvidFile *CurFile;\r
99\r
100 for(CurFile = FileStr->Parent; CurFile != NULL; CurFile = CurFile->Parent)\r
101 CurFile->ReSeek = 1;\r
102 if(FileStr->ReSeek == 1)\r
103 {\r
104 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurAU * FileStr->AUSize) + FileStr->Offset, SEEK_SET);\r
105 FileStr->ReSeek = 0;\r
106 FileStr->CurFAT = 0xFFFFFFFF;\r
107 }\r
108 RetVal = (unsigned char)fgetc(FileStr->FilePtr);\r
109 if(FileStr->Offset++ == FileStr->AUSize - 1)\r
110 {\r
111 if(FileStr->CurFAT == 0xFFFFFFFF)\r
112 FileStr->CurFAT = GetFAT(FileStr, FileStr->CurAU);\r
113 OldAU = FileStr->CurAU;\r
114 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurFAT * FileStr->AUSize) + (((FileStr->CurAU % ((FileStr->AUSize >> 2) - 1)) + 1) << 2), SEEK_SET);\r
115 fread((void *)&FileStr->CurAU, 4, 1, FileStr->FilePtr);\r
116 if(FileStr->CurAU == 0xFFFFFFFF)\r
117 FileStr->AtEOF = 1;\r
118 FileStr->Offset = 0;\r
119 NumEntries = (FileStr->AUSize >> 2) - 1;\r
120 if((FileStr->CurAU / NumEntries) == (OldAU / NumEntries))\r
121 {\r
122 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurAU * FileStr->AUSize) + FileStr->Offset, SEEK_SET);\r
123 } else {\r
124 FileStr->ReSeek = 1;\r
125 }\r
126 }\r
127 return(RetVal);\r
128}\r
129\r
130static void PutDatChar(unsigned char c, KvidFile *FileStr)\r
131{\r
132 unsigned char RetVal;\r
133 unsigned long OldAU;\r
134 KvidFile *CurFile;\r
135\r
136 for(CurFile = FileStr->Parent; CurFile != NULL; CurFile = CurFile->Parent)\r
137 CurFile->ReSeek = 1;\r
138 if(FileStr->ReSeek == 1)\r
139 {\r
140 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurAU * FileStr->AUSize) + FileStr->Offset, SEEK_SET);\r
141 FileStr->ReSeek = 0;\r
142 FileStr->CurFAT = 0xFFFFFFFF;\r
143 }\r
144 fputc(c, FileStr->FilePtr);\r
145 if(FileStr->Offset++ == FileStr->AUSize - 1)\r
146 {\r
147 if(FileStr->CurFAT == 0xFFFFFFFF)\r
148 FileStr->CurFAT = GetFAT(FileStr, FileStr->CurAU);\r
149 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurFAT * FileStr->AUSize) + (((FileStr->CurAU % ((FileStr->AUSize >> 2) - 1)) + 1) << 2), SEEK_SET);\r
150 OldAU = FileStr->CurAU;\r
151 fread((void *)&FileStr->CurAU, 4, 1, FileStr->FilePtr);\r
152 if(FileStr->CurAU == 0xFFFFFFFF)\r
153 {\r
154 FileStr->CurAU = FindFreeAU(FileStr, 0);\r
155 SetFATEntry(FileStr, OldAU, FileStr->CurAU);\r
156 SetFATEntry(FileStr, FileStr->CurAU, 0xFFFFFFFF);\r
157 }\r
158 FileStr->Offset = 0;\r
159 FileStr->ReSeek = 1;\r
160 }\r
161}\r
162\r
163unsigned char FileGetChar(KvidFile *FileStr)\r
164{\r
165 signed long RetVal;\r
166\r
167 if(FileStr->AtEOF == 1)\r
168 return(0);\r
169 if(FileStr->LastOp == 1)\r
170 {\r
171 FileStr->LastOp = 0;\r
172 fflush(FileStr->FilePtr);\r
173 }\r
174 if(FileStr->Parent != NULL)\r
175 return(GetDatChar(FileStr));\r
176 if((FileStr->Parent == NULL) && (FileStr->DataFile == 0))\r
177 {\r
178 if((RetVal = (signed long)fgetc(FileStr->FilePtr)) == EOF)\r
179 {\r
180 FileStr->AtEOF = 1;\r
181 return(0);\r
182 } else {\r
183 return((unsigned char)RetVal);\r
184 }\r
185 }\r
186 if((FileStr->Parent == NULL) && (FileStr->DataFile == 1))\r
187 return(GetDatChar(FileStr));\r
188}\r
189\r
190void FilePutChar(unsigned char c, KvidFile *FileStr)\r
191{\r
192 if(FileStr->CanWrite == 0)\r
193 return;\r
194 FileStr->LastOp = 1;\r
195 if(FileStr->Parent != NULL)\r
196 PutDatChar(c, FileStr);\r
197 if((FileStr->Parent == NULL) && (FileStr->DataFile == 0))\r
198 fputc(c, FileStr->FilePtr);\r
199 if((FileStr->Parent == NULL) && (FileStr->DataFile == 1))\r
200 PutDatChar(c, FileStr);\r
201}\r
202\r
203void FileSkip(KvidFile *FileStr, unsigned long NumBytes)\r
204{\r
205 KvidFile *CurFile;\r
206\r
207 if(FileStr->AtEOF == 1)\r
208 return;\r
209 if((FileStr->Parent == NULL) && (FileStr->DataFile == 0))\r
210 {\r
211 fseek(FileStr->FilePtr, NumBytes, SEEK_CUR);\r
212 return;\r
213 }\r
214 for(CurFile = FileStr->Parent; CurFile != NULL; CurFile = CurFile->Parent)\r
215 CurFile->ReSeek = 1;\r
216 if(FileStr->ReSeek == 1)\r
217 FileStr->CurFAT = 0xFFFFFFFF;\r
218 while((NumBytes > 0) && (FileStr->AtEOF == 0))\r
219 {\r
220 if(NumBytes < FileStr->AUSize - FileStr->Offset)\r
221 {\r
222 if(FileStr->ReSeek == 0)\r
223 fseek(FileStr->FilePtr, NumBytes, SEEK_CUR);\r
224 FileStr->Offset += NumBytes;\r
225 NumBytes = 0;\r
226 } else {\r
227 NumBytes -= FileStr->AUSize - FileStr->Offset;\r
228 if(FileStr->CurFAT == 0xFFFFFFFF)\r
229 FileStr->CurFAT = GetFAT(FileStr, FileStr->CurAU);\r
230 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurFAT * FileStr->AUSize) + (((FileStr->CurAU % ((FileStr->AUSize >> 2) - 1)) + 1) << 2), SEEK_SET);\r
231 fread((void *)&FileStr->CurAU, 4, 1, FileStr->FilePtr);\r
232 if(FileStr->CurAU == 0xFFFFFFFF)\r
233 FileStr->AtEOF = 1;\r
234 FileStr->Offset = 0;\r
235 FileStr->ReSeek = 1;\r
236 }\r
237 }\r
238 if(FileStr->ReSeek == 1)\r
239 {\r
240 fseek(FileStr->FilePtr, DAT_START + (FileStr->CurAU * FileStr->AUSize) + FileStr->Offset, SEEK_SET);\r
241 FileStr->ReSeek = 0;\r
242 FileStr->CurFAT = 0xFFFFFFFF;\r
243 }\r
244}\r
245\r
246unsigned long FileReadBits(unsigned char NumBits, KvidFile *FileStr)\r
247{\r
248 unsigned char i;\r
249 unsigned long Value;\r
250\r
251 Value = 0;\r
252 for(i = NumBits; i > 0; i--)\r
253 {\r
254 if(FileStr->CurBit > 7)\r
255 {\r
256 FileStr->CurChar = fgetc(FileStr->FilePtr);\r
257 FileStr->CurBit = 7;\r
258 }\r
259 if((FileStr->CurChar & (1 << FileStr->CurBit)) != 0)\r
260 Value += 1 << (i - 1);\r
261 FileStr->CurBit--;\r
262 }\r
263 return(Value);\r
264}\r
265\r
266void FileRead(void *Buffer, unsigned long NumBytes, KvidFile *FileStr)\r
267{\r
268 if((FileStr->Parent == NULL) && (FileStr->DataFile == 0))\r
269 {\r
270 fread(Buffer, NumBytes, 1, FileStr->FilePtr);\r
271 return;\r
272 }\r
273 while(NumBytes-- > 0)\r
274 *(unsigned char *)Buffer++ = FileGetChar(FileStr);\r
275}\r
276\r
277void FileWrite(void *Buffer, unsigned long NumBytes, KvidFile *FileStr)\r
278{\r
279 if(FileStr->CanWrite == 0)\r
280 return;\r
281 if((FileStr->Parent == NULL) && (FileStr->DataFile == 0))\r
282 {\r
283 fwrite(Buffer, NumBytes, 1, FileStr->FilePtr);\r
284 return;\r
285 }\r
286 while(NumBytes-- > 0)\r
287 FilePutChar(*(unsigned char *)Buffer++, FileStr);\r
288}\r
289\r
290void FileClose(KvidFile *FileStr)\r
291{\r
292 if(FileStr->Parent == NULL)\r
293 fclose(FileStr->FilePtr);\r
294}\r
295\r
296unsigned char OpenRootDir(KvidFile *FileStr, KvidFile *ParentFile)\r
297{\r
298 if(ParentFile->DataFile == 0)\r
299 return(0);\r
300 FileStr->DataFile = 0;\r
301 FileStr->CanWrite = ParentFile->CanWrite;\r
302 FileStr->Parent = ParentFile;\r
303 FileStr->FilePtr = ParentFile->FilePtr;\r
304 FileStr->AtEOF = 0;\r
305 FileStr->LastOp = 0;\r
306 FileStr->ReSeek = 1;\r
307 FileStr->CurAU = 1;\r
308 FileStr->Offset = 0;\r
309 FileStr->AUSize = ParentFile->AUSize;\r
310 FileStr->CurBit = 255;\r
311 return(1);\r
312}\r
313\r
314unsigned char OpenNestedFile(unsigned char *FileName, KvidFile *FileStr, KvidFile *ParentFile, unsigned long *TimeBuffer)\r
315{\r
316 unsigned char FileNameBuffer[20];\r
317 KvidFile RootDir;\r
318\r
319 if(OpenRootDir(&RootDir, ParentFile) == 0)\r
320 return(0);\r
321 FileStr->DataFile = 0;\r
322 FileStr->CanWrite = ParentFile->CanWrite;\r
323 FileStr->Parent = ParentFile;\r
324 FileStr->FilePtr = ParentFile->FilePtr;\r
325 FileStr->AtEOF = 0;\r
326 FileStr->LastOp = 0;\r
327 FileStr->ReSeek = 1;\r
328 FileStr->Offset = 0;\r
329 FileStr->AUSize = ParentFile->AUSize;\r
330 FileStr->CurBit = 255;\r
331 while(1)\r
332 {\r
333 FileRead((void *)FileNameBuffer, 20, &RootDir);\r
334 if((FileNameBuffer[0] == 0) || (RootDir.AtEOF == 1))\r
335 return(0);\r
336 if(strcmp(FileNameBuffer, FileName) == 0)\r
337 {\r
338 FileRead((void *)FileNameBuffer, 4, &RootDir);\r
339 FileNameBuffer[4] = 0;\r
340 if(TimeBuffer == NULL)\r
341 FileSkip(&RootDir, 4);\r
342 else\r
343 FileRead((void *)TimeBuffer, 4, &RootDir);\r
344 FileRead((void *)&FileStr->CurAU, 4, &RootDir);\r
345 if(strcmp(FileNameBuffer, "SDIR") == 0)\r
346 {\r
347 FileRead((void *)FileNameBuffer, 5, FileStr);\r
348 FileNameBuffer[5] = 0;\r
349 if(strcmp(FileNameBuffer, "KFDAT") != 0)\r
350 return(0);\r
351 FileRead((void *)&FileStr->AUSize, 2, FileStr);\r
352 FileStr->DataFile = 1;\r
353 }\r
354 return(1);\r
355 } else {\r
356 FileSkip(&RootDir, 12);\r
357 }\r
358 }\r
359}\r
360\r
361unsigned char OpenFile(unsigned char *FileName, KvidFile *FileStr)\r
362{\r
363 FileStr->DataFile = 0;\r
364 FileStr->Parent = NULL;\r
365 FileStr->AtEOF = 0;\r
366 FileStr->LastOp = 0;\r
367 FileStr->CurBit = 255;\r
368 if((FileStr->FilePtr = fopen(FileName, "rb+")) == NULL)\r
369 {\r
370 if((FileStr->FilePtr = fopen(FileName, "rb")) == NULL)\r
371 return((MainDat == NULL)?0:OpenNestedFile(FileName, FileStr, MainDat, NULL));\r
372 else\r
373 FileStr->CanWrite = 0;\r
374 } else {\r
375 FileStr->CanWrite = 1;\r
376 }\r
377 return(1);\r
378}\r
379\r
380unsigned char DeleteFile(unsigned char *FileName, KvidFile *ParentFile)\r
381{\r
382 unsigned char FileNameBuffer[20];\r
383 unsigned short OldOffset;\r
384 unsigned long OldAU, CurAU, CurFAT;\r
385 KvidFile RootDir;\r
386\r
387 if(OpenRootDir(&RootDir, ParentFile) == 0)\r
388 return(0);\r
389 while(1)\r
390 {\r
391 OldOffset = RootDir.Offset;\r
392 OldAU = RootDir.CurAU;\r
393 FileRead((void *)FileNameBuffer, 20, &RootDir);\r
394 if((FileNameBuffer[0] == 0) || (RootDir.AtEOF == 1))\r
395 return(0);\r
396 if(strcmp(FileNameBuffer, FileName) == 0)\r
397 {\r
398 FileSkip(&RootDir, 8);\r
399 FileRead(&CurAU, 4, &RootDir);\r
400 RootDir.Offset = OldOffset;\r
401 RootDir.CurAU = OldAU;\r
402 RootDir.ReSeek = 1;\r
403 FilePutChar(1, &RootDir);\r
404 while(CurAU < 0x80000000)\r
405 {\r
406 CurFAT = GetFAT(&RootDir, CurAU);\r
407 fseek(RootDir.FilePtr, DAT_START + (CurFAT * RootDir.AUSize) + ((CurAU % ((RootDir.AUSize >> 2) - 1)) << 2) + 4, SEEK_SET);\r
408 OldAU = CurAU;\r
409 fread((void *)&CurAU, 4, 1, RootDir.FilePtr);\r
410 fseek(RootDir.FilePtr, DAT_START + (CurFAT * RootDir.AUSize) + ((OldAU % ((RootDir.AUSize >> 2) - 1)) << 2) + 4, SEEK_SET);\r
411 CurFAT = 0;\r
412 fwrite((void *)&CurFAT, 4, 1, RootDir.FilePtr);\r
413 }\r
414 return(1);\r
415 } else {\r
416 FileSkip(&RootDir, 12);\r
417 }\r
418 }\r
419}\r
420\r
421unsigned char CreateFile(unsigned char *FileName, KvidFile *FileStr, KvidFile *ParentFile, unsigned long FileType)\r
422{\r
423 KvidFile RootDir;\r
424 unsigned char FileNameBuffer[20];\r
425 unsigned char Existing;\r
426 unsigned long OldAU;\r
427 unsigned short OldOffset;\r
428 unsigned long i;\r
429 unsigned long CurTime;\r
430 unsigned long NewAU;\r
431\r
432 if(ParentFile == NULL)\r
433 {\r
434 FileStr->DataFile = 0;\r
435 FileStr->Parent = NULL;\r
436 FileStr->AtEOF = 1;\r
437 FileStr->LastOp = 0;\r
438 FileStr->CanWrite = 1;\r
439 if((FileStr->FilePtr = fopen(FileName, "wb+")) == NULL)\r
440 return(0);\r
441 else\r
442 return(1);\r
443 }\r
444 if((OpenRootDir(&RootDir, ParentFile) == 0) || (RootDir.CanWrite == 0))\r
445 return(0);\r
446 FileStr->DataFile = 0;\r
447 FileStr->CanWrite = ParentFile->CanWrite;\r
448 FileStr->Parent = ParentFile;\r
449 FileStr->FilePtr = ParentFile->FilePtr;\r
450 FileStr->AtEOF = 0;\r
451 FileStr->LastOp = 0;\r
452 FileStr->ReSeek = 1;\r
453 FileStr->Offset = 0;\r
454 FileStr->AUSize = ParentFile->AUSize;\r
455 FileStr->CurBit = 255;\r
456 while(1)\r
457 {\r
458 OldAU = RootDir.CurAU;\r
459 OldOffset = RootDir.Offset;\r
460 FileRead((void *)FileNameBuffer, 20, &RootDir);\r
461 if(((Existing = FileNameBuffer[0]) < 2) || (RootDir.AtEOF == 1))\r
462 {\r
463 RootDir.CurAU = OldAU;\r
464 RootDir.Offset = OldOffset;\r
465 RootDir.ReSeek = 1;\r
466 for(i = 0; FileName[i] != 0; i++)\r
467 FileNameBuffer[i] = FileName[i];\r
468 while(i < 20)\r
469 FileNameBuffer[i++] = 0;\r
470 FileWrite((void *)FileNameBuffer, 20, &RootDir);\r
471 FileWrite((void *)&FileType, 4, &RootDir);\r
472 CurTime = (unsigned long)time(NULL);\r
473 FileWrite((void *)&CurTime, 4, &RootDir);\r
474 NewAU = FindFreeAU(ParentFile, 0);\r
475 SetFATEntry(ParentFile, NewAU, 0xFFFFFFFF);\r
476 RootDir.ReSeek = 1;\r
477 FileWrite((void *)&NewAU, 4, &RootDir);\r
478 if(Existing == 0)\r
479 for(i = 0; i < 32; i++)\r
480 FilePutChar(0, &RootDir);\r
481 FileStr->CurAU = NewAU;\r
482 return(1);\r
483 }\r
484 FileSkip(&RootDir, 12);\r
485 }\r
486}\r
487\r
488unsigned char OpenDatFile(unsigned char *FileName, KvidFile *FileStr)\r
489{\r
490 unsigned char Signature[6];\r
491 FileStr->DataFile = 1;\r
492 FileStr->Parent = NULL;\r
493 FileStr->ReSeek = 0;\r
494 FileStr->AtEOF = 0;\r
495 FileStr->LastOp = 0;\r
496 FileStr->CurBit = 255;\r
497 if((FileStr->FilePtr = fopen(FileName, "rb+")) == NULL)\r
498 {\r
499 if((FileStr->FilePtr = fopen(FileName, "rb")) == NULL)\r
500 return(0);\r
501 else\r
502 FileStr->CanWrite = 0;\r
503 } else {\r
504 FileStr->CanWrite = 1;\r
505 }\r
506 fread((void *)Signature, 1, 5, FileStr->FilePtr);\r
507 Signature[5] = 0;\r
508 if(strcmp(Signature, "KFDAT") != 0)\r
509 {\r
510 fclose(FileStr->FilePtr);\r
511 return(0);\r
512 }\r
513 fread((void *)&FileStr->AUSize, 2, 1, FileStr->FilePtr);\r
514 if((FileStr->AUSize % 4) != 0)\r
515 {\r
516 fclose(FileStr->FilePtr);\r
517 return(0);\r
518 }\r
519 FileStr->CurFAT = 0;\r
520 FileStr->CurAU = 0;\r
521 FileStr->Offset = 0;\r
522 return(1);\r
523}\r