PS2SDK
PS2 Homebrew Libraries
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 
18 struct ROMImgStat
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 
34 static 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;
51  RomDirEntry++;
52  }
53 
54  return result;
55 }
56 
57 static 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;
79  RomDirEntry++;
80  }
81  } else
82  result = -1;
83 
84  return result;
85 }
86 
87 static 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 
143 int 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 
185 int 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 
275 int LoadROMImg(ROMIMG *ROMImg, const char *path)
276 {
277  FILE *InputFile;
278  int result;
279  unsigned int ExtInfoOffset, DataStartOffset, ScanLimit;
280  struct RomDirFileFd RomDirFileFd;
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 
382 void 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 
404 static 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 
409 static 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 
455 int 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  snprintf(tbuf, sizeof(tbuf), "%s", fname);
467  if (tbuf[0] != '\0') {
468  upperbuff(tbuf);
469  char* T = strrchr(tbuf, '.');
470  if (T != NULL) *T = '\0'; //null terminate extension
471  fname = tbuf;
472  }
473  }
474  int size;
475  fseek(InputFile, 0, SEEK_END);
476  size = ftell(InputFile);
477  rewind(InputFile);
478 
479  struct FileEntry *file;
480  // 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).
481  if (strcmp(fname, "RESET")) {
482  if (!IsFileExists(ROMImg, fname)) {
483  ROMImg->NumFiles++;
484 
485  if ((ROMImg->files = (ROMImg->files == NULL) ? (struct FileEntry *)malloc(sizeof(struct FileEntry)) : (struct FileEntry *)realloc(ROMImg->files, ROMImg->NumFiles * sizeof(struct FileEntry))) != NULL) {
486  file = &ROMImg->files[ROMImg->NumFiles - 1];
487  memset(&ROMImg->files[ROMImg->NumFiles - 1], 0, sizeof(struct FileEntry));
488 
489  snprintf(file->RomDir.name, sizeof(file->RomDir.name), "%s", fname);
490  file->RomDir.ExtInfoEntrySize = 0;
491 
492  FileDateStamp = GetFileCreationDate(path);
493  AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_DATE, &FileDateStamp, 4);
494 
495  if (IsSonyRXModule(path)) {
496  char ModuleDescription[32];
497  if ((result = GetSonyRXModInfo(path, ModuleDescription, sizeof(ModuleDescription), &FileVersion)) == 0) {
498  AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_VERSION, &FileVersion, 2);
499  AddExtInfoStat(&ROMImg->files[ROMImg->NumFiles - 1], EXTINFO_FIELD_TYPE_COMMENT, ModuleDescription, strlen(ModuleDescription) + 1);
500  }
501  } else
502  result = 0;
503 
504  if (result == 0) {
505  file->RomDir.size = size;
506  file->FileData = malloc(size);
507  if (fread(file->FileData, 1, size, InputFile) != size) {
508  ERROR("failed to read %d bytes\n", size);
509  result = EIO;
510  }
511  }
512  } else
513  result = ENOMEM;
514  } else
515  result = EEXIST;
516  } else {
517  if (ROMImg->files[0].RomDir.size < 1) {
518  file = &ROMImg->files[0];
519  file->RomDir.size = size;
520  file->FileData = malloc(size);
521  if (fread(file->FileData, 1, size, InputFile) != file->RomDir.size) {
522  ERROR("failed to read %u bytes\n", file->RomDir.size);
523  result = EIO;
524  } else
525  result = 0;
526  } else
527  result = EEXIST;
528  }
529 
530  fclose(InputFile);
531  } else
532  result = ENOENT;
533 
534  return result;
535 }
536 
537 int DeleteFile(ROMIMG *ROMImg, const char *filename)
538 {
539  int result;
540  struct FileEntry *file;
541 
542  // The RESET entry cannot be deleted, but its content will be.
543  if (strcmp("RESET", filename)) {
544  unsigned int i;
545  for (result = ENOENT, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
546  if (strncmp(file->RomDir.name, filename, sizeof(file->RomDir.name)) == 0) {
547  if (file->FileData != NULL)
548  free(file->FileData);
549 
550  if (file->ExtInfoData != NULL)
551  free(file->ExtInfoData);
552  for (; i < ROMImg->NumFiles; i++)
553  memcpy(&ROMImg->files[i], &ROMImg->files[i + 1], sizeof(struct FileEntry));
554  ROMImg->files = (struct FileEntry *)realloc(ROMImg->files, (--ROMImg->NumFiles) * sizeof(struct FileEntry));
555  result = 0;
556  break;
557  }
558  }
559  } else {
560  file = &ROMImg->files[0];
561  if (file->RomDir.size > 0) {
562  file->FileData = NULL;
563  file->RomDir.size = 0;
564  result = 0;
565  } else
566  result = ENOENT;
567  }
568 
569  return result;
570 }
571 
572 int ExtractFile(const ROMIMG *ROMImg, const char *filename, const char *FileToExtract)
573 {
574  int result;
575  unsigned int i;
576  FILE *OutputFile;
577  const struct FileEntry *file;
578 
579  for (result = ENOENT, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
580  if (strncmp(file->RomDir.name, FileToExtract, sizeof(file->RomDir.name)) == 0) {
581  if ((OutputFile = fopen(filename, "wb")) != NULL) {
582  result = (fwrite(file->FileData, 1, file->RomDir.size, OutputFile) == file->RomDir.size) ? 0 : EIO;
583  fclose(OutputFile);
584  } else
585  result = EIO;
586  break;
587  }
588  }
589 
590  return result;
591 }
592 
593 int IsFileExists(const ROMIMG *ROMImg, const char *filename)
594 {
595  int result;
596  unsigned int i;
597  const struct FileEntry *file;
598 
599  for (result = 0, i = 0, file = ROMImg->files; i < ROMImg->NumFiles; i++, file++) {
600  if (strncmp(file->RomDir.name, filename, sizeof(file->RomDir.name)) == 0) {
601  result = 1;
602  break;
603  }
604  }
605 
606  return result;
607 }
RomDirEntry
Definition: romdrv.h:39
ENOMEM
#define ENOMEM
Definition: errno.h:43
ExtInfoFieldEntry
Definition: romdrv.h:54
EIO
#define EIO
Definition: errno.h:29
FileEntry
Definition: romimg.h:50
ENOENT
#define ENOENT
Definition: errno.h:23
stdio.h
EEXIST
#define EEXIST
Definition: errno.h:53
ROMImgStat
Definition: romimg.c:18
EINVAL
#define EINVAL
Definition: errno.h:63
RomDirFileFd
Definition: romimg.c:25
ImageStructure
Definition: romimg.h:57
stdlib.h
errno.h