ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_makefsdata.c Source File

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 }