1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Tiny Embedded JavaScript parser 19 * 20 * Copyright 2003, ASUSTeK Inc. 21 * All Rights Reserved. 22 * 23 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of ASUSTeK Inc.; 24 * the contents of this file may not be disclosed to third parties, copied 25 * or duplicated in any form, in whole or in part, without the prior 26 * written permission of ASUSTeK Inc.. 27 * 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <stdarg.h> 33#include <string.h> 34#include <ctype.h> 35 36#include <httpd.h> 37#include <bcmnvram.h> 38#include <rtconfig.h> 39 40static char * get_arg(char *args, char **next); 41static void call(char *func, FILE *stream); 42 43/* Look for unquoted character within a string */ 44static char * 45unqstrstr(char *haystack, char *needle) 46{ 47 char *cur; 48 int q; 49 50 for (cur = haystack, q = 0; 51 cur < &haystack[strlen(haystack)] && !(!q && !strncmp(needle, cur, strlen(needle))); 52 cur++) { 53 if (*cur == '"') 54 q ? q-- : q++; 55 } 56 return (cur < &haystack[strlen(haystack)]) ? cur : NULL; 57} 58 59static char * 60get_arg(char *args, char **next) 61{ 62 char *arg, *end; 63 64 /* Parse out arg, ... */ 65 if (!(end = unqstrstr(args, ","))) { 66 end = args + strlen(args); 67 *next = NULL; 68 } else 69 *next = end + 1; 70 71 /* Skip whitespace and quotation marks on either end of arg */ 72 for (arg = args; isspace((int)*arg) || *arg == '"'; arg++); 73 for (*end-- = '\0'; isspace((int)*end) || *end == '"'; end--) 74 *end = '\0'; 75 76 return arg; 77} 78 79static void 80call(char *func, FILE *stream) 81{ 82 char *args, *end, *next; 83 int argc; 84 char * argv[16]; 85 struct ej_handler *handler; 86 87 /* Parse out ( args ) */ 88 if (!(args = strchr(func, '('))) 89 return; 90 if (!(end = unqstrstr(func, ")"))) 91 return; 92 *args++ = *end = '\0'; 93 94 /* Set up argv list */ 95 for (argc = 0; argc < 16 && args && *args; argc++, args = next) { 96 if (!(argv[argc] = get_arg(args, &next))) 97 break; 98 } 99 100 /* Call handler */ 101 for (handler = &ej_handlers[0]; handler->pattern; handler++) { 102// if (strncmp(handler->pattern, func, strlen(handler->pattern)) == 0) 103 if (strcmp(handler->pattern, func) == 0) 104 handler->output(0, stream, argc, argv); 105 } 106} 107#ifdef TRANSLATE_ON_FLY 108static const char *asp_mark1 = "<%", *asp_mark2 = "%>", *kw_mark1 = "<#", *kw_mark2 = "#>"; 109 110// Call this function if and only if we can read whole <%....%> pattern. 111static char * 112process_asp (char *s, char *e, FILE *f) 113{ 114 char *func = NULL, *end = NULL; 115 116 if (s == NULL || e == NULL || f == NULL || s >= e) { 117 return NULL; 118 } 119 120 for (func = s; func < e; func = end) { 121 /* Skip initial whitespace */ 122 for (; isspace((int)*func); func++); 123 if (!(end = unqstrstr(func, ";"))) 124 break; 125 *end++ = '\0'; 126 127 /* Call function */ 128 call(func, f); 129 130 // skip asp_mark2 131 end = e + strlen (asp_mark2); 132 break; 133 } 134 135 return end; 136} 137 138// Call this function if and only if we can read whole <#....#> pattern. 139static char * 140translate_lang (char *s, char *e, FILE *f, kw_t *pkw) 141{ 142 char *end = NULL, *name = NULL, *desc = NULL; 143 if (s == NULL || e == NULL || f == NULL || pkw == NULL || s >= e) { 144 return NULL; 145 } 146 147 for (name = s; name < e; name = end) { 148 /* Skip initial whitespace */ 149 for (; isspace((int)*name); name++); 150 if (!(end = strstr(name, kw_mark2))) 151 break; 152 *end++ = '='; // '#' --> '=', search_desc() need '=' 153 *end++ = '\0'; // '>' --> '\0' 154 155 desc = search_desc (pkw, name); 156 if (desc != NULL) { 157#ifdef RTCONFIG_ODMPID 158 static char pattern1[2048]; 159 char *p_PID_STR = NULL; 160 char *PID_STR = nvram_safe_get("productid"); 161 char *ODM_PID_STR = nvram_safe_get("odmpid"); 162 char *pSrc, *pDest; 163 int pid_len, odm_len; 164 165 pid_len = strlen(PID_STR); 166 odm_len = strlen(ODM_PID_STR); 167 168 if (odm_len && strcmp(PID_STR, ODM_PID_STR) != 0) { 169 pSrc = desc; 170 pDest = pattern1; 171 while((p_PID_STR = strstr(pSrc, PID_STR))) 172 { 173 memcpy(pDest, pSrc, p_PID_STR - pSrc); 174 pDest += (p_PID_STR - pSrc); 175 pSrc = p_PID_STR + pid_len; 176 177 memcpy(pDest, ODM_PID_STR, odm_len); 178 pDest += odm_len; 179 } 180 if(pDest != pattern1) 181 { 182 strcpy(pDest, pSrc); 183 desc = pattern1; 184 } 185 } 186#endif 187 fprintf (f, "%s", desc); 188 } 189 190 // skip kw_mark2 191 end = e + strlen (kw_mark2); 192 break; 193 } 194 195 return end; 196} 197 198#ifdef TRANSLATE_ON_FLY 199extern char Accept_Language[]; 200extern int is_firsttime(void); 201#endif 202 203// This translation engine can not process <%...%> interlace with <#...#> 204void 205do_ej(char *path, FILE *stream) 206{ 207#define PATTERN_LENGTH 1024 208#define FRAG_SIZE 128 209#define RESERVE_SIZE 4 210 int frag_size = FRAG_SIZE; 211 int pattern_size = PATTERN_LENGTH - RESERVE_SIZE; 212 char pat_buf[PATTERN_LENGTH]; 213 char *pattern = pat_buf, *asp = NULL, *asp_end = NULL, *key = NULL, *key_end = NULL; 214 char *start_pat, *end_pat, *lang; 215 FILE *fp; 216 int conn_break = 0; 217 size_t ret, read_len, len; 218 int no_translate = 1; 219 static kw_t kw = {0, 0, NULL, NULL}; 220 221 if (!(fp = fopen(path, "r"))) 222 return; 223 224#ifdef TRANSLATE_ON_FLY 225 // Load dictionary file 226 227 // If the router is restored to default, using browser's language setting to display ALL pages 228 if (is_firsttime () && Accept_Language[0] != '\0' && nvram_match("ui_Setting", "0")) { 229 lang = Accept_Language; 230 nvram_set("ui_Setting" , "1"); 231 } else { 232 lang = nvram_safe_get("preferred_lang"); 233 if (!check_lang_support(lang)) { 234 nvram_set("preferred_lang", "EN"); 235 lang = "EN"; 236 } 237 } 238 239 if(!strncmp(nvram_safe_get("territory_code"), "JP", 2) && strcmp(nvram_safe_get("ATEMODE"), "1")){ 240 nvram_set("preferred_lang", "JP"); 241 lang = "JP"; 242 } 243 244 if (load_dictionary (lang, &kw)) { 245 no_translate = 0; 246 } 247#endif //defined TRANSLATE_ON_FLY 248 249 start_pat = end_pat = pattern; 250 memset (pattern + pattern_size, 0, 4); 251 while (conn_break == 0) 252 { 253 int special; 254 255 // Arrange pattern[] if available buffer length (end_pat~pattern[pattern_size]) is smaller than frag_size 256 if (((pattern + pattern_size) - end_pat) < frag_size) 257 { 258 len = end_pat - start_pat; 259 memcpy (pattern, start_pat, len); 260 start_pat = pattern; 261 end_pat = start_pat + len; 262 *end_pat = '\0'; 263 } 264 265 read_len = (pattern + pattern_size) - end_pat; 266 len = fread (end_pat, 1, read_len, fp); 267 if (len == 0) { 268 if (start_pat < end_pat) { 269 fwrite (start_pat, 1, (size_t) (end_pat - start_pat), stream); 270 } 271 break; 272 } 273 end_pat += len; 274 *end_pat = '\0'; 275 276 asp = strstr (start_pat, asp_mark1); 277 key = NULL; 278 if (no_translate == 0) { 279 key = strstr (start_pat, kw_mark1); 280 } 281 special = 0; 282 while ((start_pat < end_pat) && special == 0) 283 { 284 int postproc = 0; /* 0: need more data; 1: translate; 2: execute asp; 3: write only; */ 285 char *s, *e, *p; 286 287 /* asp asp_end 288 * ^ ^ 289 * +------------------------------<%.......%>-------------------------------+ 290 * | XXXXXXXXXXXXXXXXXXXXX<#.......#>YYYYYYYYYYYYYYYYYY0 |0000 291 * +------------------------------------------------------------------------+ 292 * ^ ^ ^ ^ ^ ^ ^ 293 * | | | | p | | 294 * pattern start_pat,s key,e(2) key_end end_pat,e(1) pattern + pattern_size 295 * ^ | 296 * +--------------------------------+ 297 * 298 */ 299 300 // If <%...%> and <#...#> do not exist in pattern[], write whole pattern[]. 301 s = start_pat; 302 e = end_pat; 303 304 if (key != NULL && asp == NULL) { 305 e = key; // Write start_pat ~ (key - 1) 306 key_end = strstr (key, kw_mark2); 307 if (key_end != NULL) { // We do have <#...#> in pattern[]. 308 postproc = 1; 309 } 310 } else if (key != NULL && asp != NULL) { 311 // We have <%...%> and <#...#> in pattern[], process first occurrence 312 if (asp < key) { 313 e = asp; // Write start_pat ~ (asp - 1) 314 asp_end = strstr (asp, asp_mark2); 315 if (asp_end != NULL) { // We do have whole <%...%>. 316 postproc = 2; 317 } 318 } else { 319 e = key; // Write start_pat ~ (key - 1) 320 key_end = strstr (key, kw_mark2); 321 if (key_end != NULL) { // We do have whole <#...#>. 322 postproc = 1; 323 } 324 } 325 } else if (key == NULL && asp != NULL) { 326 e = asp; // Write start_pat ~ (asp - 1) 327 asp_end = strstr (asp, asp_mark2); 328 if (asp_end != NULL) { // We do have whole <%...%>. 329 postproc = 2; 330 } 331 } else { 332 // Special case. If last character is '<' 333 // DO NOT write this character due to next one may be % or #. 334 if (*(e-1) == *asp_mark1 || *(e-1) == *kw_mark1) { 335 special = 1; 336 e--; 337 } 338 339 postproc = 3; 340 } 341 342 // process text preceeding <# or <% 343 if (e > s) { 344 ret = fwrite (s, 1, (size_t) (e - s), stream); 345 if (ret == 0 || ret < (e - s)) { 346 /* the connection had been damaged. DO NOT process another data. */ 347 /* (reduce response time of httpd) */ 348// cprintf ("fwrite() ret %d, s %p e %p len %d, break do_ej()'s while loop\n", ret, s, e, e-s); 349 conn_break = 1; 350 break; 351 } else { 352 start_pat = e; 353 } 354 } 355 // post process 356 p = NULL; 357 if (postproc == 1) { // translate 358 p = translate_lang (key + strlen (kw_mark1), key_end, stream, &kw); 359 if (no_translate == 0 && p != NULL) { 360 key = strstr (p, kw_mark1); 361 } 362 } else if (postproc == 2) { // execute asp 363 p = process_asp (asp + strlen (asp_mark1), asp_end, stream); 364 if (p != NULL) { 365 asp = strstr (p, asp_mark1); 366 } 367 } else if (postproc == 3) { // no <%...%> or <#...#> 368 p = e; 369 } else if (postproc == 0) { // read more data 370 break; 371 } 372 373 if (p != NULL) { 374 start_pat = p; 375 } 376 377 } /* while ((start_pat < end_pat) && special == 0) */ 378 } /* while (conn_break == 0) */ 379 380 fflush (stream); 381 fclose(fp); 382 383 if (pattern != pat_buf) { 384 free (pattern); 385 } 386} 387#endif // defined TRANSLATE_ON_FLY 388 389int 390ejArgs(int argc, char **argv, char *fmt, ...) 391{ 392 va_list ap; 393 int arg; 394 char *c; 395 396 if (!argv) 397 return 0; 398 399 va_start(ap, fmt); 400 for (arg = 0, c = fmt; c && *c && arg < argc;) { 401 if (*c++ != '%') 402 continue; 403 switch (*c) { 404 case 'd': 405 *(va_arg(ap, int *)) = atoi(argv[arg]); 406 break; 407 case 's': 408 *(va_arg(ap, char **)) = argv[arg]; 409 break; 410 } 411 arg++; 412 } 413 va_end(ap); 414 415 return arg; 416} 417