BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * makefsdata: Converts a directory structure for use with the lwIP httpd.
3 *
4 * This file is part of the lwIP TCP/IP stack.
5 *
6 * Author: Jim Pettinato
7 * Simon Goldschmidt
8 *
9 * @todo:
10 * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and
11 * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments
12 */
13  
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #include <sys/stat.h>
19  
20 #include "tinydir.h"
21  
22 /** Makefsdata can generate *all* files deflate-compressed (where file size shrinks).
23 * Since nearly all browsers support this, this is a good way to reduce ROM size.
24 * To compress the files, "miniz.c" must be downloaded seperately.
25 */
26 #ifndef MAKEFS_SUPPORT_DEFLATE
27 #define MAKEFS_SUPPORT_DEFLATE 0
28 #endif
29  
30 #define COPY_BUFSIZE (1024*1024) /* 1 MByte */
31  
32 #if MAKEFS_SUPPORT_DEFLATE
33 #include "../miniz.c"
34  
35 typedef unsigned char uint8;
36 typedef unsigned short uint16;
37 typedef unsigned int uint;
38  
39 #define my_max(a,b) (((a) > (b)) ? (a) : (b))
40 #define my_min(a,b) (((a) < (b)) ? (a) : (b))
41  
42 /* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression.
43 COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */
44 #define COMP_OUT_BUF_SIZE COPY_BUFSIZE
45  
46 /* OUT_BUF_SIZE is the size of the output buffer used during decompression.
47 OUT_BUF_SIZE must be a power of 2 >= TINFL_LZ_DICT_SIZE (because the low-level decompressor not only writes, but reads from the output buffer as it decompresses) */
48 #define OUT_BUF_SIZE COPY_BUFSIZE
49 static uint8 s_outbuf[OUT_BUF_SIZE];
50 static uint8 s_checkbuf[OUT_BUF_SIZE];
51  
52 /* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k).
53 This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it. */
54 tdefl_compressor g_deflator;
55 tinfl_decompressor g_inflator;
56  
57 int deflate_level = 10; /* default compression level, can be changed via command line */
58 #define USAGE_ARG_DEFLATE " [-defl<:compr_level>]"
59 #else /* MAKEFS_SUPPORT_DEFLATE */
60 #define USAGE_ARG_DEFLATE ""
61 #endif /* MAKEFS_SUPPORT_DEFLATE */
62  
63 #ifdef WIN32
64  
65 #define GETCWD(path, len) GetCurrentDirectoryA(len, path)
66 #define CHDIR(path) SetCurrentDirectoryA(path)
67 #define CHDIR_SUCCEEDED(ret) (ret == TRUE)
68  
69 #elif __linux__
70  
71 #define GETCWD(path, len) getcwd(path, len)
72 #define CHDIR(path) chdir(path)
73 #define CHDIR_SUCCEEDED(ret) (ret == 0)
74  
75 #else
76  
77 #error makefsdata not supported on this platform
78  
79 #endif
80  
81 #define NEWLINE "\r\n"
82 #define NEWLINE_LEN 2
83  
84 /* define this to get the header variables we use to build HTTP headers */
85 #define LWIP_HTTPD_DYNAMIC_HEADERS 1
86 #define LWIP_HTTPD_SSI 1
87 #include "lwip/init.h"
88 #include "../httpd_structs.h"
89 #include "lwip/apps/fs.h"
90  
91 #include "../core/inet_chksum.c"
92 #include "../core/def.c"
93  
94 /** (Your server name here) */
95 const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n";
96 char serverIDBuffer[1024];
97  
98 /* change this to suit your MEM_ALIGNMENT */
99 #define PAYLOAD_ALIGNMENT 4
100 /* set this to 0 to prevent aligning payload */
101 #define ALIGN_PAYLOAD 1
102 /* define this to a type that has the required alignment */
103 #define PAYLOAD_ALIGN_TYPE "unsigned int"
104 static int payload_alingment_dummy_counter = 0;
105  
106 #define HEX_BYTES_PER_LINE 16
107  
108 #define MAX_PATH_LEN 256
109  
110 struct file_entry {
111 struct file_entry *next;
112 const char *filename_c;
113 };
114  
115 int process_sub(FILE *data_file, FILE *struct_file);
116 int process_file(FILE *data_file, FILE *struct_file, const char *filename);
117 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len,
118 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed);
119 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i);
120 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i);
121 void concat_files(const char *file1, const char *file2, const char *targetfile);
122 int check_path(char *path, size_t size);
123  
124 /* 5 bytes per char + 3 bytes per line */
125 static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)];
126  
127 char curSubdir[MAX_PATH_LEN];
128 char lastFileVar[MAX_PATH_LEN];
129 char hdr_buf[4096];
130  
131 unsigned char processSubs = 1;
132 unsigned char includeHttpHeader = 1;
133 unsigned char useHttp11 = 0;
134 unsigned char supportSsi = 1;
135 unsigned char precalcChksum = 0;
136 unsigned char includeLastModified = 0;
137 #if MAKEFS_SUPPORT_DEFLATE
138 unsigned char deflateNonSsiFiles = 0;
139 size_t deflatedBytesReduced = 0;
140 size_t overallDataBytes = 0;
141 #endif
142  
143 struct file_entry *first_file = NULL;
144 struct file_entry *last_file = NULL;
145  
146 static void print_usage(void)
147 {
148 printf(" Usage: htmlgen [targetdir] [-s] [-e] [-i] [-11] [-nossi] [-c] [-f:<filename>] [-m] [-svr:<name>]" USAGE_ARG_DEFLATE NEWLINE NEWLINE);
149 printf(" targetdir: relative or absolute path to files to convert" NEWLINE);
150 printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE);
151 printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE);
152 printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE);
153 printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE);
154 printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE);
155 printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE);
156 printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE);
157 printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE);
158 #if MAKEFS_SUPPORT_DEFLATE
159 printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE);
160 printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE);
161 #endif
162 printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE);
163 printf(" process files in subdirectory 'fs'" NEWLINE);
164 }
165  
166 int main(int argc, char *argv[])
167 {
168 char path[MAX_PATH_LEN];
169 char appPath[MAX_PATH_LEN];
170 FILE *data_file;
171 FILE *struct_file;
172 int filesProcessed;
173 int i;
174 char targetfile[MAX_PATH_LEN];
175 strcpy(targetfile, "fsdata.c");
176  
177 memset(path, 0, sizeof(path));
178 memset(appPath, 0, sizeof(appPath));
179  
180 printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE);
181 printf(" by Jim Pettinato - circa 2003 " NEWLINE);
182 printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE);
183  
184 LWIP_ASSERT("sizeof(hdr_buf) must fit into an u16_t", sizeof(hdr_buf) <= 0xffff);
185  
186 strcpy(path, "fs");
187 for (i = 1; i < argc; i++) {
188 if (argv[i] == NULL) {
189 continue;
190 }
191 if (argv[i][0] == '-') {
192 if (strstr(argv[i], "-svr:") == argv[i]) {
193 snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]);
194 serverID = serverIDBuffer;
195 printf("Using Server-ID: \"%s\"\n", serverID);
196 } else if (strstr(argv[i], "-s") == argv[i]) {
197 processSubs = 0;
198 } else if (strstr(argv[i], "-e") == argv[i]) {
199 includeHttpHeader = 0;
200 } else if (strstr(argv[i], "-11") == argv[i]) {
201 useHttp11 = 1;
202 } else if (strstr(argv[i], "-nossi") == argv[i]) {
203 supportSsi = 0;
204 } else if (strstr(argv[i], "-c") == argv[i]) {
205 precalcChksum = 1;
206 } else if (strstr(argv[i], "-f:") == argv[i]) {
207 strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1);
208 targetfile[sizeof(targetfile) - 1] = 0;
209 printf("Writing to file \"%s\"\n", targetfile);
210 } else if (strstr(argv[i], "-m") == argv[i]) {
211 includeLastModified = 1;
212 } else if (strstr(argv[i], "-defl") == argv[i]) {
213 #if MAKEFS_SUPPORT_DEFLATE
214 char *colon = strstr(argv[i], ":");
215 if (colon) {
216 if (colon[1] != 0) {
217 int defl_level = atoi(&colon[1]);
218 if ((defl_level >= 0) && (defl_level <= 10)) {
219 deflate_level = defl_level;
220 } else {
221 printf("ERROR: deflate level must be [0..10]" NEWLINE);
222 exit(0);
223 }
224 }
225 }
226 deflateNonSsiFiles = 1;
227 printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level);
228 #else
229 printf("WARNING: Deflate support is disabled\n");
230 #endif
231 } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) {
232 print_usage();
233 exit(0);
234 }
235 } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) {
236 print_usage();
237 exit(0);
238 } else {
239 strncpy(path, argv[i], sizeof(path) - 1);
240 path[sizeof(path) - 1] = 0;
241 }
242 }
243  
244 if (!check_path(path, sizeof(path))) {
245 printf("Invalid path: \"%s\"." NEWLINE, path);
246 exit(-1);
247 }
248  
249 GETCWD(appPath, MAX_PATH_LEN);
250 /* if command line param or subdir named 'fs' not found spout usage verbiage */
251 if (!CHDIR_SUCCEEDED(CHDIR(path))) {
252 /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */
253 printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path);
254 print_usage();
255 exit(-1);
256 }
257 CHDIR(appPath);
258  
259 printf("HTTP %sheader will %s statically included." NEWLINE,
260 (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""),
261 (includeHttpHeader ? "be" : "not be"));
262  
263 curSubdir[0] = '\0'; /* start off in web page's root directory - relative paths */
264 printf(" Processing all files in directory %s", path);
265 if (processSubs) {
266 printf(" and subdirectories..." NEWLINE NEWLINE);
267 } else {
268 printf("..." NEWLINE NEWLINE);
269 }
270  
271 data_file = fopen("fsdata.tmp", "wb");
272 if (data_file == NULL) {
273 printf("Failed to create file \"fsdata.tmp\"\n");
274 exit(-1);
275 }
276 struct_file = fopen("fshdr.tmp", "wb");
277 if (struct_file == NULL) {
278 printf("Failed to create file \"fshdr.tmp\"\n");
279 fclose(data_file);
280 exit(-1);
281 }
282  
283 CHDIR(path);
284  
285 fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE);
286 fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE NEWLINE NEWLINE);
287  
288 fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE);
289 /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */
290 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE);
291 /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */
292 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE);
293  
294 /* define alignment defines */
295 #if ALIGN_PAYLOAD
296 fprintf(data_file, "/* FSDATA_FILE_ALIGNMENT: 0=off, 1=by variable, 2=by include */" NEWLINE "#ifndef FSDATA_FILE_ALIGNMENT" NEWLINE "#define FSDATA_FILE_ALIGNMENT 0" NEWLINE "#endif" NEWLINE);
297 #endif
298 fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE);
299 fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE);
300 #if ALIGN_PAYLOAD
301 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE);
302 #endif
303  
304 sprintf(lastFileVar, "NULL");
305  
306 filesProcessed = process_sub(data_file, struct_file);
307  
308 /* data_file now contains all of the raw data.. now append linked list of
309 * file header structs to allow embedded app to search for a file name */
310 fprintf(data_file, NEWLINE NEWLINE);
311 fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar);
312 fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed);
313  
314 fclose(data_file);
315 fclose(struct_file);
316  
317 CHDIR(appPath);
318 /* append struct_file to data_file */
319 printf(NEWLINE "Creating target file..." NEWLINE NEWLINE);
320 concat_files("fsdata.tmp", "fshdr.tmp", targetfile);
321  
322 /* if succeeded, delete the temporary files */
323 if (remove("fsdata.tmp") != 0) {
324 printf("Warning: failed to delete fsdata.tmp\n");
325 }
326 if (remove("fshdr.tmp") != 0) {
327 printf("Warning: failed to delete fshdr.tmp\n");
328 }
329  
330 printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed);
331 #if MAKEFS_SUPPORT_DEFLATE
332 if (deflateNonSsiFiles) {
333 printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE,
334 (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced * 100.0) / overallDataBytes));
335 }
336 #endif
337 printf(NEWLINE);
338  
339 while (first_file != NULL) {
340 struct file_entry *fe = first_file;
341 first_file = fe->next;
342 free(fe);
343 }
344  
345 return 0;
346 }
347  
348 int check_path(char *path, size_t size)
349 {
350 size_t slen;
351 if (path[0] == 0) {
352 /* empty */
353 return 0;
354 }
355 slen = strlen(path);
356 if (slen >= size) {
357 /* not NULL-terminated */
358 return 0;
359 }
360 while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) {
361 /* path should not end with trailing backslash */
362 path[slen] = 0;
363 slen--;
364 }
365 if (slen == 0) {
366 return 0;
367 }
368 return 1;
369 }
370  
371 static void copy_file(const char *filename_in, FILE *fout)
372 {
373 FILE *fin;
374 size_t len;
375 void *buf;
376 fin = fopen(filename_in, "rb");
377 if (fin == NULL) {
378 printf("Failed to open file \"%s\"\n", filename_in);
379 exit(-1);
380 }
381 buf = malloc(COPY_BUFSIZE);
382 while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) {
383 fwrite(buf, 1, len, fout);
384 }
385 free(buf);
386 fclose(fin);
387 }
388  
389 void concat_files(const char *file1, const char *file2, const char *targetfile)
390 {
391 FILE *fout;
392 fout = fopen(targetfile, "wb");
393 if (fout == NULL) {
394 printf("Failed to open file \"%s\"\n", targetfile);
395 exit(-1);
396 }
397 copy_file(file1, fout);
398 copy_file(file2, fout);
399 fclose(fout);
400 }
401  
402 int process_sub(FILE *data_file, FILE *struct_file)
403 {
404 tinydir_dir dir;
405 int filesProcessed = 0;
406  
407 if (processSubs) {
408 /* process subs recursively */
409 size_t sublen = strlen(curSubdir);
410 size_t freelen = sizeof(curSubdir) - sublen - 1;
411 int ret;
412 LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir));
413  
414 ret = tinydir_open_sorted(&dir, TINYDIR_STRING("."));
415  
416 if (ret == 0) {
417 unsigned int i;
418 for (i = 0; i < dir.n_files; i++) {
419 tinydir_file file;
420  
421 ret = tinydir_readfile_n(&dir, &file, i);
422  
423 if (ret == 0) {
424 #if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE)
425 size_t i;
426 char currName[256];
427 wcstombs_s(&i, currName, sizeof(currName), file.name, sizeof(currName));
428 #else
429 const char *currName = file.name;
430 #endif
431  
432 if (currName[0] == '.') {
433 continue;
434 }
435 if (!file.is_dir) {
436 continue;
437 }
438 if (freelen > 0) {
439 CHDIR(currName);
440 strncat(curSubdir, "/", freelen);
441 strncat(curSubdir, currName, freelen - 1);
442 curSubdir[sizeof(curSubdir) - 1] = 0;
443 printf("processing subdirectory %s/..." NEWLINE, curSubdir);
444 filesProcessed += process_sub(data_file, struct_file);
445 CHDIR("..");
446 curSubdir[sublen] = 0;
447 } else {
448 printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, currName);
449 }
450 }
451 }
452 }
453  
454 ret = tinydir_open_sorted(&dir, TINYDIR_STRING("."));
455 if (ret == 0) {
456 unsigned int i;
457 for (i = 0; i < dir.n_files; i++) {
458 tinydir_file file;
459  
460 ret = tinydir_readfile_n(&dir, &file, i);
461  
462 if (ret == 0) {
463 if (!file.is_dir) {
464 #if (defined _MSC_VER || defined __MINGW32__) && (defined _UNICODE)
465 size_t i;
466 char curName[256];
467 wcstombs_s(&i, curName, sizeof(curName), file.name, sizeof(curName));
468 #else
469 const char *curName = file.name;
470 #endif
471  
472 if (strcmp(curName, "fsdata.tmp") == 0) {
473 continue;
474 }
475 if (strcmp(curName, "fshdr.tmp") == 0) {
476 continue;
477 }
478  
479 printf("processing %s/%s..." NEWLINE, curSubdir, curName);
480  
481 if (process_file(data_file, struct_file, curName) < 0) {
482 printf(NEWLINE "Error... aborting" NEWLINE);
483 return -1;
484 }
485 filesProcessed++;
486 }
487 }
488 }
489 }
490 }
491  
492 return filesProcessed;
493 }
494  
495 static u8_t *get_file_data(const char *filename, int *file_size, int can_be_compressed, int *is_compressed)
496 {
497 FILE *inFile;
498 size_t fsize = 0;
499 u8_t *buf;
500 size_t r;
501 int rs;
502 inFile = fopen(filename, "rb");
503 if (inFile == NULL) {
504 printf("Failed to open file \"%s\"\n", filename);
505 exit(-1);
506 }
507 fseek(inFile, 0, SEEK_END);
508 rs = ftell(inFile);
509 if (rs < 0) {
510 printf("ftell failed with %d\n", errno);
511 exit(-1);
512 }
513 fsize = (size_t)rs;
514 fseek(inFile, 0, SEEK_SET);
515 buf = (u8_t *)malloc(fsize);
516 LWIP_ASSERT("buf != NULL", buf != NULL);
517 r = fread(buf, 1, fsize, inFile);
518 LWIP_ASSERT("r == fsize", r == fsize);
519 *file_size = fsize;
520 *is_compressed = 0;
521 #if MAKEFS_SUPPORT_DEFLATE
522 overallDataBytes += fsize;
523 if (deflateNonSsiFiles) {
524 if (can_be_compressed) {
525 if (fsize < OUT_BUF_SIZE) {
526 u8_t *ret_buf;
527 tdefl_status status;
528 size_t in_bytes = fsize;
529 size_t out_bytes = OUT_BUF_SIZE;
530 const void *next_in = buf;
531 void *next_out = s_outbuf;
532 /* create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined). */
533 mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
534 if (!deflate_level) {
535 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
536 }
537 status = tdefl_init(&g_deflator, NULL, NULL, comp_flags);
538 if (status != TDEFL_STATUS_OKAY) {
539 printf("tdefl_init() failed!\n");
540 exit(-1);
541 }
542 memset(s_outbuf, 0, sizeof(s_outbuf));
543 status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH);
544 if (status != TDEFL_STATUS_DONE) {
545 printf("deflate failed: %d\n", status);
546 exit(-1);
547 }
548 LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE);
549 if (out_bytes < fsize) {
550 ret_buf = (u8_t *)malloc(out_bytes);
551 LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL);
552 memcpy(ret_buf, s_outbuf, out_bytes);
553 {
554 /* sanity-check compression be inflating and comparing to the original */
555 tinfl_status dec_status;
556 tinfl_decompressor inflator;
557 size_t dec_in_bytes = out_bytes;
558 size_t dec_out_bytes = OUT_BUF_SIZE;
559 next_out = s_checkbuf;
560  
561 tinfl_init(&inflator);
562 memset(s_checkbuf, 0, sizeof(s_checkbuf));
563 dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0);
564 LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE);
565 LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes);
566 LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize));
567 }
568 /* free original buffer, use compressed data + size */
569 free(buf);
570 buf = ret_buf;
571 *file_size = out_bytes;
572 printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes * 100.0) / fsize));
573 deflatedBytesReduced += (size_t)(fsize - out_bytes);
574 *is_compressed = 1;
575 } else {
576 printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize));
577 }
578 } else {
579 printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE);
580 }
581 } else {
582 printf(" - SSI file, cannot be compressed" NEWLINE);
583 }
584 }
585 #else
586 LWIP_UNUSED_ARG(can_be_compressed);
587 #endif
588 fclose(inFile);
589 return buf;
590 }
591  
592 static void process_file_data(FILE *data_file, u8_t *file_data, size_t file_size)
593 {
594 size_t written, i, src_off = 0;
595  
596 size_t off = 0;
597 for (i = 0; i < file_size; i++) {
598 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5);
599 sprintf(&file_buffer_c[off], "0x%02x,", file_data[i]);
600 off += 5;
601 if ((++src_off % HEX_BYTES_PER_LINE) == 0) {
602 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN);
603 memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN);
604 off += NEWLINE_LEN;
605 }
606 if (off + 20 >= sizeof(file_buffer_c)) {
607 written = fwrite(file_buffer_c, 1, off, data_file);
608 LWIP_ASSERT("written == off", written == off);
609 off = 0;
610 }
611 }
612 written = fwrite(file_buffer_c, 1, off, data_file);
613 LWIP_ASSERT("written == off", written == off);
614 }
615  
616 static int write_checksums(FILE *struct_file, const char *varname,
617 u16_t hdr_len, u16_t hdr_chksum, const u8_t *file_data, size_t file_size)
618 {
619 int chunk_size = TCP_MSS;
620 int offset, src_offset;
621 size_t len;
622 int i = 0;
623 #if LWIP_TCP_TIMESTAMPS
624 /* when timestamps are used, usable space is 12 bytes less per segment */
625 chunk_size -= 12;
626 #endif
627  
628 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
629 fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname);
630  
631 if (hdr_len > 0) {
632 /* add checksum for HTTP header */
633 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len);
634 i++;
635 }
636 src_offset = 0;
637 for (offset = hdr_len; ; offset += len) {
638 unsigned short chksum;
639 const void *data = (const void *)&file_data[src_offset];
640 len = LWIP_MIN(chunk_size, (int)file_size - src_offset);
641 if (len == 0) {
642 break;
643 }
644 chksum = ~inet_chksum(data, (u16_t)len);
645 /* add checksum for data */
646 fprintf(struct_file, "{%d, 0x%04x, %"SZT_F"}," NEWLINE, offset, chksum, len);
647 i++;
648 }
649 fprintf(struct_file, "};" NEWLINE);
650 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE);
651 return i;
652 }
653  
654 static int is_valid_char_for_c_var(char x)
655 {
656 if (((x >= 'A') && (x <= 'Z')) ||
657 ((x >= 'a') && (x <= 'z')) ||
658 ((x >= '0') && (x <= '9')) ||
659 (x == '_')) {
660 return 1;
661 }
662 return 0;
663 }
664  
665 static void fix_filename_for_c(char *qualifiedName, size_t max_len)
666 {
667 struct file_entry *f;
668 size_t len = strlen(qualifiedName);
669 char *new_name = (char *)malloc(len + 2);
670 int filename_ok;
671 int cnt = 0;
672 size_t i;
673 if (len + 3 == max_len) {
674 printf("File name too long: \"%s\"\n", qualifiedName);
675 exit(-1);
676 }
677 strcpy(new_name, qualifiedName);
678 for (i = 0; i < len; i++) {
679 if (!is_valid_char_for_c_var(new_name[i])) {
680 new_name[i] = '_';
681 }
682 }
683 do {
684 filename_ok = 1;
685 for (f = first_file; f != NULL; f = f->next) {
686 if (!strcmp(f->filename_c, new_name)) {
687 filename_ok = 0;
688 cnt++;
689 /* try next unique file name */
690 sprintf(&new_name[len], "%d", cnt);
691 break;
692 }
693 }
694 } while (!filename_ok && (cnt < 999));
695 if (!filename_ok) {
696 printf("Failed to get unique file name: \"%s\"\n", qualifiedName);
697 exit(-1);
698 }
699 strcpy(qualifiedName, new_name);
700 free(new_name);
701 }
702  
703 static void register_filename(const char *qualifiedName)
704 {
705 struct file_entry *fe = (struct file_entry *)malloc(sizeof(struct file_entry));
706 fe->filename_c = strdup(qualifiedName);
707 fe->next = NULL;
708 if (first_file == NULL) {
709 first_file = last_file = fe;
710 } else {
711 last_file->next = fe;
712 last_file = fe;
713 }
714 }
715  
716 static int is_ssi_file(const char *filename)
717 {
718 size_t loop;
719 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) {
720 if (strstr(filename, g_pcSSIExtensions[loop])) {
721 return 1;
722 }
723 }
724 return 0;
725 }
726  
727 int process_file(FILE *data_file, FILE *struct_file, const char *filename)
728 {
729 char varname[MAX_PATH_LEN];
730 int i = 0;
731 char qualifiedName[MAX_PATH_LEN];
732 int file_size;
733 u16_t http_hdr_chksum = 0;
734 u16_t http_hdr_len = 0;
735 int chksum_count = 0;
736 u8_t flags = 0;
737 const char *flags_str;
738 u8_t has_content_len;
739 u8_t *file_data;
740 int is_compressed = 0;
741  
742 /* create qualified name (@todo: prepend slash or not?) */
743 sprintf(qualifiedName, "%s/%s", curSubdir, filename);
744 /* create C variable name */
745 strcpy(varname, qualifiedName);
746 /* convert slashes & dots to underscores */
747 fix_filename_for_c(varname, MAX_PATH_LEN);
748 register_filename(varname);
749 #if ALIGN_PAYLOAD
750 /* to force even alignment of array, type 1 */
751 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE);
752 fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++);
753 fprintf(data_file, "#endif" NEWLINE);
754 #endif /* ALIGN_PAYLOAD */
755 fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname);
756 /* encode source file name (used by file system, not returned to browser) */
757 fprintf(data_file, "/* %s (%"SZT_F" chars) */" NEWLINE, qualifiedName, strlen(qualifiedName) + 1);
758 file_put_ascii(data_file, qualifiedName, strlen(qualifiedName) + 1, &i);
759 #if ALIGN_PAYLOAD
760 /* pad to even number of bytes to assure payload is on aligned boundary */
761 while (i % PAYLOAD_ALIGNMENT != 0) {
762 fprintf(data_file, "0x%02x,", 0);
763 i++;
764 }
765 #endif /* ALIGN_PAYLOAD */
766 fprintf(data_file, NEWLINE);
767  
768 has_content_len = !is_ssi_file(filename);
769 file_data = get_file_data(filename, &file_size, includeHttpHeader && has_content_len, &is_compressed);
770 if (includeHttpHeader) {
771 file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed);
772 flags = FS_FILE_FLAGS_HEADER_INCLUDED;
773 if (has_content_len) {
774 flags |= FS_FILE_FLAGS_HEADER_PERSISTENT;
775 }
776 }
777 if (precalcChksum) {
778 chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size);
779 }
780  
781 /* build declaration of struct fsdata_file in temp file */
782 fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname);
783 fprintf(struct_file, "file_%s," NEWLINE, lastFileVar);
784 fprintf(struct_file, "data_%s," NEWLINE, varname);
785 fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i);
786 fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i);
787 switch (flags) {
788 case (FS_FILE_FLAGS_HEADER_INCLUDED):
789 flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED";
790 break;
791 case (FS_FILE_FLAGS_HEADER_PERSISTENT):
792 flags_str = "FS_FILE_FLAGS_HEADER_PERSISTENT";
793 break;
794 case (FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT):
795 flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT";
796 break;
797 default:
798 flags_str = "0";
799 break;
800 }
801 fprintf(struct_file, "%s," NEWLINE, flags_str);
802 if (precalcChksum) {
803 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
804 fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname);
805 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE);
806 }
807 fprintf(struct_file, "}};" NEWLINE NEWLINE);
808 strcpy(lastFileVar, varname);
809  
810 /* write actual file contents */
811 i = 0;
812 fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size);
813 process_file_data(data_file, file_data, file_size);
814 fprintf(data_file, "};" NEWLINE NEWLINE);
815 free(file_data);
816 return 0;
817 }
818  
819 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len,
820 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed)
821 {
822 int i = 0;
823 int response_type = HTTP_HDR_OK;
824 const char *file_type;
825 const char *cur_string;
826 size_t cur_len;
827 int written = 0;
828 size_t hdr_len = 0;
829 u16_t acc;
830 const char *file_ext;
831 size_t j;
832 u8_t provide_last_modified = includeLastModified;
833  
834 memset(hdr_buf, 0, sizeof(hdr_buf));
835  
836 if (useHttp11) {
837 response_type = HTTP_HDR_OK_11;
838 }
839  
840 fprintf(data_file, NEWLINE "/* HTTP header */");
841 if (strstr(filename, "404") == filename) {
842 response_type = HTTP_HDR_NOT_FOUND;
843 if (useHttp11) {
844 response_type = HTTP_HDR_NOT_FOUND_11;
845 }
846 } else if (strstr(filename, "400") == filename) {
847 response_type = HTTP_HDR_BAD_REQUEST;
848 if (useHttp11) {
849 response_type = HTTP_HDR_BAD_REQUEST_11;
850 }
851 } else if (strstr(filename, "501") == filename) {
852 response_type = HTTP_HDR_NOT_IMPL;
853 if (useHttp11) {
854 response_type = HTTP_HDR_NOT_IMPL_11;
855 }
856 }
857 cur_string = g_psHTTPHeaderStrings[response_type];
858 cur_len = strlen(cur_string);
859 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len);
860 written += file_put_ascii(data_file, cur_string, cur_len, &i);
861 i = 0;
862 if (precalcChksum) {
863 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
864 hdr_len += cur_len;
865 }
866  
867 cur_string = serverID;
868 cur_len = strlen(cur_string);
869 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len);
870 written += file_put_ascii(data_file, cur_string, cur_len, &i);
871 i = 0;
872 if (precalcChksum) {
873 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
874 hdr_len += cur_len;
875 }
876  
877 file_ext = filename;
878 if (file_ext != NULL) {
879 while (strstr(file_ext, ".") != NULL) {
880 file_ext = strstr(file_ext, ".");
881 file_ext++;
882 }
883 }
884 if ((file_ext == NULL) || (*file_ext == 0)) {
885 printf("failed to get extension for file \"%s\", using default.\n", filename);
886 file_type = HTTP_HDR_DEFAULT_TYPE;
887 } else {
888 file_type = NULL;
889 for (j = 0; j < NUM_HTTP_HEADERS; j++) {
890 if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) {
891 file_type = g_psHTTPHeaders[j].content_type;
892 break;
893 }
894 }
895 if (file_type == NULL) {
896 printf("failed to get file type for extension \"%s\", using default.\n", file_ext);
897 file_type = HTTP_HDR_DEFAULT_TYPE;
898 }
899 }
900  
901 /* Content-Length is used for persistent connections in HTTP/1.1 but also for
902 download progress in older versions
903 @todo: just use a big-enough buffer and let the HTTPD send spaces? */
904 if (provide_content_len) {
905 char intbuf[MAX_PATH_LEN];
906 int content_len = file_size;
907 memset(intbuf, 0, sizeof(intbuf));
908 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
909 cur_len = strlen(cur_string);
910 fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, content_len, cur_len + 2);
911 written += file_put_ascii(data_file, cur_string, cur_len, &i);
912 if (precalcChksum) {
913 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
914 hdr_len += cur_len;
915 }
916  
917 lwip_itoa(intbuf, sizeof(intbuf), content_len);
918 strcat(intbuf, "\r\n");
919 cur_len = strlen(intbuf);
920 written += file_put_ascii(data_file, intbuf, cur_len, &i);
921 i = 0;
922 if (precalcChksum) {
923 memcpy(&hdr_buf[hdr_len], intbuf, cur_len);
924 hdr_len += cur_len;
925 }
926 }
927 if (provide_last_modified) {
928 char modbuf[256];
929 struct stat stat_data;
930 struct tm *t;
931 memset(modbuf, 0, sizeof(modbuf));
932 memset(&stat_data, 0, sizeof(stat_data));
933 cur_string = modbuf;
934 strcpy(modbuf, "Last-Modified: ");
935 if (stat(filename, &stat_data) != 0) {
936 printf("stat(%s) failed with error %d\n", filename, errno);
937 exit(-1);
938 }
939 t = gmtime(&stat_data.st_mtime);
940 if (t == NULL) {
941 printf("gmtime() failed with error %d\n", errno);
942 exit(-1);
943 }
944 strftime(&modbuf[15], sizeof(modbuf) - 15, "%a, %d %b %Y %H:%M:%S GMT", t);
945 cur_len = strlen(cur_string);
946 fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%"SZT_F"+ bytes) */" NEWLINE, cur_string, cur_len + 2);
947 written += file_put_ascii(data_file, cur_string, cur_len, &i);
948 if (precalcChksum) {
949 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
950 hdr_len += cur_len;
951 }
952  
953 modbuf[0] = 0;
954 strcat(modbuf, "\r\n");
955 cur_len = strlen(modbuf);
956 written += file_put_ascii(data_file, modbuf, cur_len, &i);
957 i = 0;
958 if (precalcChksum) {
959 memcpy(&hdr_buf[hdr_len], modbuf, cur_len);
960 hdr_len += cur_len;
961 }
962 }
963  
964 /* HTTP/1.1 implements persistent connections */
965 if (useHttp11) {
966 if (provide_content_len) {
967 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE];
968 } else {
969 /* no Content-Length available, so a persistent connection is no possible
970 because the client does not know the data length */
971 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
972 }
973 cur_len = strlen(cur_string);
974 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len);
975 written += file_put_ascii(data_file, cur_string, cur_len, &i);
976 i = 0;
977 if (precalcChksum) {
978 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
979 hdr_len += cur_len;
980 }
981 }
982  
983 #if MAKEFS_SUPPORT_DEFLATE
984 if (is_compressed) {
985 /* tell the client about the deflate encoding */
986 LWIP_ASSERT("error", deflateNonSsiFiles);
987 cur_string = "Content-Encoding: deflate\r\n";
988 cur_len = strlen(cur_string);
989 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
990 written += file_put_ascii(data_file, cur_string, cur_len, &i);
991 i = 0;
992 }
993 #else
994 LWIP_UNUSED_ARG(is_compressed);
995 #endif
996  
997 /* write content-type, ATTENTION: this includes the double-CRLF! */
998 cur_string = file_type;
999 cur_len = strlen(cur_string);
1000 fprintf(data_file, NEWLINE "/* \"%s\" (%"SZT_F" bytes) */" NEWLINE, cur_string, cur_len);
1001 written += file_put_ascii(data_file, cur_string, cur_len, &i);
1002 i = 0;
1003  
1004 /* ATTENTION: headers are done now (double-CRLF has been written!) */
1005  
1006 if (precalcChksum) {
1007 LWIP_ASSERT("hdr_len + cur_len <= sizeof(hdr_buf)", hdr_len + cur_len <= sizeof(hdr_buf));
1008 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
1009 hdr_len += cur_len;
1010  
1011 LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len);
1012 acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len);
1013 *http_hdr_len = (u16_t)hdr_len;
1014 *http_hdr_chksum = acc;
1015 }
1016  
1017 return written;
1018 }
1019  
1020 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i)
1021 {
1022 int x;
1023 for (x = 0; x < len; x++) {
1024 unsigned char cur = ascii_string[x];
1025 fprintf(file, "0x%02x,", cur);
1026 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) {
1027 fprintf(file, NEWLINE);
1028 }
1029 }
1030 return len;
1031 }
1032  
1033 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i)
1034 {
1035 int x;
1036 int idx = 0;
1037 for (x = 0; x < len; x++) {
1038 unsigned char cur = ascii_string[x];
1039 sprintf(&buf[idx], "0x%02x,", cur);
1040 idx += 5;
1041 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) {
1042 sprintf(&buf[idx], NEWLINE);
1043 idx += NEWLINE_LEN;
1044 }
1045 }
1046 return len;
1047 }