Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <zlib.h>
- #include <dirent.h>
- #include <vector>
- #include <string>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/stat.h>
- using namespace std;
- // make a file archive
- typedef unsigned int u32;
- const size_t FILENAME_LEN = 64;
- const size_t BLOCKSIZE = 128;
- const u32 VERSION = 0x10001000;
- // 16 bytes
- struct Header {
- char id[4];
- u32 version;
- u32 size;
- u32 files;
- };
- // 96 bytes
- struct FileEntry {
- char filename[FILENAME_LEN];
- u32 size;
- u32 offset;
- u32 namehash;
- u32 checksum;
- u32 flags;
- u32 locale;
- u32 reserved1;
- u32 reserved2;
- };
- enum FLAGS
- {
- FLAG_LOCALIZED = 1<<0,
- FLAG_TSC = 1<<1
- };
- u32 calc_crc32(const void *data, u32 size)
- {
- u32 crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, (const Bytef*)data, size);
- return crc;
- }
- vector<FileEntry> files;
- vector<string> filepaths;
- u32 gsize;
- void addFile(const char *filename, const struct stat *st)
- {
- assert(filename);
- size_t namelen = strlen(filename);
- if (namelen>FILENAME_LEN) {
- fprintf(stderr, "Skipping file: %s (filename too long)\n", filename);
- return;
- }
- string origname(filename);
- FileEntry fe;
- memset(&fe, 0, sizeof(FileEntry));
- // check name for a locale?
- if (!strcmp(filename+namelen-3,".en")) fe.locale = 1;
- else if (!strcmp(filename+namelen-3,".jp")) fe.locale = 2;
- if (fe.locale) {
- namelen -= 3;
- fe.flags |= FLAG_LOCALIZED;
- }
- strncpy(fe.filename, filename, namelen);
- fe.size = st->st_size;
- fe.namehash = calc_crc32(filename, namelen);
- if (!strncmp(filename+namelen-4,".tsc",4)) fe.flags |= FLAG_TSC;
- FILE *f = fopen(origname.c_str(),"rb");
- char *buf = new char[fe.size];
- fread(buf, fe.size, 1, f);
- fclose(f);
- fe.checksum = calc_crc32(buf,fe.size);
- delete[] buf;
- files.push_back(fe);
- filepaths.push_back(origname);
- }
- void scanDir(const char *dirname) {
- assert(dirname);
- string basepath(dirname);
- DIR *dir = opendir(dirname);
- while (dirent *de = readdir(dir)) {
- const char *filename = de->d_name;
- string fullpath = basepath + "/";
- fullpath += filename;
- if (filename[0]!='.') {
- //printf("%s\n",fullpath.c_str());
- struct stat st;
- stat(fullpath.c_str(), &st);
- if (S_ISDIR(st.st_mode)) {
- // recurse
- scanDir(fullpath.c_str());
- } else {
- addFile(fullpath.c_str(), &st);
- }
- }
- }
- closedir(dir);
- }
- int roundUp(int value, int block = BLOCKSIZE)
- {
- int rem = value % block;
- return rem ? (value + block - rem) : value;
- }
- void buildFile(const char *nameOut)
- {
- int num = files.size();
- static char dummy[BLOCKSIZE];
- memset(dummy, 0, BLOCKSIZE);
- // fix up offsets
- int headersize = sizeof(Header) + num * sizeof(FileEntry);
- int firstoffset = roundUp(headersize);
- int of = firstoffset;
- for (vector<FileEntry>::iterator it = files.begin(); it != files.end(); ++it) {
- it->offset = of;
- of = roundUp(of+it->size);
- }
- Header h;
- strncpy(h.id, "Cave", 4);
- h.version = VERSION;
- h.size = of;
- gsize = of;
- h.files = num;
- FILE *fo = fopen(nameOut,"wb");
- // write header
- fwrite(&h, sizeof(Header), 1, fo);
- // write file entries
- for (vector<FileEntry>::iterator it = files.begin(); it != files.end(); ++it) {
- FileEntry *fe = &(*it);
- fwrite(fe, sizeof(FileEntry), 1, fo);
- }
- // pad
- fwrite(dummy, firstoffset-headersize, 1, fo);
- // write the files
- for (u32 i=0; i<num; i++) {
- FileEntry &fe = files[i];
- string &name = filepaths[i];
- FILE *fi = fopen(name.c_str(), "rb");
- char *buf = new char[fe.size];
- fread(buf, fe.size, 1, fi);
- fclose(fi);
- fwrite(buf, fe.size, 1, fo);
- delete[] buf;
- // pad
- int toPad = roundUp(fe.size) - fe.size;
- if (toPad) fwrite(dummy, toPad, 1, fo);
- }
- fclose(fo);
- printf("%d files packed.\n", num);
- }
- void compressFile(const char *nameIn, const char *nameOut)
- {
- FILE *f = fopen(nameIn, "rb");
- char *buf = new char[gsize];
- fread(buf, gsize, 1, f);
- fclose(f);
- u32 len = compressBound(gsize);
- char *buf2 = new char[len];
- int res = compress2((Bytef*)buf2, (uLongf*)&len, (const Bytef*)buf, gsize, 9);
- if (res != Z_OK) {
- fprintf(stderr, "Couldn't compress data\n");
- } else {
- f = fopen(nameOut, "wb");
- fwrite(&gsize, sizeof(u32), 1, f);
- fwrite(buf2, len, 1, f);
- fclose(f);
- delete[] buf;
- delete[] buf2;
- printf("Compressed %d -> %d bytes\n", gsize, len);
- }
- }
- int main(int argc, char *argv[])
- {
- scanDir("data");
- buildFile("archive.dat");
- compressFile("archive.dat", "data.csz");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment