mkespfsimage is now able to gzip files with selected extensions

pull/30/head
Jindra Dolezy 10 years ago
parent 391b6d014e
commit 7fabf11107
  1. 1
      espfs/espfsformat.h
  2. 161
      espfs/mkespfsimage/main.c

@ -16,6 +16,7 @@ with the FLAG_LASTFILE flag set.
#define FLAG_LASTFILE (1<<0) #define FLAG_LASTFILE (1<<0)
#define FLAG_GZIP (1<<1)
#define COMPRESS_NONE 0 #define COMPRESS_NONE 0
#define COMPRESS_HEATSHRINK 1 #define COMPRESS_HEATSHRINK 1
#define ESPFS_MAGIC 0x73665345 #define ESPFS_MAGIC 0x73665345

@ -18,6 +18,13 @@
#include "heatshrink_encoder.h" #include "heatshrink_encoder.h"
#endif #endif
//Gzip
#ifdef ESPFS_GZIP
// If compiler complains about missing header, try running "sudo apt-get install zlib1g-dev"
// to install missing package.
#include <zlib.h>
#endif
//Routines to convert host format to the endianness used in the xtensa //Routines to convert host format to the endianness used in the xtensa
short htoxs(short in) { short htoxs(short in) {
@ -83,11 +90,97 @@ size_t compressHeatshrink(char *in, int insize, char *out, int outsize, int leve
} }
#endif #endif
int handleFile(int f, char *name, int compression, int level) { #ifdef ESPFS_GZIP
size_t compressGzip(char *in, int insize, char *out, int outsize, int level) {
z_stream stream;
int zresult;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.next_in = in;
stream.avail_in = insize;
stream.next_out = out;
stream.avail_out = outsize;
// 31 -> 15 window bits + 16 for gzip
zresult = deflateInit2 (&stream, level, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
if (zresult != Z_OK) {
fprintf(stderr, "DeflateInit2 failed with code %d\n", zresult);
exit(1);
}
zresult = deflate(&stream, Z_FINISH);
if (zresult != Z_STREAM_END) {
fprintf(stderr, "Deflate failed with code %d\n", zresult);
exit(1);
}
zresult = deflateEnd(&stream);
if (zresult != Z_OK) {
fprintf(stderr, "DeflateEnd failed with code %d\n", zresult);
exit(1);
}
return stream.total_out;
}
char **gzipExtensions = NULL;
int shouldCompressGzip(char *name) {
char *ext = name + strlen(name);
while (*ext != '.') {
ext--;
if (ext < name) {
// no dot in file name -> no extension -> nothing to match against
return 0;
}
}
ext++;
int i = 0;
while (gzipExtensions[i] != NULL) {
if (strcmp(ext,gzipExtensions[i]) == 0) {
return 1;
}
i++;
}
return 0;
}
int parseGzipExtensions(char *input) {
char *token;
char *extList = input;
int count = 2; // one for first element, second for terminator
// count elements
while (*extList != 0) {
if (*extList == ',') count++;
extList++;
}
// split string
extList = input;
gzipExtensions = malloc(count * sizeof(char*));
count = 0;
token = strtok(extList, ",");
while (token) {
gzipExtensions[count++] = token;
token = strtok(NULL, ",");
}
// terminate list
gzipExtensions[count] = NULL;
return 1;
}
#endif
int handleFile(int f, char *name, int compression, int level, char **compName) {
char *fdat, *cdat; char *fdat, *cdat;
off_t size, csize; off_t size, csize;
EspFsHeader h; EspFsHeader h;
int nameLen; int nameLen;
int8_t flags = 0;
size=lseek(f, 0, SEEK_END); size=lseek(f, 0, SEEK_END);
fdat=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0); fdat=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0);
if (fdat==MAP_FAILED) { if (fdat==MAP_FAILED) {
@ -95,6 +188,17 @@ int handleFile(int f, char *name, int compression, int level) {
return 0; return 0;
} }
#ifdef ESPFS_GZIP
if (shouldCompressGzip(name)) {
csize = size*3;
if (csize<100) // gzip has some headers that do not fit when trying to compress small files
csize = 100; // enlarge buffer if this is the case
cdat=malloc(csize);
csize=compressGzip(fdat, size, cdat, csize, level);
compression = COMPRESS_NONE;
flags = FLAG_GZIP;
} else
#endif
if (compression==COMPRESS_NONE) { if (compression==COMPRESS_NONE) {
csize=size; csize=size;
cdat=fdat; cdat=fdat;
@ -113,20 +217,25 @@ int handleFile(int f, char *name, int compression, int level) {
compression=COMPRESS_NONE; compression=COMPRESS_NONE;
csize=size; csize=size;
cdat=fdat; cdat=fdat;
flags=0;
} }
//Fill header data //Fill header data
h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24); h.magic=('E'<<0)+('S'<<8)+('f'<<16)+('s'<<24);
h.flags=0; h.flags=flags;
h.compression=compression; h.compression=compression;
nameLen=strlen(name)+1; h.nameLen=nameLen=strlen(name)+1;
if (nameLen&3) nameLen+=4-(nameLen&3); //Round to next 32bit boundary if (h.nameLen&3) h.nameLen+=4-(h.nameLen&3); //Round to next 32bit boundary
h.nameLen=htoxs(nameLen); h.nameLen=htoxs(h.nameLen);
h.fileLenComp=htoxl(csize); h.fileLenComp=htoxl(csize);
h.fileLenDecomp=htoxl(size); h.fileLenDecomp=htoxl(size);
write(1, &h, sizeof(EspFsHeader)); write(1, &h, sizeof(EspFsHeader));
write(1, name, nameLen); //ToDo: this can eat up a few bytes after the buffer. write(1, name, nameLen);
while (nameLen&3) {
write(1, "\000", 1);
nameLen++;
}
write(1, cdat, csize); write(1, cdat, csize);
//Pad out to 32bit boundary //Pad out to 32bit boundary
while (csize&3) { while (csize&3) {
@ -134,6 +243,20 @@ int handleFile(int f, char *name, int compression, int level) {
csize++; csize++;
} }
munmap(fdat, size); munmap(fdat, size);
if (compName != NULL) {
if (h.compression==COMPRESS_HEATSHRINK) {
*compName = "heatshrink";
} else if (h.compression==COMPRESS_NONE) {
if (h.flags & FLAG_GZIP) {
*compName = "gzip";
} else {
*compName = "none";
}
} else {
*compName = "unknown";
}
}
return (csize*100)/size; return (csize*100)/size;
} }
@ -149,7 +272,6 @@ void finishArchive() {
write(1, &h, sizeof(EspFsHeader)); write(1, &h, sizeof(EspFsHeader));
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
int f, x; int f, x;
char fileName[1024]; char fileName[1024];
@ -175,14 +297,29 @@ int main(int argc, char **argv) {
compLvl=atoi(argv[x+1]); compLvl=atoi(argv[x+1]);
if (compLvl<1 || compLvl>9) err=1; if (compLvl<1 || compLvl>9) err=1;
x++; x++;
#ifdef ESPFS_GZIP
} else if (strcmp(argv[x], "-g")==0 && argc>=x-2) {
if (!parseGzipExtensions(argv[x+1])) err=1;
x++;
#endif
} else { } else {
err=1; err=1;
} }
} }
#ifdef ESPFS_GZIP
if (gzipExtensions == NULL) {
parseGzipExtensions(strdup("html,css,js"));
}
#endif
if (err) { if (err) {
fprintf(stderr, "%s - Program to create espfs images\n", argv[0]); fprintf(stderr, "%s - Program to create espfs images\n", argv[0]);
fprintf(stderr, "Usage: \nfind | %s [-c compressor] [-l compression_level] > out.espfs\n", argv[0]); fprintf(stderr, "Usage: \nfind | %s [-c compressor] [-l compression_level] ", argv[0]);
#ifdef ESPFS_GZIP
fprintf(stderr, "[-g gzipped_extensions] ");
#endif
fprintf(stderr, "> out.espfs\n");
fprintf(stderr, "Compressors:\n"); fprintf(stderr, "Compressors:\n");
#ifdef ESPFS_HEATSHRINK #ifdef ESPFS_HEATSHRINK
fprintf(stderr, "0 - None\n1 - Heatshrink(default)\n"); fprintf(stderr, "0 - None\n1 - Heatshrink(default)\n");
@ -190,6 +327,9 @@ int main(int argc, char **argv) {
fprintf(stderr, "0 - None(default)\n"); fprintf(stderr, "0 - None(default)\n");
#endif #endif
fprintf(stderr, "\nCompression level: 1 is worst but low RAM usage, higher is better compression \nbut uses more ram on decompression. -1 = compressors default.\n"); fprintf(stderr, "\nCompression level: 1 is worst but low RAM usage, higher is better compression \nbut uses more ram on decompression. -1 = compressors default.\n");
#ifdef ESPFS_GZIP
fprintf(stderr, "\nGzipped extensions: list of comma separated, case sensitive file extensions \nthat will be gzipped. Defaults to 'html,css,js'\n");
#endif
exit(0); exit(0);
} }
@ -205,8 +345,9 @@ int main(int argc, char **argv) {
if (realName[0]=='/') realName++; if (realName[0]=='/') realName++;
f=open(fileName, O_RDONLY); f=open(fileName, O_RDONLY);
if (f>0) { if (f>0) {
rate=handleFile(f, realName, compType, compLvl); char *compName = "unknown";
fprintf(stderr, "%s (%d%%)\n", realName, rate); rate=handleFile(f, realName, compType, compLvl, &compName);
fprintf(stderr, "%s (%d%%, %s)\n", realName, rate, compName);
close(f); close(f);
} else { } else {
perror(fileName); perror(fileName);

Loading…
Cancel
Save