2 * makefsdata: Converts a directory structure for use with the lwIP httpd.
4 * This file is part of the lwIP TCP/IP stack.
6 * Author: Jim Pettinato
10 * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and
11 * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments
17 #define WIN32_LEAN_AND_MEAN
25 /* Compatibility defines Win32 vs. DOS */
28 #define FIND_T WIN32_FIND_DATAA
29 #define FIND_T_FILENAME(fInfo) (fInfo.cFileName)
30 #define FIND_T_IS_DIR(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
31 #define FIND_T_IS_FILE(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
32 #define FIND_RET_T HANDLE
33 #define FINDFIRST_FILE(path, result) FindFirstFileA(path, result)
34 #define FINDFIRST_DIR(path, result) FindFirstFileA(path, result)
35 #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result)
36 #define FINDFIRST_SUCCEEDED(ret) (ret != INVALID_HANDLE_VALUE)
37 #define FINDNEXT_SUCCEEDED(ret) (ret == TRUE)
39 #define GETCWD(path, len) GetCurrentDirectoryA(len, path)
40 #define CHDIR(path) SetCurrentDirectoryA(path)
42 #define NEWLINE "\r\n"
47 #define FIND_T struct fflbk
48 #define FIND_T_FILENAME(fInfo) (fInfo.ff_name)
49 #define FIND_T_IS_DIR(fInfo) ((fInfo.ff_attrib & FA_DIREC) == FA_DIREC)
50 #define FIND_T_IS_FILE(fInfo) (1)
51 #define FIND_RET_T int
52 #define FINDFIRST_FILE(path, result) findfirst(path, result, FA_ARCH)
53 #define FINDFIRST_DIR(path, result) findfirst(path, result, FA_DIREC)
54 #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result)
55 #define FINDFIRST_SUCCEEDED(ret) (ret == 0)
56 #define FINDNEXT_SUCCEEDED(ret) (ret == 0)
58 #define GETCWD(path, len) getcwd(path, len)
59 #define CHDIR(path) chdir(path)
63 /* define this to get the header variables we use to build HTTP headers */
64 #define LWIP_HTTPD_DYNAMIC_HEADERS 1
65 #include "../httpd_structs.h"
67 #include "../../../lwip-1.4.0/src/core/ipv4/inet_chksum.c"
68 #include "../../../lwip-1.4.0/src/core/def.c"
70 /** (Your server name here) */
71 const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n";
73 /* change this to suit your MEM_ALIGNMENT */
74 #define PAYLOAD_ALIGNMENT 4
75 /* set this to 0 to prevent aligning payload */
76 #define ALIGN_PAYLOAD 1
77 /* define this to a type that has the required alignment */
78 #define PAYLOAD_ALIGN_TYPE "unsigned int"
79 static int payload_alingment_dummy_counter = 0;
81 #define HEX_BYTES_PER_LINE 16
83 #define MAX_PATH_LEN 256
85 #define COPY_BUFSIZE 10240
87 int process_sub(FILE *data_file, FILE *struct_file);
88 int process_file(FILE *data_file, FILE *struct_file, const char *filename);
89 int file_write_http_header(FILE *data_file, const char *filename, int file_size,
90 u16_t *http_hdr_len, u16_t *http_hdr_chksum);
91 int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i);
92 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i);
93 void concat_files(const char *file1, const char *file2, const char *targetfile);
95 static unsigned char file_buffer_raw[COPY_BUFSIZE];
96 /* 5 bytes per char + 3 bytes per line */
97 static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)];
99 char curSubdir[MAX_PATH_LEN];
100 char lastFileVar[MAX_PATH_LEN];
103 unsigned char processSubs = 1;
104 unsigned char includeHttpHeader = 1;
105 unsigned char useHttp11 = 0;
106 unsigned char precalcChksum = 0;
108 int main(int argc, char *argv[])
112 char path[MAX_PATH_LEN];
113 char appPath[MAX_PATH_LEN];
118 char targetfile[MAX_PATH_LEN];
119 strcpy(targetfile, "fsdata.c");
121 memset(path, 0, sizeof(path));
122 memset(appPath, 0, sizeof(appPath));
124 printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE);
125 printf(" by Jim Pettinato - circa 2003 " NEWLINE);
126 printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE);
129 for(i = 1; i < argc; i++) {
130 if (argv[i][0] == '-') {
131 if (strstr(argv[i], "-s")) {
133 } else if (strstr(argv[i], "-e")) {
134 includeHttpHeader = 0;
135 } else if (strstr(argv[i], "-11")) {
137 } else if (strstr(argv[i], "-c")) {
139 } else if((argv[i][1] == 'f') && (argv[i][2] == ':')) {
140 strcpy(targetfile, &argv[i][3]);
141 printf("Writing to file \"%s\"\n", targetfile);
144 strcpy(path, argv[i]);
148 /* if command line param or subdir named 'fs' not found spout usage verbiage */
149 fret = FINDFIRST_DIR(path, &fInfo);
150 if (!FINDFIRST_SUCCEEDED(fret)) {
151 /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */
152 printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path);
153 printf(" Usage: htmlgen [targetdir] [-s] [-i] [-f:<filename>]" NEWLINE NEWLINE);
154 printf(" targetdir: relative or absolute path to files to convert" NEWLINE);
155 printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE);
156 printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE);
157 printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE);
158 printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE);
159 printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE);
160 printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE);
161 printf(" process files in subdirectory 'fs'" NEWLINE);
165 printf("HTTP %sheader will %s statically included." NEWLINE,
166 (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""),
167 (includeHttpHeader ? "be" : "not be"));
169 sprintf(curSubdir, ""); /* start off in web page's root directory - relative paths */
170 printf(" Processing all files in directory %s", path);
172 printf(" and subdirectories..." NEWLINE NEWLINE);
174 printf("..." NEWLINE NEWLINE);
177 GETCWD(appPath, MAX_PATH_LEN);
178 data_file = fopen("fsdata.tmp", "wb");
179 if (data_file == NULL) {
180 printf("Failed to create file \"fsdata.tmp\"\n");
183 struct_file = fopen("fshdr.tmp", "wb");
184 if (struct_file == NULL) {
185 printf("Failed to create file \"fshdr.tmp\"\n");
191 fprintf(data_file, "#include \"fs.h\"" NEWLINE);
192 fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE);
193 fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE);
195 fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE);
197 sprintf(lastFileVar, "NULL");
199 filesProcessed = process_sub(data_file, struct_file);
201 /* data_file now contains all of the raw data.. now append linked list of
202 * file header structs to allow embedded app to search for a file name */
203 fprintf(data_file, NEWLINE NEWLINE);
204 fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar);
205 fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed);
211 /* append struct_file to data_file */
212 printf(NEWLINE "Creating target file..." NEWLINE NEWLINE);
213 concat_files("fsdata.tmp", "fshdr.tmp", targetfile);
215 /* if succeeded, delete the temporary files */
216 remove("fsdata.tmp");
219 printf(NEWLINE "Processed %d files - done." NEWLINE NEWLINE, filesProcessed);
224 static void copy_file(const char *filename_in, FILE *fout)
228 fin = fopen(filename_in, "rb");
230 printf("Failed to open file \"%s\"\n", filename_in);
234 while((len = fread(file_buffer_raw, 1, COPY_BUFSIZE, fin)) > 0)
236 fwrite(file_buffer_raw, 1, len, fout);
241 void concat_files(const char *file1, const char *file2, const char *targetfile)
244 fout = fopen(targetfile, "wb");
246 printf("Failed to open file \"%s\"\n", targetfile);
249 copy_file(file1, fout);
250 copy_file(file2, fout);
254 int process_sub(FILE *data_file, FILE *struct_file)
258 int filesProcessed = 0;
259 char oldSubdir[MAX_PATH_LEN];
262 /* process subs recursively */
263 strcpy(oldSubdir, curSubdir);
264 fret = FINDFIRST_DIR("*", &fInfo);
265 if (FINDFIRST_SUCCEEDED(fret)) {
267 const char *curName = FIND_T_FILENAME(fInfo);
268 if (curName == NULL) continue;
269 if (curName[0] == '.') continue;
270 if (strcmp(curName, "CVS") == 0) continue;
271 if (!FIND_T_IS_DIR(fInfo)) continue;
273 strcat(curSubdir, "/");
274 strcat(curSubdir, curName);
275 printf(NEWLINE "processing subdirectory %s/..." NEWLINE, curSubdir);
276 filesProcessed += process_sub(data_file, struct_file);
278 strcpy(curSubdir, oldSubdir);
279 } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo)));
283 fret = FINDFIRST_FILE("*.*", &fInfo);
284 if (FINDFIRST_SUCCEEDED(fret)) {
285 /* at least one file in directory */
287 if (FIND_T_IS_FILE(fInfo)) {
288 const char *curName = FIND_T_FILENAME(fInfo);
289 printf("processing %s/%s..." NEWLINE, curSubdir, curName);
290 if (process_file(data_file, struct_file, curName) < 0) {
291 printf(NEWLINE "Error... aborting" NEWLINE);
296 } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo)));
298 return filesProcessed;
301 int get_file_size(const char* filename)
305 inFile = fopen(filename, "rb");
306 if (inFile == NULL) {
307 printf("Failed to open file \"%s\"\n", filename);
310 fseek(inFile, 0, SEEK_END);
311 file_size = ftell(inFile);
316 void process_file_data(const char *filename, FILE *data_file)
319 size_t len, written, i, src_off=0;
321 source_file = fopen(filename, "rb");
325 len = fread(file_buffer_raw, 1, COPY_BUFSIZE, source_file);
327 for (i = 0; i < len; i++) {
328 sprintf(&file_buffer_c[off], "0x%02.2x,", file_buffer_raw[i]);
330 if ((++src_off % HEX_BYTES_PER_LINE) == 0) {
331 memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN);
335 written = fwrite(file_buffer_c, 1, off, data_file);
341 int write_checksums(FILE *struct_file, const char *filename, const char *varname,
342 u16_t hdr_len, u16_t hdr_chksum)
344 int chunk_size = TCP_MSS;
349 #if LWIP_TCP_TIMESTAMPS
350 /* when timestamps are used, usable space is 12 bytes less per segment */
354 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
355 fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname);
357 memset(file_buffer_raw, 0xab, sizeof(file_buffer_raw));
358 f = fopen(filename, "rb");
359 if (f == INVALID_HANDLE_VALUE) {
360 printf("Failed to open file \"%s\"\n", filename);
364 /* add checksum for HTTP header */
365 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len);
368 for (offset = hdr_len; ; offset += len) {
369 unsigned short chksum;
370 len = fread(file_buffer_raw, 1, chunk_size, f);
374 chksum = ~inet_chksum(file_buffer_raw, (u16_t)len);
375 /* add checksum for data */
376 fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len);
380 fprintf(struct_file, "};" NEWLINE);
381 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE);
385 int process_file(FILE *data_file, FILE *struct_file, const char *filename)
388 char varname[MAX_PATH_LEN];
390 char qualifiedName[MAX_PATH_LEN];
392 u16_t http_hdr_chksum = 0;
393 u16_t http_hdr_len = 0;
394 int chksum_count = 0;
396 /* create qualified name (TODO: prepend slash or not?) */
397 sprintf(qualifiedName,"%s/%s", curSubdir, filename);
398 /* create C variable name */
399 strcpy(varname, qualifiedName);
400 /* convert slashes & dots to underscores */
401 while ((pch = strpbrk(varname, "./\\")) != NULL) {
405 /* to force even alignment of array */
406 fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++);
407 #endif /* ALIGN_PAYLOAD */
408 fprintf(data_file, "static const unsigned char data_%s[] = {" NEWLINE, varname);
409 /* encode source file name (used by file system, not returned to browser) */
410 fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1);
411 file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i);
413 /* pad to even number of bytes to assure payload is on aligned boundary */
414 while(i % PAYLOAD_ALIGNMENT != 0) {
415 fprintf(data_file, "0x%02.2x,", 0);
418 #endif /* ALIGN_PAYLOAD */
419 fprintf(data_file, NEWLINE);
421 file_size = get_file_size(filename);
422 if (includeHttpHeader) {
423 file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum);
426 chksum_count = write_checksums(struct_file, filename, varname, http_hdr_len, http_hdr_chksum);
429 /* build declaration of struct fsdata_file in temp file */
430 fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname);
431 fprintf(struct_file, "file_%s," NEWLINE, lastFileVar);
432 fprintf(struct_file, "data_%s," NEWLINE, varname);
433 fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i);
434 fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i);
435 fprintf(struct_file, "%d," NEWLINE, includeHttpHeader);
437 fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE);
438 fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname);
439 fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE);
441 fprintf(struct_file, "}};" NEWLINE NEWLINE);
442 strcpy(lastFileVar, varname);
444 /* write actual file contents */
446 fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size);
447 process_file_data(filename, data_file);
448 fprintf(data_file, "};" NEWLINE NEWLINE);
453 int file_write_http_header(FILE *data_file, const char *filename, int file_size,
454 u16_t *http_hdr_len, u16_t *http_hdr_chksum)
457 int response_type = HTTP_HDR_OK;
458 int file_type = HTTP_HDR_DEFAULT_TYPE;
459 const char *cur_string;
464 const char *file_ext;
467 memset(hdr_buf, 0, sizeof(hdr_buf));
470 response_type = HTTP_HDR_OK_11;
473 fprintf(data_file, NEWLINE "/* HTTP header */");
474 if (strstr(filename, "404") == filename) {
475 response_type = HTTP_HDR_NOT_FOUND;
477 response_type = HTTP_HDR_NOT_FOUND_11;
479 } else if (strstr(filename, "400") == filename) {
480 response_type = HTTP_HDR_BAD_REQUEST;
482 response_type = HTTP_HDR_BAD_REQUEST_11;
484 } else if (strstr(filename, "501") == filename) {
485 response_type = HTTP_HDR_NOT_IMPL;
487 response_type = HTTP_HDR_NOT_IMPL_11;
490 cur_string = g_psHTTPHeaderStrings[response_type];
491 cur_len = strlen(cur_string);
492 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
493 written += file_put_ascii(data_file, cur_string, cur_len, &i);
496 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
500 cur_string = serverID;
501 cur_len = strlen(cur_string);
502 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
503 written += file_put_ascii(data_file, cur_string, cur_len, &i);
506 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
511 while(strstr(file_ext, ".") != NULL) {
512 file_ext = strstr(file_ext, ".");
515 if((file_ext == NULL) || (*file_ext == 0)) {
516 printf("failed to get extension for file \"%s\", using default.\n", filename);
518 for(j = 0; j < NUM_HTTP_HEADERS; j++) {
519 if(!strcmp(file_ext, g_psHTTPHeaders[j].extension)) {
520 file_type = g_psHTTPHeaders[j].headerIndex;
524 if (j >= NUM_HTTP_HEADERS) {
525 printf("failed to get file type for extension \"%s\", using default.\n", file_ext);
526 file_type = HTTP_HDR_DEFAULT_TYPE;
531 char intbuf[MAX_PATH_LEN];
532 memset(intbuf, 0, sizeof(intbuf));
534 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH];
535 cur_len = strlen(cur_string);
536 fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, file_size, cur_len+2);
537 written += file_put_ascii(data_file, cur_string, cur_len, &i);
539 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
543 _itoa(file_size, intbuf, 10);
544 strcat(intbuf, "\r\n");
545 cur_len = strlen(intbuf);
546 written += file_put_ascii(data_file, intbuf, cur_len, &i);
549 memcpy(&hdr_buf[hdr_len], intbuf, cur_len);
553 cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE];
554 cur_len = strlen(cur_string);
555 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
556 written += file_put_ascii(data_file, cur_string, cur_len, &i);
559 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
564 cur_string = g_psHTTPHeaderStrings[file_type];
565 cur_len = strlen(cur_string);
566 fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len);
567 written += file_put_ascii(data_file, cur_string, cur_len, &i);
570 memcpy(&hdr_buf[hdr_len], cur_string, cur_len);
573 LWIP_ASSERT("hdr_len <= 0xffff", hdr_len <= 0xffff);
574 LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len);
575 acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len);
576 *http_hdr_len = (u16_t)hdr_len;
577 *http_hdr_chksum = acc;
583 int file_put_ascii(FILE *file, const char* ascii_string, int len, int *i)
586 for(x = 0; x < len; x++) {
587 unsigned char cur = ascii_string[x];
588 fprintf(file, "0x%02.2x,", cur);
589 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) {
590 fprintf(file, NEWLINE);
596 int s_put_ascii(char *buf, const char *ascii_string, int len, int *i)
600 for(x = 0; x < len; x++) {
601 unsigned char cur = ascii_string[x];
602 sprintf(&buf[idx], "0x%02.2x,", cur);
604 if ((++(*i) % HEX_BYTES_PER_LINE) == 0) {
605 sprintf(&buf[idx], NEWLINE);