221 lines
4.7 KiB
C
221 lines
4.7 KiB
C
#include "skip.h"
|
|
|
|
#include "error.h"
|
|
#include "file.h"
|
|
#include "str.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
struct sw_skip *sw_skip_self;
|
|
|
|
struct sw_skip *sw_skip_create() {
|
|
struct sw_skip *skip;
|
|
|
|
skip = calloc(1, sizeof(struct sw_skip));
|
|
|
|
return skip;
|
|
}
|
|
|
|
struct sw_skip *sw_skip_load(char *filename) {
|
|
FILE *fil;
|
|
struct sw_skip *skip;
|
|
char magic[5] = {0};
|
|
u8 version, compression;
|
|
u16 i;
|
|
char str[257];
|
|
u8 str_len;
|
|
u32 off;
|
|
|
|
skip = sw_skip_create();
|
|
fil = fopen(filename, "rb");
|
|
fseek(fil, -4, SEEK_END);
|
|
fread(&off, 4, 1, fil);
|
|
fseek(fil, -off, SEEK_END);
|
|
|
|
fread(magic, 1, 4, fil);
|
|
if(strcmp("SWZP", magic) != 0) {
|
|
sw_log("not a .skip file");
|
|
return 0;
|
|
}
|
|
|
|
fread(&version, 1, 1, fil);
|
|
if(version > 0) {
|
|
sw_error("version %i of .skip not supported", version);
|
|
}
|
|
|
|
fread(&compression, 1, 1, fil);
|
|
if(compression > 0) {
|
|
sw_error("unsupported .skip compression method");
|
|
}
|
|
|
|
fread(&skip->data_size, 1, 4, fil);
|
|
fseek(fil, 4, SEEK_CUR); /* ignore compressed size */
|
|
fread(&skip->file_count, 1, 2, fil);
|
|
|
|
skip->files = malloc(sizeof(skip->files[0]) * skip->file_count);
|
|
|
|
for(i = 0; i < skip->file_count; ++i) {
|
|
memset(str, 0, 257);
|
|
fread(&skip->files[i].offset, 1, 4, fil);
|
|
fread(&skip->files[i].size, 1, 4, fil);
|
|
fread(&str_len, 1, 1, fil);
|
|
fread(str, str_len, 1, fil);
|
|
str[str_len] = 0;
|
|
|
|
skip->files[i].name = malloc(str_len + 1);
|
|
strcpy(skip->files[i].name, str);
|
|
}
|
|
|
|
skip->data = malloc(skip->data_size);
|
|
fread(skip->data, 1, skip->data_size, fil);
|
|
|
|
fclose(fil);
|
|
return skip;
|
|
}
|
|
|
|
static void sw_skip_save_to(struct sw_skip *skip, FILE *fil);
|
|
|
|
void sw_skip_destroy(struct sw_skip *skip) {
|
|
i32 i;
|
|
|
|
for(i = 0; i < skip->file_count; ++i) {
|
|
free(skip->files[i].name);
|
|
}
|
|
free(skip->files);
|
|
free(skip->data);
|
|
free(skip);
|
|
}
|
|
|
|
void sw_skip_add(struct sw_skip *skip, u8 *data, u32 data_size, char *name) {
|
|
u32 off;
|
|
|
|
off = skip->data_size;
|
|
|
|
skip->data_size += data_size;
|
|
skip->data = realloc(skip->data, skip->data_size);
|
|
memcpy(skip->data + off, data, data_size);
|
|
|
|
skip->file_count += 1;
|
|
skip->files =
|
|
realloc(skip->files, sizeof(skip->files[0]) * skip->file_count);
|
|
skip->files[skip->file_count - 1].name = sw_str_dup(name);
|
|
skip->files[skip->file_count - 1].offset = off;
|
|
skip->files[skip->file_count - 1].size = data_size;
|
|
}
|
|
|
|
void sw_skip_add_file(struct sw_skip *skip, char *name, char *filename) {
|
|
FILE *fil;
|
|
u32 len;
|
|
u8 *data;
|
|
|
|
fil = fopen(filename, "rb");
|
|
fseek(fil, 0, SEEK_END);
|
|
len = ftell(fil);
|
|
fseek(fil, 0, SEEK_SET);
|
|
|
|
data = malloc(len);
|
|
fread(data, 1, len, fil);
|
|
fclose(fil);
|
|
|
|
sw_skip_add(skip, data, len, name);
|
|
|
|
free(data);
|
|
}
|
|
|
|
void sw_skip_attach(struct sw_skip *skip, char *filename) {
|
|
FILE *fil;
|
|
|
|
fil = fopen(filename, "rb+");
|
|
fseek(fil, 0, SEEK_END);
|
|
sw_skip_save_to(skip, fil);
|
|
}
|
|
|
|
void sw_skip_dettach(char *filename) {
|
|
FILE *fil;
|
|
char magic[5] = {0};
|
|
u32 off;
|
|
u32 len;
|
|
u8 *data;
|
|
|
|
fil = fopen(filename, "rb");
|
|
fseek(fil, -4, SEEK_END);
|
|
fread(&off, 4, 1, fil);
|
|
fseek(fil, -off, SEEK_END);
|
|
|
|
fread(magic, 1, 4, fil);
|
|
sw_log("magic: [%s]", magic);
|
|
sw_log("off: %i", off);
|
|
if(strcmp("SWZP", magic) == 0) {
|
|
sw_log("detaching .skip from %s", filename);
|
|
len = ftell(fil) - 4;
|
|
fseek(fil, 0, SEEK_SET);
|
|
data = malloc(len);
|
|
fread(data, 1, len, fil);
|
|
fclose(fil);
|
|
fil = fopen(filename, "wb");
|
|
fwrite(data, 1, len, fil);
|
|
}
|
|
fclose(fil);
|
|
}
|
|
|
|
u8 *sw_skip_get(struct sw_skip *skip, char *name, u32 *out_size) {
|
|
u32 i;
|
|
|
|
for(i = 0; i < skip->file_count; ++i) {
|
|
if(strcmp(name, skip->files[i].name) == 0) {
|
|
if(out_size) {
|
|
*out_size = skip->files[i].size;
|
|
}
|
|
return skip->data + skip->files[i].offset;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *sw_skip_get_string(struct sw_skip *skip, char *name) {
|
|
u8 *data;
|
|
u32 size;
|
|
char *str;
|
|
|
|
data = sw_skip_get(skip, name, &size);
|
|
if(data == 0) {
|
|
return 0;
|
|
}
|
|
|
|
str = malloc(size + 1);
|
|
memcpy(str, data, size);
|
|
str[size] = 0;
|
|
|
|
return str;
|
|
}
|
|
|
|
void sw_skip_save(struct sw_skip *skip, char *filename) {
|
|
sw_skip_save_to(skip, fopen(filename, "wb"));
|
|
}
|
|
|
|
static void sw_skip_save_to(struct sw_skip *skip, FILE *fil) {
|
|
u16 i;
|
|
u32 start;
|
|
|
|
start = ftell(fil);
|
|
sw_fwrite_str_nozero(fil, "SWZP");
|
|
sw_fwrite_u8(fil, 0); /* version */
|
|
sw_fwrite_u8(fil, 0); /* compression */
|
|
sw_fwrite_u32(fil, skip->data_size); /* uncompressed size */
|
|
sw_fwrite_u32(fil, skip->data_size); /* compressed size */
|
|
sw_fwrite_u16(fil, skip->file_count); /* file count */
|
|
|
|
for(i = 0; i < skip->file_count; ++i) {
|
|
sw_fwrite_u32(fil, skip->files[i].offset); /* offset */
|
|
sw_fwrite_u32(fil, skip->files[i].size); /* file size */
|
|
sw_fwrite_str_prefix8(fil, skip->files[i].name); /* file name */
|
|
}
|
|
|
|
fwrite(skip->data, 1, skip->data_size, fil);
|
|
|
|
sw_fwrite_u32(fil, ftell(fil) + 4 - start); /* file length */
|
|
|
|
fclose(fil);
|
|
}
|