#include "rsb-lz.h"
#include "extract.h"
-void extract_files(unsigned char *fw, int len)
+struct file_entry* get_next_file(unsigned char *fw, int len)
{
- unsigned char *pos;
- unsigned int content_length;
- unsigned int name_length;
- unsigned char unknown;
- char *name;
-
- pos = fw + 0x28;
- printf("Start of filesystem: 0x%08x\n", *((unsigned int*)pos));
-
- pos = fw + *((unsigned int*)pos);
-
- while (pos < (fw + len)) {
- unknown = *pos; pos++;
- name_length = *((unsigned int*)pos);
- pos += 4;
- content_length = *((unsigned int*)pos);
- pos += 4;
- name = (char*)pos;
-
- if (((pos + content_length) > (fw + len)) ||
- ((pos + name_length) > (fw + len))) {
- printf("EOF reached\n");
- break;
+ static unsigned char *pos;
+ static unsigned char *start;
+ static unsigned char *end;
+ static struct file_entry fent;
+ int name_length;
+
+ if (fw != NULL && len != 0) {
+ pos = fw + 0x28;
+
+#if 0
+ printf("Start of filesystem: 0x%08x\n", *((unsigned int*)pos));
+#endif
+ start = fw;
+ pos = fw + *((unsigned int*)pos);
+ end = fw + len;
+ }
+
+ fent.unknown = *pos;
+ pos++;
+
+ if (fent.unknown == 0x00) {
+ /* EOF */
+ int fill = (4 - ((pos - start) % 4)) % 4;
+ int i;
+
+ for (i = 0; i < fill; i++) {
+ if (*pos != 0xff) {
+ fprintf(stderr, "Wrong fill byte after EOF: 0x%02x, aborting!\n", *pos);
+ exit(1);
+ }
+ pos++;
}
- pos += name_length;
+ if (pos != end) {
+ fprintf(stderr, "EOF marker not at end-of-file %p <-> %p, aborting!\n", pos, end);
+ exit(1);
+ }
+
+ return NULL;
+ }
+
+
+ name_length = *((unsigned int*)pos);
+ pos += 4;
+
+ fent.length = *((unsigned int*)pos);
+ pos += 4;
+
+ if ((fent.length > (end - pos)) ||
+ (name_length > (end - pos))) {
+ printf("EOF reached without hitting EOF marker, aborting "
+ "(unknown: 0x%02x, namelen: 0x%08x, contentlen: 0x%08x!\n",
+ fent.unknown, name_length, fent.length);
+ exit(1);
+ }
+
+ fent.name = (char*)pos;
+ pos += name_length;
+
+ fent.start = pos;
+ pos += fent.length;
+
+ return &fent;
+}
+
+void extract_files(unsigned char *fw, int len)
+{
+ struct file_entry *fent;
+
+ fent = get_next_file(fw, len);
+
+ while (fent) {
printf("%s: unknown: 0x%02x, length: %d",
- name, unknown, content_length);
+ fent->name, fent->unknown, fent->length);
- if (content_length > 0) {
- write_file(name, pos, content_length);
- if (*((unsigned int*)pos) == LZ_MAGIC) {
+ if (fent->length > 0) {
+ write_file(fent->name, fent->start, fent->length);
+ if (*((unsigned int*)fent->start) == LZ_MAGIC) {
char *lzname;
- if ((lzname = strdup(name)) == NULL) {
+ if ((lzname = strdup(fent->name)) == NULL) {
perror("strdup");
exit(1);
}
printf("%s: packed file found", lzname);
- extract_lz_file(pos, (unsigned char*)lzname);
+ extract_lz_file(fent->start, (unsigned char*)lzname);
free(lzname);
- } else if (!strcmp(name, "firmware")) {
+ } else if (!strcmp(fent->name, "firmware")) {
unsigned char *lzpos;
char lzname[128];
bzero(lzname, sizeof(lzname));
strcpy(lzname, "firmware.");
- lzpos = pos + *((unsigned int*)(pos + 0x20));
+ lzpos = fent->start + *((unsigned int*)(fent->start + 0x20));
memcpy(lzname + strlen(lzname), lzpos - 4, 4);
lzpos += 4;
if (*((unsigned int*)(lzpos)) == LZ_MAGIC) {
extract_lz_file(lzpos, (unsigned char*)lzname);
}
}
+ } else {
+ printf(", ignoring...\n");
}
-
- pos += content_length;
-
+ fent = get_next_file(NULL, 0);
}
}