PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
romimg.c
1/*
2 roming.c - ROM image file manager.
3*/
4
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10#include <limits.h>
11
12#include "platform.h"
13#include "romimg.h"
14#include "SonyRX.h"
15
16#define IMAGE_COMMENT_BASESIZE 31
17
19{
20 void *image;
21 unsigned int size;
22 void *ROMFS_start;
23};
24
26{
27 unsigned int FileOffset; /* The offset into the image at which the file exists at. */
28 unsigned int ExtInfoOffset;
29 unsigned int size;
30 unsigned int offset;
31 unsigned short int ExtInfoEntrySize;
32};
33
34static int GetRomDirExtInfoOffset(const struct ROMImgStat *ImageStat, struct RomDirFileFd *fd)
35{
36 const struct RomDirEntry *RomDirEntry;
37 int result;
38 unsigned int offset;
39 RomDirEntry = (const struct RomDirEntry *)ImageStat->ROMFS_start; // (struct RomDirEntry *)
40 result = ENOENT;
41 offset = 0;
42 while (RomDirEntry->name[0] != '\0') {
43 if (strncmp("EXTINFO", RomDirEntry->name, sizeof(RomDirEntry->name)) == 0) {
44 DPRINTF("Found 'EXTINFO' at 0x%x\n", offset);
45 fd->ExtInfoOffset = offset;
46 result = 0;
47 break;
48 }
49
50 offset += (RomDirEntry->size + 0xF) & ~0xF;
52 }
53
54 return result;
55}
56
57static int OpenRomDirFile(const struct ROMImgStat *ImageStat, const char *file, struct RomDirFileFd *fd)
58{
59 const struct RomDirEntry *RomDirEntry;
60 int result;
61
62 memset(fd, 0, sizeof(struct RomDirFileFd));
63
64 RomDirEntry = (const struct RomDirEntry *)ImageStat->ROMFS_start;
65 result = ENOENT;
66 if (GetRomDirExtInfoOffset(ImageStat, fd) == 0) {
67 unsigned int offset = 0;
68 while (RomDirEntry->name[0] != '\0') {
69 if (strncmp(file, RomDirEntry->name, sizeof(RomDirEntry->name)) == 0) {
70 fd->FileOffset = offset;
71 fd->size = RomDirEntry->size;
72 fd->ExtInfoEntrySize = RomDirEntry->ExtInfoEntrySize;
73 result = 0;
74 break;
75 }
76
77 fd->ExtInfoOffset += RomDirEntry->ExtInfoEntrySize;
78 offset += (RomDirEntry->size + 0xF) & ~0xF;
80 }
81 } else
82 result = -1;
83
84 return result;
85}
86
87static int GetExtInfoStat(const struct ROMImgStat *ImageStat, struct RomDirFileFd *fd, unsigned char type, void **buffer, unsigned int nbytes)
88{
89 int result;
90 unsigned int offset, BytesToCopy;
91
92 result = ENOENT;
93 offset = 0;
94 while (offset < fd->ExtInfoEntrySize) {
95 struct ExtInfoFieldEntry *ExtInfoEntry = (struct ExtInfoFieldEntry *)((RMIMG_PTRCAST)ImageStat->image + fd->ExtInfoOffset);
96
97 if (ExtInfoEntry->type == EXTINFO_FIELD_TYPE_DATE || ExtInfoEntry->type == EXTINFO_FIELD_TYPE_COMMENT) {
98 if (type == ExtInfoEntry->type) {
99 if (nbytes >= ExtInfoEntry->ExtLength) {
100 BytesToCopy = ExtInfoEntry->ExtLength;
101 result = 0;
102 } else {
103 if (*buffer != NULL) {
104 BytesToCopy = nbytes;
105 } else {
106 *buffer = malloc(ExtInfoEntry->ExtLength);
107 BytesToCopy = ExtInfoEntry->ExtLength;
108 }
109 result = ExtInfoEntry->ExtLength;
110 }
111
112 memcpy(*buffer, &((const unsigned char *)ImageStat->image)[fd->ExtInfoOffset + offset + sizeof(struct ExtInfoFieldEntry)], BytesToCopy);
113 break;
114 }
115
116 offset += (sizeof(struct ExtInfoFieldEntry) + ExtInfoEntry->ExtLength);
117 } else if (ExtInfoEntry->type == EXTINFO_FIELD_TYPE_VERSION) {
118 if (type == ExtInfoEntry->type) {
119 if (nbytes >= sizeof(ExtInfoEntry->value)) {
120 result = 0;
121 memcpy(buffer, &ExtInfoEntry->value, sizeof(ExtInfoEntry->value));
122 break;
123 } else {
124 result = ENOMEM;
125 break;
126 }
127 }
128
129 offset += sizeof(struct ExtInfoFieldEntry);
130 } else if (ExtInfoEntry->type == EXTINFO_FIELD_TYPE_NULL) {
131 result = 0;
132 break;
133 } else {
134 ERROR("Unknown EXTINFO entry type: 0x%02x @ ROM offset: 0x%x, EXTINFO offset: %u\n", ExtInfoEntry->type, fd->ExtInfoOffset + offset, offset);
135 result = EIO;
136 break;
137 }
138 }
139
140 return result;
141}
142
143int CreateBlankROMImg(const char *filename, ROMIMG *ROMImg)
144{
145 unsigned int CommentLength;
146 char LocalhostName[32] = {0}, cwd[PATH_MAX] = {0}, UserName[32] = {0};
147 struct FileEntry *ResetFile;
148 struct ExtInfoFieldEntry *ExtInfoEntry;
149
150 memset(ROMImg, 0, sizeof(ROMIMG));
151
152 ROMImg->date = GetSystemDate();
153#if defined(_WIN32) || defined(WIN32)
154 GetUsername(UserName, sizeof(UserName));
155#else
156 getlogin_r(UserName, sizeof(UserName));
157#endif
158 GetLocalhostName(LocalhostName, sizeof(LocalhostName));
159 GetCurrentWorkingDirectory(cwd, sizeof(cwd));
160 /* Comment format: YYYYMMDD-XXXYYY,conffile,<filename>,<user>@<localhost>/<image path> */
161 CommentLength = IMAGE_COMMENT_BASESIZE + strlen(filename) + sizeof(LocalhostName) + sizeof(UserName) + sizeof(cwd);
162 ROMImg->comment = (char *)malloc( CommentLength+1);
163 if (!ROMImg->comment) return ENOMEM;
164 snprintf(ROMImg->comment, CommentLength, "%08x,conffile,%s,%s@%s/%s", ROMImg->date, filename, UserName, LocalhostName, cwd);
165
166 // Create a blank RESET file.
167 ROMImg->NumFiles = 1;
168 ResetFile = ROMImg->files = (struct FileEntry *)malloc(sizeof(struct FileEntry));
169
170 memset(ResetFile->RomDir.name, 0, sizeof(ResetFile->RomDir.name));
171 strcpy(ResetFile->RomDir.name, "RESET");
172 ResetFile->RomDir.ExtInfoEntrySize = sizeof(ROMImg->date) + sizeof(struct ExtInfoFieldEntry);
173 ResetFile->RomDir.size = 0;
174 ResetFile->FileData = NULL;
175 ResetFile->ExtInfoData = (unsigned char *)malloc(ResetFile->RomDir.ExtInfoEntrySize);
176 ExtInfoEntry = (struct ExtInfoFieldEntry *)ResetFile->ExtInfoData;
177 ExtInfoEntry->value = 0;
178 ExtInfoEntry->ExtLength = sizeof(ROMImg->date);
179 ExtInfoEntry->type = EXTINFO_FIELD_TYPE_DATE;
180 memcpy((void *)((RMIMG_PTRCAST)ResetFile->ExtInfoData + sizeof(struct ExtInfoFieldEntry)), &ROMImg->date, ExtInfoEntry->ExtLength);
181
182 return 0;
183}
184
185int WriteROMImg(const char *file, const ROMIMG *ROMImg)
186{
187 int result;
188 unsigned char *extinfo;
189 struct RomDirEntry ROMDIR_romdir, EXTINFO_romdir, NULL_romdir;
190 unsigned int i, TotalExtInfoSize, ExtInfoOffset, CommentLengthRounded;
191
192 result = 0;
193 ExtInfoOffset = 0;
194 CommentLengthRounded = (strlen(ROMImg->comment) + 1 + 3) & ~3;
195
196 for (i = 0, TotalExtInfoSize = 0; i < ROMImg->NumFiles; i++) {
197 TotalExtInfoSize += ROMImg->files[i].RomDir.ExtInfoEntrySize;
198 if (ROMImg->files[i].RomDir.ExtInfoEntrySize % 4 != 0) {
199 WARNING("ASSERT ROMImg->files[%u].RomDir.ExtInfoEntrySize%%4==0\n", i);
200 abort();
201 }
202 }
203 TotalExtInfoSize += CommentLengthRounded + 2 * sizeof(struct ExtInfoFieldEntry);
204 if ((extinfo = (unsigned char *)malloc(TotalExtInfoSize)) != NULL) {
205 memset(&NULL_romdir, 0, sizeof(NULL_romdir));
206 memset(&ROMDIR_romdir, 0, sizeof(ROMDIR_romdir));
207 memset(&EXTINFO_romdir, 0, sizeof(EXTINFO_romdir));
208
209 // Copy the EXTINFO data for RESET over to the EXTINFO buffer.
210 memcpy(&extinfo[ExtInfoOffset], ROMImg->files[0].ExtInfoData, ROMImg->files[0].RomDir.ExtInfoEntrySize);
211 ExtInfoOffset += ROMImg->files[0].RomDir.ExtInfoEntrySize;
212
213 // Generate the content for the ROMDIR and EXTINFO entries.
214 strcpy(ROMDIR_romdir.name, "ROMDIR");
215 ROMDIR_romdir.size = (ROMImg->NumFiles + 3) * sizeof(struct RomDirEntry); // Number of files (Including RESET) + one ROMDIR and one EXTINFO entries... and one NULL entry.
216 ROMDIR_romdir.ExtInfoEntrySize = sizeof(struct ExtInfoFieldEntry) + CommentLengthRounded;
217 struct ExtInfoFieldEntry *ExtInfoEntry = (struct ExtInfoFieldEntry *)(extinfo + ExtInfoOffset);
218 ExtInfoEntry->value = 0;
219 ExtInfoEntry->ExtLength = CommentLengthRounded;
220 ExtInfoEntry->type = EXTINFO_FIELD_TYPE_COMMENT;
221 memcpy(&extinfo[ExtInfoOffset + sizeof(struct ExtInfoFieldEntry)], ROMImg->comment, ExtInfoEntry->ExtLength);
222 ExtInfoOffset += sizeof(struct ExtInfoFieldEntry) + ExtInfoEntry->ExtLength;
223
224 strcpy(EXTINFO_romdir.name, "EXTINFO");
225 EXTINFO_romdir.size = TotalExtInfoSize;
226 EXTINFO_romdir.ExtInfoEntrySize = 0;
227
228 for (i = 1; i < ROMImg->NumFiles; i++) {
229 if (ExtInfoOffset % 4 != 0) {
230 WARNING("ASSERT: ExtInfoOffset[%u]%%4==0: %u\n", i, ExtInfoOffset);
231 abort();
232 }
233 memcpy(&extinfo[ExtInfoOffset], ROMImg->files[i].ExtInfoData, ROMImg->files[i].RomDir.ExtInfoEntrySize);
234 ExtInfoOffset += ROMImg->files[i].RomDir.ExtInfoEntrySize;
235 }
236
237 FILE *OutputFile;
238 if ((OutputFile = fopen(file, "wb")) != NULL) {
239 int FileAlignMargin;
240 // Write the content of RESET (The bootstrap program, if it exists).
241 fwrite(ROMImg->files[0].FileData, 1, ROMImg->files[0].RomDir.size, OutputFile); // It will be aligned to 16 byte units in size.
242
243 // Write out the ROMDIR entries.
244 fwrite(&ROMImg->files[0].RomDir, sizeof(struct RomDirEntry), 1, OutputFile);
245 fwrite(&ROMDIR_romdir, sizeof(struct RomDirEntry), 1, OutputFile);
246 fwrite(&EXTINFO_romdir, sizeof(struct RomDirEntry), 1, OutputFile);
247 for (i = 1; i < ROMImg->NumFiles; i++) {
248 fwrite(&ROMImg->files[i].RomDir, sizeof(struct RomDirEntry), 1, OutputFile);
249 }
250 fwrite(&NULL_romdir, sizeof(struct RomDirEntry), 1, OutputFile);
251
252 // Write out the EXTINFO section.
253 fwrite(extinfo, 1, TotalExtInfoSize, OutputFile);
254 if ((FileAlignMargin = (ftell(OutputFile) % 16)) > 0)
255 fseek(OutputFile, 16 - FileAlignMargin, SEEK_CUR);
256
257 // Write out the file data, excluding the content of RESET, which was done above.
258 for (i = 1; i < ROMImg->NumFiles; i++) {
259 fwrite(ROMImg->files[i].FileData, 1, ROMImg->files[i].RomDir.size, OutputFile);
260 if ((FileAlignMargin = (ftell(OutputFile) % 16)) > 0)
261 fseek(OutputFile, 16 - FileAlignMargin, SEEK_CUR);
262 }
263
264 fclose(OutputFile);
265 }
266
267 } else
268 result = ENOMEM;
269
270 free(extinfo);
271
272 return result;
273}
274
275int LoadROMImg(ROMIMG *ROMImg, const char *path)
276{
277 FILE *InputFile;
278 int result;
279 unsigned int ExtInfoOffset, DataStartOffset, ScanLimit;
281 struct ROMImgStat ImageStat;
282 struct FileEntry *file;
283 void *ptr;
284 memset(ROMImg, 0, sizeof(ROMIMG));
285
286 if ((InputFile = fopen(path, "rb")) != NULL) {
287 fseek(InputFile, 0, SEEK_END);
288 ImageStat.size = ftell(InputFile);
289 rewind(InputFile);
290
291 if ((ImageStat.image = malloc(ImageStat.size)) != NULL) {
292 if (fread(ImageStat.image, 1, ImageStat.size, InputFile) == ImageStat.size) {
293 DataStartOffset = 0;
294
295 // Scan for the start of the image, which is after the end of the bootstrap program. All regular IOPRP images don't have one (The image begins immediately at the start of the file).
296 unsigned int i;
297 for (i = 0, result = -EIO, ScanLimit = 0x40000 < ImageStat.size ? 0x40000 : ImageStat.size; i < ScanLimit; i++) {
298
299 if (((const char *)ImageStat.image)[i] == 'R' &&
300 ((const char *)ImageStat.image)[i + 1] == 'E' &&
301 ((const char *)ImageStat.image)[i + 2] == 'S' &&
302 ((const char *)ImageStat.image)[i + 3] == 'E' &&
303 ((const char *)ImageStat.image)[i + 4] == 'T') {
304 result = 0;
305 DataStartOffset = i;
306 break;
307 }
308 }
309 if (result == 0) {
310 ImageStat.ROMFS_start = (void *)((RMIMG_PTRCAST)ImageStat.image + DataStartOffset);
311 if (OpenRomDirFile(&ImageStat, "RESET", &RomDirFileFd) != 0) {
312 ERROR(" Unable to locate RESET!\n");
313 free(ImageStat.image);
314 fclose(InputFile);
315 return -1;
316 }
317 if (RomDirFileFd.size != DataStartOffset) {
318 ERROR(" Size of RESET does not match the start of ROMFS!\n");
319 free(ImageStat.image);
320 fclose(InputFile);
321 return -1;
322 }
323 ptr = &ROMImg->date;
324 GetExtInfoStat(&ImageStat, &RomDirFileFd, EXTINFO_FIELD_TYPE_DATE, &ptr, sizeof(ROMImg->date));
325
326 if (OpenRomDirFile(&ImageStat, "ROMDIR", &RomDirFileFd) != 0) {
327 ERROR(" Unable to locate ROMDIR!\n");
328 free(ImageStat.image);
329 fclose(InputFile);
330 return -1;
331 }
332
333 ROMImg->comment = NULL;
334 GetExtInfoStat(&ImageStat, &RomDirFileFd, EXTINFO_FIELD_TYPE_COMMENT, (void **)&ROMImg->comment, 0);
335
336 struct RomDirEntry * RomDir = (struct RomDirEntry *)ImageStat.ROMFS_start;
337 unsigned int offset = 0;
338 ExtInfoOffset = 0;
339 GetRomDirExtInfoOffset(&ImageStat, &RomDirFileFd);
340 while (RomDir->name[0] != '\0') {
341 if (strncmp(RomDir->name, "ROMDIR", sizeof(RomDir->name)) != 0 && strncmp(RomDir->name, "EXTINFO", sizeof(RomDir->name)) != 0) {
342 ROMImg->NumFiles++;
343
344 ROMImg->files = (ROMImg->files == NULL) ? (struct FileEntry *)malloc(sizeof(struct FileEntry)) : (struct FileEntry *)realloc(ROMImg->files, ROMImg->NumFiles * sizeof(struct FileEntry));
345 file = &ROMImg->files[ROMImg->NumFiles - 1];
346
347 memcpy(&file->RomDir, RomDir, sizeof(struct RomDirEntry));
348 file->ExtInfoData = (unsigned char *)malloc(RomDir->ExtInfoEntrySize);
349 memcpy(file->ExtInfoData, (void *)((RMIMG_PTRCAST)ImageStat.image + RomDirFileFd.ExtInfoOffset + ExtInfoOffset), RomDir->ExtInfoEntrySize);
350 file->FileData = malloc(RomDir->size);
351 memcpy(file->FileData, (void *)((RMIMG_PTRCAST)ImageStat.image + offset), RomDir->size);
352 }
353
354 offset += (RomDir->size + 0xF) & ~0xF;
355 ExtInfoOffset += RomDir->ExtInfoEntrySize;
356 RomDir++;
357 }
358 } else {
359 WARNING("Could not locate RESET file, aborting...\n");
360 result = EINVAL;
361 }
362 } else {
363 ERROR("failed to read %u bytes\n", ImageStat.size);
364 result = EIO;
365 }
366
367 free(ImageStat.image);
368 } else {
369 ERROR("failed to malloc %u bytes\n", ImageStat.size);
370 result = ENOMEM;
371 }
372
373 fclose(InputFile);
374 } else {
375 ERROR("cant open '%s'\n", path);
376 result = ENOENT;
377 }
378
379 return result;
380}
381
382void UnloadROMImg(ROMIMG *ROMImg)
383{
384 DPRINTF("start...\n");
385
386 if (ROMImg->comment != NULL) {
387 free(ROMImg->comment);
388 }
389 if (ROMImg->files != NULL) {
390 unsigned int i;
391 for (i = 0; i < ROMImg->NumFiles; i++) {
392 if (ROMImg->files[i].ExtInfoData != NULL)
393 free(ROMImg->files[i].ExtInfoData);
394 if (ROMImg->files[i].FileData != NULL)
395 free(ROMImg->files[i].FileData);
396 }
397
398 free(ROMImg->files);
399 }
400
401 memset(ROMImg, 0, sizeof(ROMIMG));
402}
403
404static void *ReallocExtInfoArea(struct FileEntry *file, unsigned short int nbytes)
405{
406 return (file->ExtInfoData = (file->ExtInfoData == NULL) ? (unsigned char *)malloc(nbytes + sizeof(struct ExtInfoFieldEntry)) : (unsigned char *)realloc(file->ExtInfoData, file->RomDir.ExtInfoEntrySize + nbytes + sizeof(struct ExtInfoFieldEntry)));
407}
408
409static int AddExtInfoStat(struct FileEntry *file, unsigned char type, void *data, unsigned char nbytes)
410{
411 int result;
412 struct ExtInfoFieldEntry *ExtInfo;
413 switch (type) {
414 case EXTINFO_FIELD_TYPE_DATE:
415 case EXTINFO_FIELD_TYPE_COMMENT:
416 if (type != EXTINFO_FIELD_TYPE_DATE || (type == EXTINFO_FIELD_TYPE_DATE && nbytes == 4)) {
417 if (ReallocExtInfoArea(file, nbytes) != NULL) {
418 ExtInfo = (struct ExtInfoFieldEntry *)(file->ExtInfoData + file->RomDir.ExtInfoEntrySize);
419 ExtInfo->value = 0;
420 ExtInfo->ExtLength = (nbytes + 0x3) & ~0x3;
421 ExtInfo->type = type;
422 memcpy(file->ExtInfoData + file->RomDir.ExtInfoEntrySize + sizeof(struct ExtInfoFieldEntry), data, nbytes);
423
424 file->RomDir.ExtInfoEntrySize += ExtInfo->ExtLength + sizeof(struct ExtInfoFieldEntry);
425
426 result = 0;
427 } else
428 result = ENOMEM;
429 } else
430 result = EINVAL;
431 break;
432 case EXTINFO_FIELD_TYPE_VERSION:
433 if (nbytes == 2) {
434 if (ReallocExtInfoArea(file, 0) != NULL) {
435 ExtInfo = (struct ExtInfoFieldEntry *)(file->ExtInfoData + file->RomDir.ExtInfoEntrySize);
436 ExtInfo->value = *(unsigned short int *)data;
437 ExtInfo->ExtLength = 0;
438 ExtInfo->type = type;
439
440 file->RomDir.ExtInfoEntrySize += sizeof(struct ExtInfoFieldEntry);
441
442 result = 0;
443 } else
444 result = ENOMEM;
445 } else
446 result = EINVAL;
447 break;
448 default:
449 result = EINVAL;
450 }
451
452 return result;
453}
454
455int AddFile(ROMIMG *ROMImg, const char *path, int upperconv)
456{
457 char tbuf[9] = "\0"; // we dont need a large buf, this is for filling in the filename on ROMFS
458 FILE *InputFile;
459 int result;
460 unsigned int FileDateStamp;
461 unsigned short FileVersion;
462 if ((InputFile = fopen(path, "rb")) != NULL) {
463 const char* fname = strrchr(path, PATHSEP);
464 if (fname == NULL) fname = path; else fname++;
465 if (upperconv) {
466 strncpy(tbuf, fname, sizeof(tbuf));
467 tbuf[sizeof(tbuf) - 1] = '\0';
468 if (tbuf[0] != '\0') {
469 upperbuff(tbuf);
470 fname = tbuf;
471 char* T = strrchr(fname, '.');
472 if (T != NULL) *T = '\0'; //null terminate extension
473 }
474 }
475 int size;
476 fseek(InputFile, 0, SEEK_END);
477 size = ftell(InputFile);
478 rewind(InputFile);
479
480 struct FileEntry *file;
481 // Files cannot exist more than once in an image. The RESET entry is special here because all images will have a RESET entry, but it might be empty (If it has no content, allow the user to add in content).
482 if (strcmp(fname, "RESET")) {
483 if (!IsFileExists(ROMImg, fname)) {
484 ROMImg->NumFiles++;
485
486 if ((ROMImg->files = (ROMImg->files == NULL) ? (struct FileEntry *)malloc(sizeof(struct FileEntry)) : (struct FileEntry *)realloc(ROMImg->files, ROMImg->NumFiles * sizeof(struct FileEntry))) != NULL) {
487 file = &ROMImg->files[ROMImg->NumFiles - 1];
488 memset(&ROMImg->files[ROMImg->NumFiles - 1], 0, sizeof(struct FileEntry));
489
490 strncpy(file->RomDir.name, fname, sizeof(file->RomDir.name));
491 file->RomDir.name[sizeof(file->RomDir.name) - 1] = '\0';
492 file->RomDir.ExtInfoEntrySize = 0;
493
494 FileDateStamp = GetFileCreationDate(path);
495 AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_DATE, &FileDateStamp, 4);
496
497 if (IsSonyRXModule(path)) {
498 char ModuleDescription[32];
499 if ((result = GetSonyRXModInfo(path, ModuleDescription, sizeof(ModuleDescription), &FileVersion)) == 0) {
500 AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_VERSION, &FileVersion, 2);
501 AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_COMMENT, ModuleDescription, strlen(ModuleDescription) + 1);
502 }
503 } else
504 result = 0;
505
506 if (result == 0) {
507 file->RomDir.size = size;
508 file->FileData = malloc(size);
509 if (fread(file->FileData, 1, size, InputFile) != size) {
510 ERROR("failed to read %d bytes\n", size);
511 result = EIO;
512 }
513 }
514 } else
515 result = ENOMEM;
516 } else
517 result = EEXIST;
518 } else {
519 if (ROMImg->files[0].RomDir.size < 1) {
520 file = &ROMImg->files[0];
521 file->RomDir.size = size;
522 file->FileData = malloc(size);
523 if (fread(file->FileData, 1, size, InputFile) != file->RomDir.size) {
524 ERROR("failed to read %u bytes\n", file->RomDir.size);
525 result = EIO;
526 } else
527 result = 0;
528 } else
529 result = EEXIST;
530 }
531
532 fclose(InputFile);
533 } else
534 result = ENOENT;
535
536 return result;
537}
538
539int DeleteFile(ROMIMG *ROMImg, const char *filename)
540{
541 int result;
542 struct FileEntry *file;
543
544 // The RESET entry cannot be deleted, but its content will be.
545 if (strcmp("RESET", filename)) {
546 unsigned int i;
547 for (result = ENOENT, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
548 if (strncmp(file->RomDir.name, filename, sizeof(file->RomDir.name)) == 0) {
549 if (file->FileData != NULL)
550 free(file->FileData);
551
552 if (file->ExtInfoData != NULL)
553 free(file->ExtInfoData);
554 for (; i < ROMImg->NumFiles; i++)
555 memcpy(&ROMImg->files[i], &ROMImg->files[i + 1], sizeof(struct FileEntry));
556 ROMImg->files = (struct FileEntry *)realloc(ROMImg->files, (--ROMImg->NumFiles) * sizeof(struct FileEntry));
557 result = 0;
558 break;
559 }
560 }
561 } else {
562 file = &ROMImg->files[0];
563 if (file->RomDir.size > 0) {
564 file->FileData = NULL;
565 file->RomDir.size = 0;
566 result = 0;
567 } else
568 result = ENOENT;
569 }
570
571 return result;
572}
573
574int ExtractFile(const ROMIMG *ROMImg, const char *filename, const char *FileToExtract)
575{
576 int result;
577 unsigned int i;
578 FILE *OutputFile;
579 const struct FileEntry *file;
580
581 for (result = ENOENT, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
582 if (strncmp(file->RomDir.name, FileToExtract, sizeof(file->RomDir.name)) == 0) {
583 if ((OutputFile = fopen(filename, "wb")) != NULL) {
584 result = (fwrite(file->FileData, 1, file->RomDir.size, OutputFile) == file->RomDir.size) ? 0 : EIO;
585 fclose(OutputFile);
586 } else
587 result = EIO;
588 break;
589 }
590 }
591
592 return result;
593}
594
595int IsFileExists(const ROMIMG *ROMImg, const char *filename)
596{
597 int result;
598 unsigned int i;
599 const struct FileEntry *file;
600
601 for (result = 0, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
602 if (strncmp(file->RomDir.name, filename, sizeof(file->RomDir.name)) == 0) {
603 result = 1;
604 break;
605 }
606 }
607
608 return result;
609}
#define ENOENT
Definition errno.h:23
#define EEXIST
Definition errno.h:53
#define EINVAL
Definition errno.h:63
#define ENOMEM
Definition errno.h:43
#define EIO
Definition errno.h:29
Definition romdrv.h:55
Definition romimg.h:52
Definition romdrv.h:40