mkespfsimage is now able to gzip files with selected extensions
This commit is contained in:
@@ -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
|
||||||
|
|||||||
+152
-11
@@ -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,18 +90,115 @@ 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) {
|
||||||
perror("mmap");
|
perror("mmap");
|
||||||
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);
|
||||||
|
|||||||
Reference in New Issue
Block a user