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