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