?? grf.c
字號:
grf->files = (GrfFile *) calloc (sizeof (GrfFile), grf->nfiles); for (entry = 0, index = 0, offset = 0; entry < filelist_entries; entry++) { unsigned long ofs2; int type; ofs2 = offset + getlong (filelist_data + offset) + 4; type = filelist_data[ofs2 + 12]; /* Type 0 is a directory index; skip that */ if (type != 0) { unsigned char *name; /* Filename */ unsigned long compressed_len; /* Compressed file size */ unsigned long compressed_len_aligned; /* Not sure what this is but it's used for decoding the data */ unsigned long real_len; /* Real (uncompressed) file size */ unsigned long pos; /* Position of the real file data */ long cycle; char *ext; name = decode_filename (filelist_data + offset + 6, filelist_data[offset] - 6); compressed_len_aligned = getlong (filelist_data + ofs2 + 4) - 37579; real_len = getlong (filelist_data + ofs2 + 8); pos = getlong (filelist_data + ofs2 + 13) + 46; /* Detect the file's "cycle". This contains information about how the file entry's encoded */ compressed_len = 0; cycle = 0; /* Only files with an extension are encoded */ if ((ext = strrchr ((const char *) name, '.')) != NULL) { compressed_len = getlong (filelist_data + ofs2) - getlong (filelist_data + ofs2 + 8) - 715; if (strcasecmp (ext, ".gnd") != 0 && strcasecmp (ext, ".gat") != 0 && strcasecmp (ext, ".act") != 0 && strcasecmp (ext, ".str") != 0) { unsigned long i; for (i = 10, cycle = 1; compressed_len >= i; i *= 10, cycle++); } } grf->files[index].name = strdup ((const char *) name); grf->files[index].compressed_len = compressed_len; grf->files[index].compressed_len_aligned = compressed_len_aligned; grf->files[index].real_len = real_len; grf->files[index].pos = pos; grf->files[index].cycle = cycle; grf->files[index].type = type; index++; } offset = ofs2 + 17; } free (filelist_data); } else if (grf->version == 2) { /* The file list header contains two sections: 1. Information about the number of files and how big the file list data is. 2. The actual file list itself (compressed). */ unsigned char size_header[8]; /* The header that contains information about sizes */ uLongf compressed_size; /* Size of the compressed file list data */ uLongf decompressed_size; /* Size of the decompressed file list data */ unsigned char *rBuf; /* Temporarily store the compress file list data */ unsigned char *filelist_data; /* The decompressed file list data */ unsigned long entry; int offset; /* Get size information */ fread (size_header, 1, 8, f); compressed_size = getlong (size_header); decompressed_size = getlong (size_header + 4); debug ("File header compressed:\t\t%ld bytes\n" "File header decompressed:\t%ld bytes\n", compressed_size, decompressed_size); if (compressed_size > (uLongf) (grf_size - ftell (f))) { fclose (f); if (error) *error = GE_CORRUPTED; free (grf); return NULL; } /* Allocate a buffer to store the raw (compressed) file list data */ rBuf = (unsigned char *) malloc (compressed_size); if (!rBuf) { fclose (f); if (error) *error = GE_NOMEM; free (grf); return NULL; } fread (rBuf, 1, compressed_size, f); /* Allocate a buffer to store the decompressed file list data */ filelist_data = (unsigned char *) malloc (decompressed_size); if (!filelist_data) { free (rBuf); free (filelist_data); fclose (f); if (error) *error = GE_NOMEM; free (grf); return NULL; } /* Decompress the file list data */ decode_zip (filelist_data, &decompressed_size, rBuf, compressed_size); free (rBuf); /* Store the entire file list into an array */ grf->nfiles = getlong (grf_header + 0x26) - 7; debug ("nfiles: %ld\n" "Allocating %d bytes of memory for file list structure.\n", grf->nfiles, sizeof (GrfFile) * grf->nfiles); grf->files = (GrfFile *) calloc (sizeof (GrfFile), grf->nfiles); if (!grf->files) { free (filelist_data); fclose (f); free (grf); if (error) *error = GE_NOMEM; return NULL; } debug ("Reading file list...\n"); for (entry = 0, offset = 0; entry < grf->nfiles; entry++){ char *name; /* This entry's filename */ int type; int ofs2; name = strdup ((char *) (filelist_data + offset)); ofs2 = offset + strlen (name) + 1; type = filelist_data[ofs2 + 12]; if (type == 1 || type == 3 || type == 5) { unsigned long compressed_len; /* Compressed file size */ unsigned long compressed_len_aligned; /* Not sure what this is but it's used for decoding the data */ unsigned long real_len; /* Real (uncompressed) file size */ unsigned long pos; /* Position of the real file data */ long cycle; compressed_len = getlong (filelist_data + ofs2); compressed_len_aligned = getlong (filelist_data + ofs2 + 4); real_len = getlong (filelist_data + ofs2 + 8); pos = getlong (filelist_data + ofs2 + 13) + 0x2e; /* Detect the file's "cycle". This contains information about how the file entry's encoded */ if (type == 3) { unsigned long i; for (i = 10, cycle = 1; compressed_len >= i; i *= 10, cycle++); } else if (type == 5) { cycle = 0; } else { /* if (type == 1) */ cycle = -1; } grf->files[entry].compressed_len = compressed_len; grf->files[entry].compressed_len_aligned = compressed_len_aligned; grf->files[entry].real_len = real_len; grf->files[entry].pos = pos; grf->files[entry].cycle = cycle; } grf->files[entry].name = name; grf->files[entry].type = type; /* Calculate next entry's offset */ offset += strlen ((char *) (filelist_data + offset)) + 18; } free (filelist_data); debug ("Done!\n"); } else { if (error) *error = GE_NSUP; free (grf); fclose (f); return NULL; } grf->filename = strdup (fname); return grf;}GRFEXPORT GrfFile *grf_find (Grf *grf, char *fname, unsigned long *index){ unsigned long i; if (!grf || !fname) return NULL; for (i = 0; i < grf->nfiles; i++) { if (strcmp (grf->files[i].name, fname) == 0) { if (index) *index = i; return &(grf->files[i]); } } return NULL;}GRFEXPORT void *grf_get (Grf *grf, char *fname, unsigned long *size, GrfError *error){ unsigned long index; if (!grf || !fname) { if (error) *error = GE_BADARGS; return NULL; } if (!grf_find (grf, fname, &index)) { if (error) *error = GE_NOTFOUND; return NULL; } return grf_index_get (grf, index, size, error);}GRFEXPORT void *grf_index_get (Grf *grf, unsigned long index, unsigned long *size, GrfError *error){ GrfFile *file; unsigned char *buf, *decbuf; if (!grf) { if (error) *error = GE_BADARGS; return NULL; } if (index < 0 || index >= grf->nfiles) { if (error) *error = GE_INDEX; return NULL; } file = &(grf->files[index]); buf = (unsigned char *) calloc (file->compressed_len_aligned + 1024, 1); if (!buf) { if (error) *error = GE_NOMEM; return NULL; } fseek (grf->f, file->pos, SEEK_SET); fread (buf, 1, file->compressed_len_aligned, grf->f); if (file->type == 1 || file->type == 3 || file->type == 5) { uLongf len; decbuf = (unsigned char *) calloc (file->real_len + 1024, 1); /* Some data are encoded. They must be decoded first before they can be decompressed. */ if (file->cycle >= 0) { decode_des_etc (buf, file->compressed_len_aligned, file->cycle == 0, file->cycle); } /* Now, decompress the data and return it */ len = file->real_len; decode_zip (decbuf, &len, buf, file->compressed_len); if (size) *size = len; if (len != file->real_len) { fprintf (stderr, "decode_zip size miss match err: %ld != %ld\n", len, file->real_len); } free (buf); } else decbuf = buf; return decbuf;}GRFEXPORT intgrf_extract (Grf *grf, char *fname, const char *writeToFile, GrfError *error){ unsigned long index; if (!grf || !fname) { if (error) *error = GE_BADARGS; return 0; } if (!grf_find (grf, fname, &index)) { if (error) *error = GE_NOTFOUND; return 0; } return grf_index_extract (grf, index, writeToFile, error);}GRFEXPORT intgrf_index_extract (Grf *grf, unsigned long index, const char *writeToFile, GrfError *error){ void *buf; unsigned long size; FILE *f; if (!writeToFile) { if (error) *error = GE_BADARGS; return 0; } buf = grf_index_get (grf, index, &size, error); if (!buf) return 0; f = fopen (writeToFile, "wb"); if (!f) { free (buf); if (error) *error = GE_WRITE; return 0; } fwrite (buf, size, 1, f); fclose (f); free (buf); return 1;}GRFEXPORT voidgrf_free (Grf *grf){ unsigned long i; if (!grf) return; if (grf->f) fclose (grf->f); if (grf->filename) free (grf->filename); if (grf->files) { for (i = 0; i < grf->nfiles; i++) { if (grf->files[i].name) free (grf->files[i].name); } free (grf->files); } free (grf);}GRFEXPORT const char *grf_strerror (GrfError error){ switch (error) { case GE_BADARGS: return "Bad arguments passed to function."; case GE_CANTOPEN: return "Cannot open file."; case GE_INVALID: return "Not a valid GRF archive."; case GE_CORRUPTED: return "The GRF archive appears to be corrupted."; case GE_NOMEM: return "Not enough free memory."; case GE_NSUP: return "GRF archives of this version is not supported."; case GE_NOTFOUND: return "File not found inside GRF file."; case GE_INDEX: return "Invalid index."; case GE_WRITE: return "Cannot write to destination file."; default: return "Unknown error."; };}#ifdef __cplusplus }#endif /* __cplusplus */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -