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