Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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