Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
lwip_makefsdata.c
00001 /** 00002 * makefsdata: Converts a directory structure for use with the lwIP httpd. 00003 * 00004 * This file is part of the lwIP TCP/IP stack. 00005 * 00006 * Author: Jim Pettinato 00007 * Simon Goldschmidt 00008 * 00009 * @todo: 00010 * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and 00011 * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments 00012 */ 00013 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #ifdef WIN32 00017 #define WIN32_LEAN_AND_MEAN 00018 #include "windows.h" 00019 #else 00020 #include <dir.h> 00021 #endif 00022 #include <dos.h> 00023 #include <string.h> 00024 #include <time.h> 00025 #include <sys/stat.h> 00026 00027 /** Makefsdata can generate *all* files deflate-compressed (where file size shrinks). 00028 * Since nearly all browsers support this, this is a good way to reduce ROM size. 00029 * To compress the files, "miniz.c" must be downloaded seperately. 00030 */ 00031 #ifndef MAKEFS_SUPPORT_DEFLATE 00032 #define MAKEFS_SUPPORT_DEFLATE 0 00033 #endif 00034 00035 #define COPY_BUFSIZE (1024*1024) /* 1 MByte */ 00036 00037 #if MAKEFS_SUPPORT_DEFLATE 00038 #include "../miniz.c" 00039 00040 typedef unsigned char uint8; 00041 typedef unsigned short uint16; 00042 typedef unsigned int uint; 00043 00044 #define my_max(a,b) (((a) > (b)) ? (a) : (b)) 00045 #define my_min(a,b) (((a) < (b)) ? (a) : (b)) 00046 00047 /* COMP_OUT_BUF_SIZE is the size of the output buffer used during compression. 00048 COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE */ 00049 #define COMP_OUT_BUF_SIZE COPY_BUFSIZE 00050 00051 /* OUT_BUF_SIZE is the size of the output buffer used during decompression. 00052 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) */ 00053 #define OUT_BUF_SIZE COPY_BUFSIZE 00054 static uint8 s_outbuf[OUT_BUF_SIZE]; 00055 static uint8 s_checkbuf[OUT_BUF_SIZE]; 00056 00057 /* tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k). 00058 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. */ 00059 tdefl_compressor g_deflator; 00060 tinfl_decompressor g_inflator; 00061 00062 int deflate_level = 10; /* default compression level, can be changed via command line */ 00063 #define USAGE_ARG_DEFLATE " [-defl<:compr_level>]" 00064 #else /* MAKEFS_SUPPORT_DEFLATE */ 00065 #define USAGE_ARG_DEFLATE "" 00066 #endif /* MAKEFS_SUPPORT_DEFLATE */ 00067 00068 /* Compatibility defines Win32 vs. DOS */ 00069 #ifdef WIN32 00070 00071 #define FIND_T WIN32_FIND_DATAA 00072 #define FIND_T_FILENAME(fInfo) (fInfo.cFileName) 00073 #define FIND_T_IS_DIR(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) 00074 #define FIND_T_IS_FILE(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) 00075 #define FIND_RET_T HANDLE 00076 #define FINDFIRST_FILE(path, result) FindFirstFileA(path, result) 00077 #define FINDFIRST_DIR(path, result) FindFirstFileA(path, result) 00078 #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) 00079 #define FINDFIRST_SUCCEEDED(ret) (ret != INVALID_HANDLE_VALUE) 00080 #define FINDNEXT_SUCCEEDED(ret) (ret == TRUE) 00081 00082 #define GETCWD(path, len) GetCurrentDirectoryA(len, path) 00083 #define CHDIR(path) SetCurrentDirectoryA(path) 00084 #define CHDIR_SUCCEEDED(ret) (ret == TRUE) 00085 00086 #else 00087 00088 #define FIND_T struct ffblk 00089 #define FIND_T_FILENAME(fInfo) (fInfo.ff_name) 00090 #define FIND_T_IS_DIR(fInfo) ((fInfo.ff_attrib & FA_DIREC) == FA_DIREC) 00091 #define FIND_T_IS_FILE(fInfo) (1) 00092 #define FIND_RET_T int 00093 #define FINDFIRST_FILE(path, result) findfirst(path, result, FA_ARCH) 00094 #define FINDFIRST_DIR(path, result) findfirst(path, result, FA_DIREC) 00095 #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) 00096 #define FINDFIRST_SUCCEEDED(ret) (ret == 0) 00097 #define FINDNEXT_SUCCEEDED(ret) (ret == 0) 00098 00099 #define GETCWD(path, len) getcwd(path, len) 00100 #define CHDIR(path) chdir(path) 00101 #define CHDIR_SUCCEEDED(ret) (ret == 0) 00102 00103 #endif 00104 00105 #define NEWLINE "\r\n" 00106 #define NEWLINE_LEN 2 00107 00108 /* define this to get the header variables we use to build HTTP headers */ 00109 #define LWIP_HTTPD_DYNAMIC_HEADERS 1 00110 #define LWIP_HTTPD_SSI 1 00111 #include "lwip/init.h" 00112 #include "../httpd_structs.h" 00113 #include "lwip/apps/fs.h" 00114 00115 #include "../core/inet_chksum.c" 00116 #include "../core/def.c" 00117 00118 /** (Your server name here) */ 00119 const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; 00120 char serverIDBuffer[1024]; 00121 00122 /* change this to suit your MEM_ALIGNMENT */ 00123 #define PAYLOAD_ALIGNMENT 4 00124 /* set this to 0 to prevent aligning payload */ 00125 #define ALIGN_PAYLOAD 1 00126 /* define this to a type that has the required alignment */ 00127 #define PAYLOAD_ALIGN_TYPE "unsigned int" 00128 static int payload_alingment_dummy_counter = 0; 00129 00130 #define HEX_BYTES_PER_LINE 16 00131 00132 #define MAX_PATH_LEN 256 00133 00134 struct file_entry 00135 { 00136 struct file_entry* next; 00137 const char* filename_c; 00138 }; 00139 00140 int process_sub(FILE *data_file, FILE *struct_file); 00141 int process_file(FILE *data_file, FILE *struct_file, const char *filename); 00142 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 00143 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed); 00144 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); 00145 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); 00146 void concat_files(const char *file1, const char *file2, const char *targetfile); 00147 int check_path(char* path, size_t size); 00148 00149 /* 5 bytes per char + 3 bytes per line */ 00150 static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; 00151 00152 char curSubdir[MAX_PATH_LEN]; 00153 char lastFileVar[MAX_PATH_LEN]; 00154 char hdr_buf[4096]; 00155 00156 unsigned char processSubs = 1; 00157 unsigned char includeHttpHeader = 1; 00158 unsigned char useHttp11 = 0; 00159 unsigned char supportSsi = 1; 00160 unsigned char precalcChksum = 0; 00161 unsigned char includeLastModified = 0; 00162 #if MAKEFS_SUPPORT_DEFLATE 00163 unsigned char deflateNonSsiFiles = 0; 00164 size_t deflatedBytesReduced = 0; 00165 size_t overallDataBytes = 0; 00166 #endif 00167 00168 struct file_entry* first_file = NULL; 00169 struct file_entry* last_file = NULL; 00170 00171 static void print_usage(void) 00172 { 00173 printf(" Usage: htmlgen [targetdir] [-s] [-e] [-i] [-11] [-nossi] [-c] [-f:<filename>] [-m] [-svr:<name>]" USAGE_ARG_DEFLATE NEWLINE NEWLINE); 00174 printf(" targetdir: relative or absolute path to files to convert" NEWLINE); 00175 printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); 00176 printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); 00177 printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); 00178 printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); 00179 printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); 00180 printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); 00181 printf(" switch -m: include \"Last-Modified\" header based on file time" NEWLINE); 00182 printf(" switch -svr: server identifier sent in HTTP response header ('Server' field)" NEWLINE); 00183 #if MAKEFS_SUPPORT_DEFLATE 00184 printf(" switch -defl: deflate-compress all non-SSI files (with opt. compr.-level, default=10)" NEWLINE); 00185 printf(" ATTENTION: browser has to support \"Content-Encoding: deflate\"!" NEWLINE); 00186 #endif 00187 printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); 00188 printf(" process files in subdirectory 'fs'" NEWLINE); 00189 } 00190 00191 int main(int argc, char *argv[]) 00192 { 00193 char path[MAX_PATH_LEN]; 00194 char appPath[MAX_PATH_LEN]; 00195 FILE *data_file; 00196 FILE *struct_file; 00197 int filesProcessed; 00198 int i; 00199 char targetfile[MAX_PATH_LEN]; 00200 strcpy(targetfile, "fsdata.c"); 00201 00202 memset(path, 0, sizeof(path)); 00203 memset(appPath, 0, sizeof(appPath)); 00204 00205 printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); 00206 printf(" by Jim Pettinato - circa 2003 " NEWLINE); 00207 printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); 00208 00209 strcpy(path, "fs"); 00210 for (i = 1; i < argc; i++) { 00211 if (argv[i] == NULL) { 00212 continue; 00213 } 00214 if (argv[i][0] == '-') { 00215 if (strstr(argv[i], "-svr:") == argv[i]) { 00216 snprintf(serverIDBuffer, sizeof(serverIDBuffer), "Server: %s\r\n", &argv[i][5]); 00217 serverID = serverIDBuffer; 00218 printf("Using Server-ID: \"%s\"\n", serverID); 00219 } else if (strstr(argv[i], "-s") == argv[i]) { 00220 processSubs = 0; 00221 } else if (strstr(argv[i], "-e") == argv[i]) { 00222 includeHttpHeader = 0; 00223 } else if (strstr(argv[i], "-11") == argv[i]) { 00224 useHttp11 = 1; 00225 } else if (strstr(argv[i], "-nossi") == argv[i]) { 00226 supportSsi = 0; 00227 } else if (strstr(argv[i], "-c") == argv[i]) { 00228 precalcChksum = 1; 00229 } else if (strstr(argv[i], "-f:") == argv[i]) { 00230 strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); 00231 targetfile[sizeof(targetfile) - 1] = 0; 00232 printf("Writing to file \"%s\"\n", targetfile); 00233 } else if (strstr(argv[i], "-m") == argv[i]) { 00234 includeLastModified = 1; 00235 } else if (strstr(argv[i], "-defl") == argv[i]) { 00236 #if MAKEFS_SUPPORT_DEFLATE 00237 char* colon = strstr(argv[i], ":"); 00238 if (colon) { 00239 if (colon[1] != 0) { 00240 int defl_level = atoi(&colon[1]); 00241 if ((defl_level >= 0) && (defl_level <= 10)) { 00242 deflate_level = defl_level; 00243 } else { 00244 printf("ERROR: deflate level must be [0..10]" NEWLINE); 00245 exit(0); 00246 } 00247 } 00248 } 00249 deflateNonSsiFiles = 1; 00250 printf("Deflating all non-SSI files with level %d (but only if size is reduced)" NEWLINE, deflate_level); 00251 #else 00252 printf("WARNING: Deflate support is disabled\n"); 00253 #endif 00254 } else if ((strstr(argv[i], "-?")) || (strstr(argv[i], "-h"))) { 00255 print_usage(); 00256 exit(0); 00257 } 00258 } else if ((argv[i][0] == '/') && (argv[i][1] == '?') && (argv[i][2] == 0)) { 00259 print_usage(); 00260 exit(0); 00261 } else { 00262 strncpy(path, argv[i], sizeof(path)-1); 00263 path[sizeof(path)-1] = 0; 00264 } 00265 } 00266 00267 if (!check_path(path, sizeof(path))) { 00268 printf("Invalid path: \"%s\"." NEWLINE, path); 00269 exit(-1); 00270 } 00271 00272 GETCWD(appPath, MAX_PATH_LEN); 00273 /* if command line param or subdir named 'fs' not found spout usage verbiage */ 00274 if (!CHDIR_SUCCEEDED(CHDIR(path))) { 00275 /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ 00276 printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); 00277 print_usage(); 00278 exit(-1); 00279 } 00280 CHDIR(appPath); 00281 00282 printf("HTTP %sheader will %s statically included." NEWLINE, 00283 (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), 00284 (includeHttpHeader ? "be" : "not be")); 00285 00286 sprintf(curSubdir, ""); /* start off in web page's root directory - relative paths */ 00287 printf(" Processing all files in directory %s", path); 00288 if (processSubs) { 00289 printf(" and subdirectories..." NEWLINE NEWLINE); 00290 } else { 00291 printf("..." NEWLINE NEWLINE); 00292 } 00293 00294 data_file = fopen("fsdata.tmp", "wb"); 00295 if (data_file == NULL) { 00296 printf("Failed to create file \"fsdata.tmp\"\n"); 00297 exit(-1); 00298 } 00299 struct_file = fopen("fshdr.tmp", "wb"); 00300 if (struct_file == NULL) { 00301 printf("Failed to create file \"fshdr.tmp\"\n"); 00302 fclose(data_file); 00303 exit(-1); 00304 } 00305 00306 CHDIR(path); 00307 00308 fprintf(data_file, "#include \"lwip/apps/fs.h\"" NEWLINE); 00309 fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE); 00310 fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE); 00311 00312 fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); 00313 /* define FS_FILE_FLAGS_HEADER_INCLUDED to 1 if not defined (compatibility with older httpd/fs) */ 00314 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_INCLUDED" NEWLINE "#define FS_FILE_FLAGS_HEADER_INCLUDED 1" NEWLINE "#endif" NEWLINE); 00315 /* define FS_FILE_FLAGS_HEADER_PERSISTENT to 0 if not defined (compatibility with older httpd/fs: wasn't supported back then) */ 00316 fprintf(data_file, "#ifndef FS_FILE_FLAGS_HEADER_PERSISTENT" NEWLINE "#define FS_FILE_FLAGS_HEADER_PERSISTENT 0" NEWLINE "#endif" NEWLINE); 00317 00318 /* define alignment defines */ 00319 #if ALIGN_PAYLOAD 00320 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); 00321 #endif 00322 fprintf(data_file, "#ifndef FSDATA_ALIGN_PRE" NEWLINE "#define FSDATA_ALIGN_PRE" NEWLINE "#endif" NEWLINE); 00323 fprintf(data_file, "#ifndef FSDATA_ALIGN_POST" NEWLINE "#define FSDATA_ALIGN_POST" NEWLINE "#endif" NEWLINE); 00324 #if ALIGN_PAYLOAD 00325 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==2" NEWLINE "#include \"fsdata_alignment.h\"" NEWLINE "#endif" NEWLINE); 00326 #endif 00327 00328 sprintf(lastFileVar, "NULL"); 00329 00330 filesProcessed = process_sub(data_file, struct_file); 00331 00332 /* data_file now contains all of the raw data.. now append linked list of 00333 * file header structs to allow embedded app to search for a file name */ 00334 fprintf(data_file, NEWLINE NEWLINE); 00335 fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); 00336 fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); 00337 00338 fclose(data_file); 00339 fclose(struct_file); 00340 00341 CHDIR(appPath); 00342 /* append struct_file to data_file */ 00343 printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); 00344 concat_files("fsdata.tmp", "fshdr.tmp", targetfile); 00345 00346 /* if succeeded, delete the temporary files */ 00347 if (remove("fsdata.tmp") != 0) { 00348 printf("Warning: failed to delete fsdata.tmp\n"); 00349 } 00350 if (remove("fshdr.tmp") != 0) { 00351 printf("Warning: failed to delete fshdr.tmp\n"); 00352 } 00353 00354 printf(NEWLINE "Processed %d files - done." NEWLINE, filesProcessed); 00355 #if MAKEFS_SUPPORT_DEFLATE 00356 if (deflateNonSsiFiles) { 00357 printf("(Deflated total byte reduction: %d bytes -> %d bytes (%.02f%%)" NEWLINE, 00358 (int)overallDataBytes, (int)deflatedBytesReduced, (float)((deflatedBytesReduced*100.0)/overallDataBytes)); 00359 } 00360 #endif 00361 printf(NEWLINE); 00362 00363 while (first_file != NULL) { 00364 struct file_entry* fe = first_file; 00365 first_file = fe->next; 00366 free(fe); 00367 } 00368 00369 return 0; 00370 } 00371 00372 int check_path(char* path, size_t size) 00373 { 00374 size_t slen; 00375 if (path[0] == 0) { 00376 /* empty */ 00377 return 0; 00378 } 00379 slen = strlen(path); 00380 if (slen >= size) { 00381 /* not NULL-terminated */ 00382 return 0; 00383 } 00384 while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { 00385 /* path should not end with trailing backslash */ 00386 path[slen] = 0; 00387 slen--; 00388 } 00389 if (slen == 0) { 00390 return 0; 00391 } 00392 return 1; 00393 } 00394 00395 static void copy_file(const char *filename_in, FILE *fout) 00396 { 00397 FILE *fin; 00398 size_t len; 00399 void* buf; 00400 fin = fopen(filename_in, "rb"); 00401 if (fin == NULL) { 00402 printf("Failed to open file \"%s\"\n", filename_in); 00403 exit(-1); 00404 } 00405 buf = malloc(COPY_BUFSIZE); 00406 while ((len = fread(buf, 1, COPY_BUFSIZE, fin)) > 0) { 00407 fwrite(buf, 1, len, fout); 00408 } 00409 free(buf); 00410 fclose(fin); 00411 } 00412 00413 void concat_files(const char *file1, const char *file2, const char *targetfile) 00414 { 00415 FILE *fout; 00416 fout = fopen(targetfile, "wb"); 00417 if (fout == NULL) { 00418 printf("Failed to open file \"%s\"\n", targetfile); 00419 exit(-1); 00420 } 00421 copy_file(file1, fout); 00422 copy_file(file2, fout); 00423 fclose(fout); 00424 } 00425 00426 int process_sub(FILE *data_file, FILE *struct_file) 00427 { 00428 FIND_T fInfo; 00429 FIND_RET_T fret; 00430 int filesProcessed = 0; 00431 00432 if (processSubs) { 00433 /* process subs recursively */ 00434 size_t sublen = strlen(curSubdir); 00435 size_t freelen = sizeof(curSubdir) - sublen - 1; 00436 LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); 00437 fret = FINDFIRST_DIR("*", &fInfo); 00438 if (FINDFIRST_SUCCEEDED(fret)) { 00439 do { 00440 const char *curName = FIND_T_FILENAME(fInfo); 00441 if ((curName[0] == '.') || (strcmp(curName, "CVS") == 0)) { 00442 continue; 00443 } 00444 if (!FIND_T_IS_DIR(fInfo)) { 00445 continue; 00446 } 00447 if (freelen > 0) { 00448 CHDIR(curName); 00449 strncat(curSubdir, "/", freelen); 00450 strncat(curSubdir, curName, freelen - 1); 00451 curSubdir[sizeof(curSubdir) - 1] = 0; 00452 printf("processing subdirectory %s/..." NEWLINE, curSubdir); 00453 filesProcessed += process_sub(data_file, struct_file); 00454 CHDIR(".."); 00455 curSubdir[sublen] = 0; 00456 } else { 00457 printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, curName); 00458 } 00459 } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); 00460 } 00461 } 00462 00463 fret = FINDFIRST_FILE("*.*", &fInfo); 00464 if (FINDFIRST_SUCCEEDED(fret)) { 00465 /* at least one file in directory */ 00466 do { 00467 if (FIND_T_IS_FILE(fInfo)) { 00468 const char *curName = FIND_T_FILENAME(fInfo); 00469 printf("processing %s/%s..." NEWLINE, curSubdir, curName); 00470 if (process_file(data_file, struct_file, curName) < 0) { 00471 printf(NEWLINE "Error... aborting" NEWLINE); 00472 return -1; 00473 } 00474 filesProcessed++; 00475 } 00476 } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); 00477 } 00478 return filesProcessed; 00479 } 00480 00481 u8_t* get_file_data(const char* filename, int* file_size, int can_be_compressed, int* is_compressed) 00482 { 00483 FILE *inFile; 00484 size_t fsize = 0; 00485 u8_t* buf; 00486 size_t r; 00487 int rs; 00488 inFile = fopen(filename, "rb"); 00489 if (inFile == NULL) { 00490 printf("Failed to open file \"%s\"\n", filename); 00491 exit(-1); 00492 } 00493 fseek(inFile, 0, SEEK_END); 00494 rs = ftell(inFile); 00495 if (rs < 0) { 00496 printf("ftell failed with %d\n", errno); 00497 exit(-1); 00498 } 00499 fsize = (size_t)rs; 00500 fseek(inFile, 0, SEEK_SET); 00501 buf = (u8_t*)malloc(fsize); 00502 LWIP_ASSERT("buf != NULL", buf != NULL); 00503 r = fread(buf, 1, fsize, inFile); 00504 *file_size = fsize; 00505 *is_compressed = 0; 00506 #if MAKEFS_SUPPORT_DEFLATE 00507 overallDataBytes += fsize; 00508 if (deflateNonSsiFiles) { 00509 if (can_be_compressed) { 00510 if (fsize < OUT_BUF_SIZE) { 00511 u8_t* ret_buf; 00512 tdefl_status status; 00513 size_t in_bytes = fsize; 00514 size_t out_bytes = OUT_BUF_SIZE; 00515 const void *next_in = buf; 00516 void *next_out = s_outbuf; 00517 /* 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). */ 00518 mz_uint comp_flags = s_tdefl_num_probes[MZ_MIN(10, deflate_level)] | ((deflate_level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); 00519 if (!deflate_level) { 00520 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; 00521 } 00522 status = tdefl_init(&g_deflator, NULL, NULL, comp_flags); 00523 if (status != TDEFL_STATUS_OKAY) { 00524 printf("tdefl_init() failed!\n"); 00525 exit(-1); 00526 } 00527 memset(s_outbuf, 0, sizeof(s_outbuf)); 00528 status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, TDEFL_FINISH); 00529 if (status != TDEFL_STATUS_DONE) { 00530 printf("deflate failed: %d\n", status); 00531 exit(-1); 00532 } 00533 LWIP_ASSERT("out_bytes <= COPY_BUFSIZE", out_bytes <= OUT_BUF_SIZE); 00534 if (out_bytes < fsize) { 00535 ret_buf = (u8_t*)malloc(out_bytes); 00536 LWIP_ASSERT("ret_buf != NULL", ret_buf != NULL); 00537 memcpy(ret_buf, s_outbuf, out_bytes); 00538 { 00539 /* sanity-check compression be inflating and comparing to the original */ 00540 tinfl_status dec_status; 00541 tinfl_decompressor inflator; 00542 size_t dec_in_bytes = out_bytes; 00543 size_t dec_out_bytes = OUT_BUF_SIZE; 00544 next_out = s_checkbuf; 00545 00546 tinfl_init(&inflator); 00547 memset(s_checkbuf, 0, sizeof(s_checkbuf)); 00548 dec_status = tinfl_decompress(&inflator, (const mz_uint8 *)ret_buf, &dec_in_bytes, s_checkbuf, (mz_uint8 *)next_out, &dec_out_bytes, 0); 00549 LWIP_ASSERT("tinfl_decompress failed", dec_status == TINFL_STATUS_DONE); 00550 LWIP_ASSERT("tinfl_decompress size mismatch", fsize == dec_out_bytes); 00551 LWIP_ASSERT("decompressed memcmp failed", !memcmp(s_checkbuf, buf, fsize)); 00552 } 00553 /* free original buffer, use compressed data + size */ 00554 free(buf); 00555 buf = ret_buf; 00556 *file_size = out_bytes; 00557 printf(" - deflate: %d bytes -> %d bytes (%.02f%%)" NEWLINE, (int)fsize, (int)out_bytes, (float)((out_bytes*100.0)/fsize)); 00558 deflatedBytesReduced += (size_t)(fsize - out_bytes); 00559 *is_compressed = 1; 00560 } else { 00561 printf(" - uncompressed: (would be %d bytes larger using deflate)" NEWLINE, (int)(out_bytes - fsize)); 00562 } 00563 } else { 00564 printf(" - uncompressed: (file is larger than deflate bufer)" NEWLINE); 00565 } 00566 } else { 00567 printf(" - SSI file, cannot be compressed" NEWLINE); 00568 } 00569 } 00570 #else 00571 LWIP_UNUSED_ARG(can_be_compressed); 00572 #endif 00573 fclose(inFile); 00574 return buf; 00575 } 00576 00577 void process_file_data(FILE* data_file, u8_t* file_data, size_t file_size) 00578 { 00579 size_t written, i, src_off=0; 00580 00581 size_t off = 0; 00582 for (i = 0; i < file_size; i++) { 00583 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - 5); 00584 sprintf(&file_buffer_c[off], "0x%02.2x,", file_data[i]); 00585 off += 5; 00586 if ((++src_off % HEX_BYTES_PER_LINE) == 0) { 00587 LWIP_ASSERT("file_buffer_c overflow", off < sizeof(file_buffer_c) - NEWLINE_LEN); 00588 memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); 00589 off += NEWLINE_LEN; 00590 } 00591 if (off + 20 >= sizeof(file_buffer_c)) { 00592 written = fwrite(file_buffer_c, 1, off, data_file); 00593 LWIP_ASSERT("written == off", written == off); 00594 off = 0; 00595 } 00596 } 00597 written = fwrite(file_buffer_c, 1, off, data_file); 00598 LWIP_ASSERT("written == off", written == off); 00599 } 00600 00601 int write_checksums(FILE *struct_file, const char *varname, 00602 u16_t hdr_len, u16_t hdr_chksum, const u8_t* file_data, size_t file_size) 00603 { 00604 int chunk_size = TCP_MSS; 00605 int offset, src_offset; 00606 size_t len; 00607 int i = 0; 00608 #if LWIP_TCP_TIMESTAMPS 00609 /* when timestamps are used, usable space is 12 bytes less per segment */ 00610 chunk_size -= 12; 00611 #endif 00612 00613 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 00614 fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); 00615 00616 if (hdr_len > 0) { 00617 /* add checksum for HTTP header */ 00618 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); 00619 i++; 00620 } 00621 src_offset = 0; 00622 for (offset = hdr_len; ; offset += len) { 00623 unsigned short chksum; 00624 void* data = (void*)&file_data[src_offset]; 00625 len = LWIP_MIN(chunk_size, (int)file_size - src_offset); 00626 if (len == 0) { 00627 break; 00628 } 00629 chksum = ~inet_chksum(data, (u16_t)len); 00630 /* add checksum for data */ 00631 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len); 00632 i++; 00633 } 00634 fprintf(struct_file, "};" NEWLINE); 00635 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 00636 return i; 00637 } 00638 00639 static int is_valid_char_for_c_var(char x) 00640 { 00641 if (((x >= 'A') && (x <= 'Z')) || 00642 ((x >= 'a') && (x <= 'z')) || 00643 ((x >= '0') && (x <= '9')) || 00644 (x == '_')) { 00645 return 1; 00646 } 00647 return 0; 00648 } 00649 00650 static void fix_filename_for_c(char* qualifiedName, size_t max_len) 00651 { 00652 struct file_entry* f; 00653 size_t len = strlen(qualifiedName); 00654 char *new_name = (char*)malloc(len + 2); 00655 int filename_ok; 00656 int cnt = 0; 00657 size_t i; 00658 if (len + 3 == max_len) { 00659 printf("File name too long: \"%s\"\n", qualifiedName); 00660 exit(-1); 00661 } 00662 strcpy(new_name, qualifiedName); 00663 for (i = 0; i < len; i++) { 00664 if (!is_valid_char_for_c_var(new_name[i])) { 00665 new_name[i] = '_'; 00666 } 00667 } 00668 do { 00669 filename_ok = 1; 00670 for (f = first_file; f != NULL; f = f->next) { 00671 if (!strcmp(f->filename_c, new_name)) { 00672 filename_ok = 0; 00673 cnt++; 00674 /* try next unique file name */ 00675 sprintf(&new_name[len], "%d", cnt); 00676 break; 00677 } 00678 } 00679 } while (!filename_ok && (cnt < 999)); 00680 if (!filename_ok) { 00681 printf("Failed to get unique file name: \"%s\"\n", qualifiedName); 00682 exit(-1); 00683 } 00684 strcpy(qualifiedName, new_name); 00685 free(new_name); 00686 } 00687 00688 static void register_filename(const char* qualifiedName) 00689 { 00690 struct file_entry* fe = (struct file_entry*)malloc(sizeof(struct file_entry)); 00691 fe->filename_c = strdup(qualifiedName); 00692 fe->next = NULL; 00693 if (first_file == NULL) { 00694 first_file = last_file = fe; 00695 } else { 00696 last_file->next = fe; 00697 last_file = fe; 00698 } 00699 } 00700 00701 int is_ssi_file(const char* filename) 00702 { 00703 size_t loop; 00704 for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { 00705 if (strstr(filename, g_pcSSIExtensions[loop])) { 00706 return 1; 00707 } 00708 } 00709 return 0; 00710 } 00711 00712 int process_file(FILE *data_file, FILE *struct_file, const char *filename) 00713 { 00714 char varname[MAX_PATH_LEN]; 00715 int i = 0; 00716 char qualifiedName[MAX_PATH_LEN]; 00717 int file_size; 00718 u16_t http_hdr_chksum = 0; 00719 u16_t http_hdr_len = 0; 00720 int chksum_count = 0; 00721 u8_t flags = 0; 00722 const char* flags_str; 00723 u8_t has_content_len; 00724 u8_t* file_data; 00725 int is_compressed = 0; 00726 00727 /* create qualified name (@todo: prepend slash or not?) */ 00728 sprintf(qualifiedName,"%s/%s", curSubdir, filename); 00729 /* create C variable name */ 00730 strcpy(varname, qualifiedName); 00731 /* convert slashes & dots to underscores */ 00732 fix_filename_for_c(varname, MAX_PATH_LEN); 00733 register_filename(varname); 00734 #if ALIGN_PAYLOAD 00735 /* to force even alignment of array, type 1 */ 00736 fprintf(data_file, "#if FSDATA_FILE_ALIGNMENT==1" NEWLINE); 00737 fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); 00738 fprintf(data_file, "#endif" NEWLINE); 00739 #endif /* ALIGN_PAYLOAD */ 00740 fprintf(data_file, "static const unsigned char FSDATA_ALIGN_PRE data_%s[] FSDATA_ALIGN_POST = {" NEWLINE, varname); 00741 /* encode source file name (used by file system, not returned to browser) */ 00742 fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1); 00743 file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i); 00744 #if ALIGN_PAYLOAD 00745 /* pad to even number of bytes to assure payload is on aligned boundary */ 00746 while(i % PAYLOAD_ALIGNMENT != 0) { 00747 fprintf(data_file, "0x%02.2x,", 0); 00748 i++; 00749 } 00750 #endif /* ALIGN_PAYLOAD */ 00751 fprintf(data_file, NEWLINE); 00752 00753 has_content_len = !is_ssi_file(filename); 00754 file_data = get_file_data(filename, &file_size, includeHttpHeader && has_content_len, &is_compressed); 00755 if (includeHttpHeader) { 00756 file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum, has_content_len, is_compressed); 00757 flags = FS_FILE_FLAGS_HEADER_INCLUDED; 00758 if (has_content_len) { 00759 flags |= FS_FILE_FLAGS_HEADER_PERSISTENT; 00760 } 00761 } 00762 if (precalcChksum) { 00763 chksum_count = write_checksums(struct_file, varname, http_hdr_len, http_hdr_chksum, file_data, file_size); 00764 } 00765 00766 /* build declaration of struct fsdata_file in temp file */ 00767 fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); 00768 fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); 00769 fprintf(struct_file, "data_%s," NEWLINE, varname); 00770 fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); 00771 fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); 00772 switch(flags) 00773 { 00774 case(FS_FILE_FLAGS_HEADER_INCLUDED): 00775 flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED"; 00776 break; 00777 case(FS_FILE_FLAGS_HEADER_PERSISTENT): 00778 flags_str = "FS_FILE_FLAGS_HEADER_PERSISTENT"; 00779 break; 00780 case(FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT): 00781 flags_str = "FS_FILE_FLAGS_HEADER_INCLUDED | FS_FILE_FLAGS_HEADER_PERSISTENT"; 00782 break; 00783 default: 00784 flags_str = "0"; 00785 break; 00786 } 00787 fprintf(struct_file, "%s," NEWLINE, flags_str); 00788 if (precalcChksum) { 00789 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); 00790 fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); 00791 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); 00792 } 00793 fprintf(struct_file, "}};" NEWLINE NEWLINE); 00794 strcpy(lastFileVar, varname); 00795 00796 /* write actual file contents */ 00797 i = 0; 00798 fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); 00799 process_file_data(data_file, file_data, file_size); 00800 fprintf(data_file, "};" NEWLINE NEWLINE); 00801 free(file_data); 00802 return 0; 00803 } 00804 00805 int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, 00806 u16_t *http_hdr_chksum, u8_t provide_content_len, int is_compressed) 00807 { 00808 int i = 0; 00809 int response_type = HTTP_HDR_OK; 00810 const char* file_type; 00811 const char *cur_string; 00812 size_t cur_len; 00813 int written = 0; 00814 size_t hdr_len = 0; 00815 u16_t acc; 00816 const char *file_ext; 00817 int j; 00818 u8_t provide_last_modified = includeLastModified; 00819 00820 memset(hdr_buf, 0, sizeof(hdr_buf)); 00821 00822 if (useHttp11) { 00823 response_type = HTTP_HDR_OK_11; 00824 } 00825 00826 fprintf(data_file, NEWLINE "/* HTTP header */"); 00827 if (strstr(filename, "404") == filename) { 00828 response_type = HTTP_HDR_NOT_FOUND; 00829 if (useHttp11) { 00830 response_type = HTTP_HDR_NOT_FOUND_11; 00831 } 00832 } else if (strstr(filename, "400") == filename) { 00833 response_type = HTTP_HDR_BAD_REQUEST; 00834 if (useHttp11) { 00835 response_type = HTTP_HDR_BAD_REQUEST_11; 00836 } 00837 } else if (strstr(filename, "501") == filename) { 00838 response_type = HTTP_HDR_NOT_IMPL; 00839 if (useHttp11) { 00840 response_type = HTTP_HDR_NOT_IMPL_11; 00841 } 00842 } 00843 cur_string = g_psHTTPHeaderStrings[response_type]; 00844 cur_len = strlen(cur_string); 00845 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 00846 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00847 i = 0; 00848 if (precalcChksum) { 00849 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00850 hdr_len += cur_len; 00851 } 00852 00853 cur_string = serverID; 00854 cur_len = strlen(cur_string); 00855 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 00856 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00857 i = 0; 00858 if (precalcChksum) { 00859 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00860 hdr_len += cur_len; 00861 } 00862 00863 file_ext = filename; 00864 if (file_ext != NULL) { 00865 while(strstr(file_ext, ".") != NULL) { 00866 file_ext = strstr(file_ext, "."); 00867 file_ext++; 00868 } 00869 } 00870 if ((file_ext == NULL) || (*file_ext == 0)) { 00871 printf("failed to get extension for file \"%s\", using default.\n", filename); 00872 file_type = HTTP_HDR_DEFAULT_TYPE; 00873 } else { 00874 file_type = NULL; 00875 for (j = 0; j < NUM_HTTP_HEADERS; j++) { 00876 if (!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { 00877 file_type = g_psHTTPHeaders[j].content_type; 00878 break; 00879 } 00880 } 00881 if (file_type == NULL) { 00882 printf("failed to get file type for extension \"%s\", using default.\n", file_ext); 00883 file_type = HTTP_HDR_DEFAULT_TYPE; 00884 } 00885 } 00886 00887 /* Content-Length is used for persistent connections in HTTP/1.1 but also for 00888 download progress in older versions 00889 @todo: just use a big-enough buffer and let the HTTPD send spaces? */ 00890 if (provide_content_len) { 00891 char intbuf[MAX_PATH_LEN]; 00892 int content_len = file_size; 00893 memset(intbuf, 0, sizeof(intbuf)); 00894 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; 00895 cur_len = strlen(cur_string); 00896 fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2); 00897 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00898 if (precalcChksum) { 00899 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00900 hdr_len += cur_len; 00901 } 00902 00903 _itoa(content_len, intbuf, 10); 00904 strcat(intbuf, "\r\n"); 00905 cur_len = strlen(intbuf); 00906 written += file_put_ascii(data_file, intbuf, cur_len, &i); 00907 i = 0; 00908 if (precalcChksum) { 00909 memcpy(&hdr_buf[hdr_len], intbuf, cur_len); 00910 hdr_len += cur_len; 00911 } 00912 } 00913 if (provide_last_modified) { 00914 char modbuf[256]; 00915 struct stat stat_data; 00916 struct tm* t; 00917 memset(modbuf, 0, sizeof(modbuf)); 00918 memset(&stat_data, 0, sizeof(stat_data)); 00919 cur_string = modbuf; 00920 strcpy(modbuf, "Last-Modified: "); 00921 if (stat(filename, &stat_data) != 0) { 00922 printf("stat(%s) failed with error %d\n", filename, errno); 00923 exit(-1); 00924 } 00925 t = gmtime(&stat_data.st_mtime); 00926 if (t == NULL) { 00927 printf("gmtime() failed with error %d\n", errno); 00928 exit(-1); 00929 } 00930 strftime(&modbuf[15], sizeof(modbuf)-15, "%a, %d %b %Y %H:%M:%S GMT", t); 00931 cur_len = strlen(cur_string); 00932 fprintf(data_file, NEWLINE "/* \"%s\"\r\n\" (%d+ bytes) */" NEWLINE, cur_string, cur_len+2); 00933 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00934 if (precalcChksum) { 00935 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00936 hdr_len += cur_len; 00937 } 00938 00939 modbuf[0] = 0; 00940 strcat(modbuf, "\r\n"); 00941 cur_len = strlen(modbuf); 00942 written += file_put_ascii(data_file, modbuf, cur_len, &i); 00943 i = 0; 00944 if (precalcChksum) { 00945 memcpy(&hdr_buf[hdr_len], modbuf, cur_len); 00946 hdr_len += cur_len; 00947 } 00948 } 00949 00950 /* HTTP/1.1 implements persistent connections */ 00951 if (useHttp11) { 00952 if (provide_content_len) { 00953 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; 00954 } else { 00955 /* no Content-Length available, so a persistent connection is no possible 00956 because the client does not know the data length */ 00957 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; 00958 } 00959 cur_len = strlen(cur_string); 00960 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 00961 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00962 i = 0; 00963 if (precalcChksum) { 00964 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00965 hdr_len += cur_len; 00966 } 00967 } 00968 00969 #if MAKEFS_SUPPORT_DEFLATE 00970 if (is_compressed) { 00971 /* tell the client about the deflate encoding */ 00972 LWIP_ASSERT("error", deflateNonSsiFiles); 00973 cur_string = "Content-Encoding: deflate\r\n"; 00974 cur_len = strlen(cur_string); 00975 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 00976 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00977 i = 0; 00978 } 00979 #else 00980 LWIP_UNUSED_ARG(is_compressed); 00981 #endif 00982 00983 /* write content-type, ATTENTION: this includes the double-CRLF! */ 00984 cur_string = file_type; 00985 cur_len = strlen(cur_string); 00986 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); 00987 written += file_put_ascii(data_file, cur_string, cur_len, &i); 00988 i = 0; 00989 00990 /* ATTENTION: headers are done now (double-CRLF has been written!) */ 00991 00992 if (precalcChksum) { 00993 memcpy(&hdr_buf[hdr_len], cur_string, cur_len); 00994 hdr_len += cur_len; 00995 00996 LWIP_ASSERT("hdr_len <= 0xffff", hdr_len <= 0xffff); 00997 LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); 00998 acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); 00999 *http_hdr_len = (u16_t)hdr_len; 01000 *http_hdr_chksum = acc; 01001 } 01002 01003 return written; 01004 } 01005 01006 int file_put_ascii(FILE *file, const char* ascii_string, int len, int *i) 01007 { 01008 int x; 01009 for (x = 0; x < len; x++) { 01010 unsigned char cur = ascii_string[x]; 01011 fprintf(file, "0x%02.2x,", cur); 01012 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 01013 fprintf(file, NEWLINE); 01014 } 01015 } 01016 return len; 01017 } 01018 01019 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) 01020 { 01021 int x; 01022 int idx = 0; 01023 for (x = 0; x < len; x++) { 01024 unsigned char cur = ascii_string[x]; 01025 sprintf(&buf[idx], "0x%02.2x,", cur); 01026 idx += 5; 01027 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { 01028 sprintf(&buf[idx], NEWLINE); 01029 idx += NEWLINE_LEN; 01030 } 01031 } 01032 return len; 01033 }
Generated on Tue Jul 12 2022 13:15:53 by
