1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/signtool/javascript.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1835 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "signtool.h" 1.9 +#include <prmem.h> 1.10 +#include <prio.h> 1.11 +#include <prenv.h> 1.12 + 1.13 +static int javascript_fn(char *relpath, char *basedir, char *reldir, 1.14 +char *filename, void *arg); 1.15 +static int extract_js (char *filename); 1.16 +static int copyinto (char *from, char *to); 1.17 +static PRStatus ensureExists (char *base, char *path); 1.18 +static int make_dirs(char *path, PRInt32 file_perms); 1.19 + 1.20 +static char *jartree = NULL; 1.21 +static int idOrdinal; 1.22 +static PRBool dumpParse = PR_FALSE; 1.23 + 1.24 +static char *event_handlers[] = { 1.25 + "onAbort", 1.26 + "onBlur", 1.27 + "onChange", 1.28 + "onClick", 1.29 + "onDblClick", 1.30 + "onDragDrop", 1.31 + "onError", 1.32 + "onFocus", 1.33 + "onKeyDown", 1.34 + "onKeyPress", 1.35 + "onKeyUp", 1.36 + "onLoad", 1.37 + "onMouseDown", 1.38 + "onMouseMove", 1.39 + "onMouseOut", 1.40 + "onMouseOver", 1.41 + "onMouseUp", 1.42 + "onMove", 1.43 + "onReset", 1.44 + "onResize", 1.45 + "onSelect", 1.46 + "onSubmit", 1.47 + "onUnload" 1.48 +}; 1.49 + 1.50 + 1.51 +static int num_handlers = 23; 1.52 + 1.53 +/* 1.54 + * I n l i n e J a v a S c r i p t 1.55 + * 1.56 + * Javascript signing. Instead of passing an archive to signtool, 1.57 + * a directory containing html files is given. Archives are created 1.58 + * from the archive= and src= tag attributes inside the html, 1.59 + * as appropriate. Then the archives are signed. 1.60 + * 1.61 + */ 1.62 +int 1.63 +InlineJavaScript(char *dir, PRBool recurse) 1.64 +{ 1.65 + jartree = dir; 1.66 + if (verbosity >= 0) { 1.67 + PR_fprintf(outputFD, "\nGenerating inline signatures from HTML files in: %s\n", 1.68 + dir); 1.69 + } 1.70 + if (PR_GetEnv("SIGNTOOL_DUMP_PARSE")) { 1.71 + dumpParse = PR_TRUE; 1.72 + } 1.73 + 1.74 + return foreach(dir, "", javascript_fn, recurse, PR_FALSE /*include dirs*/, 1.75 + (void * )NULL); 1.76 + 1.77 +} 1.78 + 1.79 + 1.80 +/************************************************************************ 1.81 + * 1.82 + * j a v a s c r i p t _ f n 1.83 + */ 1.84 +static int javascript_fn 1.85 +(char *relpath, char *basedir, char *reldir, char *filename, void *arg) 1.86 +{ 1.87 + char fullname [FNSIZE]; 1.88 + 1.89 + /* only process inline scripts from .htm, .html, and .shtml*/ 1.90 + 1.91 + if (!(PL_strcaserstr(filename, ".htm") == filename + strlen(filename) - 1.92 + 4) && 1.93 + !(PL_strcaserstr(filename, ".html") == filename + strlen(filename) - 1.94 + 5) && 1.95 + !(PL_strcaserstr(filename, ".shtml") == filename + strlen(filename) 1.96 + -6)) { 1.97 + return 0; 1.98 + } 1.99 + 1.100 + /* don't process scripts that signtool has already 1.101 + extracted (those that are inside .arc directories) */ 1.102 + 1.103 + if (PL_strcaserstr(filename, ".arc") == filename + strlen(filename) - 4) 1.104 + return 0; 1.105 + 1.106 + if (verbosity >= 0) { 1.107 + PR_fprintf(outputFD, "Processing HTML file: %s\n", relpath); 1.108 + } 1.109 + 1.110 + /* reset firstArchive at top of each HTML file */ 1.111 + 1.112 + /* skip directories that contain extracted scripts */ 1.113 + 1.114 + if (PL_strcaserstr(reldir, ".arc") == reldir + strlen(reldir) - 4) 1.115 + return 0; 1.116 + 1.117 + sprintf (fullname, "%s/%s", basedir, relpath); 1.118 + return extract_js (fullname); 1.119 +} 1.120 + 1.121 + 1.122 +/*=========================================================================== 1.123 + = 1.124 + = D A T A S T R U C T U R E S 1.125 + = 1.126 +*/ 1.127 +typedef enum { 1.128 + TEXT_HTML_STATE = 0, 1.129 + SCRIPT_HTML_STATE 1.130 +} 1.131 + 1.132 + 1.133 +HTML_STATE ; 1.134 + 1.135 +typedef enum { 1.136 + /* we start in the start state */ 1.137 + START_STATE, 1.138 + 1.139 + /* We are looking for or reading in an attribute */ 1.140 + GET_ATT_STATE, 1.141 + 1.142 + /* We're burning ws before finding an attribute */ 1.143 + PRE_ATT_WS_STATE, 1.144 + 1.145 + /* We're burning ws after an attribute. Looking for an '='. */ 1.146 + POST_ATT_WS_STATE, 1.147 + 1.148 + /* We're burning ws after an '=', waiting for a value */ 1.149 + PRE_VAL_WS_STATE, 1.150 + 1.151 + /* We're reading in a value */ 1.152 + GET_VALUE_STATE, 1.153 + 1.154 + /* We're reading in a value that's inside quotes */ 1.155 + GET_QUOTED_VAL_STATE, 1.156 + 1.157 + /* We've encountered the closing '>' */ 1.158 + DONE_STATE, 1.159 + 1.160 + /* Error state */ 1.161 + ERR_STATE 1.162 +} 1.163 + 1.164 + 1.165 +TAG_STATE ; 1.166 + 1.167 +typedef struct AVPair_Str { 1.168 + char *attribute; 1.169 + char *value; 1.170 + unsigned int valueLine; /* the line that the value ends on */ 1.171 + struct AVPair_Str *next; 1.172 +} AVPair; 1.173 + 1.174 +typedef enum { 1.175 + APPLET_TAG, 1.176 + SCRIPT_TAG, 1.177 + LINK_TAG, 1.178 + STYLE_TAG, 1.179 + COMMENT_TAG, 1.180 + OTHER_TAG 1.181 +} 1.182 + 1.183 + 1.184 +TAG_TYPE ; 1.185 + 1.186 +typedef struct { 1.187 + TAG_TYPE type; 1.188 + AVPair * attList; 1.189 + AVPair * attListTail; 1.190 + char *text; 1.191 +} TagItem; 1.192 + 1.193 +typedef enum { 1.194 + TAG_ITEM, 1.195 + TEXT_ITEM 1.196 +} 1.197 + 1.198 + 1.199 +ITEM_TYPE ; 1.200 + 1.201 +typedef struct HTMLItem_Str { 1.202 + unsigned int startLine; 1.203 + unsigned int endLine; 1.204 + ITEM_TYPE type; 1.205 + union { 1.206 + TagItem *tag; 1.207 + char *text; 1.208 + } item; 1.209 + struct HTMLItem_Str *next; 1.210 +} HTMLItem; 1.211 + 1.212 +typedef struct { 1.213 + PRFileDesc *fd; 1.214 + PRInt32 curIndex; 1.215 + PRBool IsEOF; 1.216 +#define FILE_BUFFER_BUFSIZE 512 1.217 + char buf[FILE_BUFFER_BUFSIZE]; 1.218 + PRInt32 startOffset; 1.219 + PRInt32 maxIndex; 1.220 + unsigned int lineNum; 1.221 +} FileBuffer; 1.222 + 1.223 +/*=========================================================================== 1.224 + = 1.225 + = F U N C T I O N S 1.226 + = 1.227 +*/ 1.228 +static HTMLItem*CreateTextItem(char *text, unsigned int startline, 1.229 +unsigned int endline); 1.230 +static HTMLItem*CreateTagItem(TagItem*ti, unsigned int startline, 1.231 +unsigned int endline); 1.232 +static TagItem*ProcessTag(FileBuffer*fb, char **errStr); 1.233 +static void DestroyHTMLItem(HTMLItem *item); 1.234 +static void DestroyTagItem(TagItem*ti); 1.235 +static TAG_TYPE GetTagType(char *att); 1.236 +static FileBuffer*FB_Create(PRFileDesc*fd); 1.237 +static int FB_GetChar(FileBuffer *fb); 1.238 +static PRInt32 FB_GetPointer(FileBuffer *fb); 1.239 +static PRInt32 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, 1.240 +char **buf); 1.241 +static unsigned int FB_GetLineNum(FileBuffer *fb); 1.242 +static void FB_Destroy(FileBuffer *fb); 1.243 +static void PrintTagItem(PRFileDesc *fd, TagItem *ti); 1.244 +static void PrintHTMLStream(PRFileDesc *fd, HTMLItem *head); 1.245 + 1.246 +/************************************************************************ 1.247 + * 1.248 + * C r e a t e T e x t I t e m 1.249 + */ 1.250 +static HTMLItem* 1.251 +CreateTextItem(char *text, unsigned int startline, unsigned int endline) 1.252 +{ 1.253 + HTMLItem * item; 1.254 + 1.255 + item = PR_Malloc(sizeof(HTMLItem)); 1.256 + if (!item) { 1.257 + return NULL; 1.258 + } 1.259 + 1.260 + item->type = TEXT_ITEM; 1.261 + item->item.text = text; 1.262 + item->next = NULL; 1.263 + item->startLine = startline; 1.264 + item->endLine = endline; 1.265 + 1.266 + return item; 1.267 +} 1.268 + 1.269 + 1.270 +/************************************************************************ 1.271 + * 1.272 + * C r e a t e T a g I t e m 1.273 + */ 1.274 +static HTMLItem* 1.275 +CreateTagItem(TagItem*ti, unsigned int startline, unsigned int endline) 1.276 +{ 1.277 + HTMLItem * item; 1.278 + 1.279 + item = PR_Malloc(sizeof(HTMLItem)); 1.280 + if (!item) { 1.281 + return NULL; 1.282 + } 1.283 + 1.284 + item->type = TAG_ITEM; 1.285 + item->item.tag = ti; 1.286 + item->next = NULL; 1.287 + item->startLine = startline; 1.288 + item->endLine = endline; 1.289 + 1.290 + return item; 1.291 +} 1.292 + 1.293 + 1.294 +static PRBool 1.295 +isAttChar(int c) 1.296 +{ 1.297 + return (isalnum(c) || c == '/' || c == '-'); 1.298 +} 1.299 + 1.300 + 1.301 +/************************************************************************ 1.302 + * 1.303 + * P r o c e s s T a g 1.304 + */ 1.305 +static TagItem* 1.306 +ProcessTag(FileBuffer*fb, char **errStr) 1.307 +{ 1.308 + TAG_STATE state; 1.309 + PRInt32 startText, startID, curPos; 1.310 + PRBool firstAtt; 1.311 + int curchar; 1.312 + TagItem * ti = NULL; 1.313 + AVPair * curPair = NULL; 1.314 + char quotechar = '\0'; 1.315 + unsigned int linenum; 1.316 + unsigned int startline; 1.317 + 1.318 + state = START_STATE; 1.319 + 1.320 + startID = FB_GetPointer(fb); 1.321 + startText = startID; 1.322 + firstAtt = PR_TRUE; 1.323 + 1.324 + ti = (TagItem * ) PR_Malloc(sizeof(TagItem)); 1.325 + if (!ti) 1.326 + out_of_memory(); 1.327 + ti->type = OTHER_TAG; 1.328 + ti->attList = NULL; 1.329 + ti->attListTail = NULL; 1.330 + ti->text = NULL; 1.331 + 1.332 + startline = FB_GetLineNum(fb); 1.333 + 1.334 + while (state != DONE_STATE && state != ERR_STATE) { 1.335 + linenum = FB_GetLineNum(fb); 1.336 + curchar = FB_GetChar(fb); 1.337 + if (curchar == EOF) { 1.338 + *errStr = PR_smprintf( 1.339 + "line %d: Unexpected end-of-file while parsing tag starting at line %d.\n", 1.340 + linenum, startline); 1.341 + state = ERR_STATE; 1.342 + continue; 1.343 + } 1.344 + 1.345 + switch (state) { 1.346 + case START_STATE: 1.347 + if (curchar == '!') { 1.348 + /* 1.349 + * SGML tag or comment 1.350 + * Here's the general rule for SGML tags. Everything from 1.351 + * <! to > is the tag. Inside the tag, comments are 1.352 + * delimited with --. So we are looking for the first '>' 1.353 + * that is not commented out, that is, not inside a pair 1.354 + * of --: <!DOCTYPE --this is a comment >(psyche!) --> 1.355 + */ 1.356 + 1.357 + PRBool inComment = PR_FALSE; 1.358 + short hyphenCount = 0; /* number of consecutive hyphens */ 1.359 + 1.360 + while (1) { 1.361 + linenum = FB_GetLineNum(fb); 1.362 + curchar = FB_GetChar(fb); 1.363 + if (curchar == EOF) { 1.364 + /* Uh oh, EOF inside comment */ 1.365 + *errStr = PR_smprintf( 1.366 + "line %d: Unexpected end-of-file inside comment starting at line %d.\n", 1.367 + linenum, startline); 1.368 + state = ERR_STATE; 1.369 + break; 1.370 + } 1.371 + if (curchar == '-') { 1.372 + if (hyphenCount == 1) { 1.373 + /* This is a comment delimiter */ 1.374 + inComment = !inComment; 1.375 + hyphenCount = 0; 1.376 + } else { 1.377 + /* beginning of a comment delimiter? */ 1.378 + hyphenCount = 1; 1.379 + } 1.380 + } else if (curchar == '>') { 1.381 + if (!inComment) { 1.382 + /* This is the end of the tag */ 1.383 + state = DONE_STATE; 1.384 + break; 1.385 + } else { 1.386 + /* The > is inside a comment, so it's not 1.387 + * really the end of the tag */ 1.388 + hyphenCount = 0; 1.389 + } 1.390 + } else { 1.391 + hyphenCount = 0; 1.392 + } 1.393 + } 1.394 + ti->type = COMMENT_TAG; 1.395 + break; 1.396 + } 1.397 + /* fall through */ 1.398 + case GET_ATT_STATE: 1.399 + if (isspace(curchar) || curchar == '=' || curchar 1.400 + == '>') { 1.401 + /* end of the current attribute */ 1.402 + curPos = FB_GetPointer(fb) - 2; 1.403 + if (curPos >= startID) { 1.404 + /* We have an attribute */ 1.405 + curPair = (AVPair * )PR_Malloc(sizeof(AVPair)); 1.406 + if (!curPair) 1.407 + out_of_memory(); 1.408 + curPair->value = NULL; 1.409 + curPair->next = NULL; 1.410 + FB_GetRange(fb, startID, curPos, 1.411 + &curPair->attribute); 1.412 + 1.413 + /* Stick this attribute on the list */ 1.414 + if (ti->attListTail) { 1.415 + ti->attListTail->next = curPair; 1.416 + ti->attListTail = curPair; 1.417 + } else { 1.418 + ti->attList = ti->attListTail = 1.419 + curPair; 1.420 + } 1.421 + 1.422 + /* If this is the first attribute, find the type of tag 1.423 + * based on it. Also, start saving the text of the tag. */ 1.424 + if (firstAtt) { 1.425 + ti->type = GetTagType(curPair->attribute); 1.426 + startText = FB_GetPointer(fb) 1.427 + -1; 1.428 + firstAtt = PR_FALSE; 1.429 + } 1.430 + } else { 1.431 + if (curchar == '=') { 1.432 + /* If we don't have any attribute but we do have an 1.433 + * equal sign, that's an error */ 1.434 + *errStr = PR_smprintf("line %d: Malformed tag starting at line %d.\n", 1.435 + linenum, startline); 1.436 + state = ERR_STATE; 1.437 + break; 1.438 + } 1.439 + } 1.440 + 1.441 + /* Compute next state */ 1.442 + if (curchar == '=') { 1.443 + startID = FB_GetPointer(fb); 1.444 + state = PRE_VAL_WS_STATE; 1.445 + } else if (curchar == '>') { 1.446 + state = DONE_STATE; 1.447 + } else if (curPair) { 1.448 + state = POST_ATT_WS_STATE; 1.449 + } else { 1.450 + state = PRE_ATT_WS_STATE; 1.451 + } 1.452 + } else if (isAttChar(curchar)) { 1.453 + /* Just another char in the attribute. Do nothing */ 1.454 + state = GET_ATT_STATE; 1.455 + } else { 1.456 + /* bogus char */ 1.457 + *errStr = PR_smprintf("line %d: Bogus chararacter '%c' in tag.\n", 1.458 + linenum, curchar); 1.459 + state = ERR_STATE; 1.460 + break; 1.461 + } 1.462 + break; 1.463 + case PRE_ATT_WS_STATE: 1.464 + if (curchar == '>') { 1.465 + state = DONE_STATE; 1.466 + } else if (isspace(curchar)) { 1.467 + /* more whitespace, do nothing */ 1.468 + } else if (isAttChar(curchar)) { 1.469 + /* starting another attribute */ 1.470 + startID = FB_GetPointer(fb) - 1; 1.471 + state = GET_ATT_STATE; 1.472 + } else { 1.473 + /* bogus char */ 1.474 + *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n", 1.475 + linenum, curchar); 1.476 + state = ERR_STATE; 1.477 + break; 1.478 + } 1.479 + break; 1.480 + case POST_ATT_WS_STATE: 1.481 + if (curchar == '>') { 1.482 + state = DONE_STATE; 1.483 + } else if (isspace(curchar)) { 1.484 + /* more whitespace, do nothing */ 1.485 + } else if (isAttChar(curchar)) { 1.486 + /* starting another attribute */ 1.487 + startID = FB_GetPointer(fb) - 1; 1.488 + state = GET_ATT_STATE; 1.489 + } else if (curchar == '=') { 1.490 + /* there was whitespace between the attribute and its equal 1.491 + * sign, which means there's a value coming up */ 1.492 + state = PRE_VAL_WS_STATE; 1.493 + } else { 1.494 + /* bogus char */ 1.495 + *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n", 1.496 + linenum, curchar); 1.497 + state = ERR_STATE; 1.498 + break; 1.499 + } 1.500 + break; 1.501 + case PRE_VAL_WS_STATE: 1.502 + if (curchar == '>') { 1.503 + /* premature end-of-tag (sounds like a personal problem). */ 1.504 + *errStr = PR_smprintf( 1.505 + "line %d: End of tag while waiting for value.\n", 1.506 + linenum); 1.507 + state = ERR_STATE; 1.508 + break; 1.509 + } else if (isspace(curchar)) { 1.510 + /* more whitespace, do nothing */ 1.511 + break; 1.512 + } else { 1.513 + /* this must be some sort of value. Fall through 1.514 + * to GET_VALUE_STATE */ 1.515 + startID = FB_GetPointer(fb) - 1; 1.516 + state = GET_VALUE_STATE; 1.517 + } 1.518 + /* Fall through if we didn't break on '>' or whitespace */ 1.519 + case GET_VALUE_STATE: 1.520 + if (isspace(curchar) || curchar == '>') { 1.521 + /* end of value */ 1.522 + curPos = FB_GetPointer(fb) - 2; 1.523 + if (curPos >= startID) { 1.524 + /* Grab the value */ 1.525 + FB_GetRange(fb, startID, curPos, 1.526 + &curPair->value); 1.527 + curPair->valueLine = linenum; 1.528 + } else { 1.529 + /* empty value, leave as NULL */ 1.530 + } 1.531 + if (isspace(curchar)) { 1.532 + state = PRE_ATT_WS_STATE; 1.533 + } else { 1.534 + state = DONE_STATE; 1.535 + } 1.536 + } else if (curchar == '\"' || curchar == '\'') { 1.537 + /* quoted value. Start recording the value inside the quote*/ 1.538 + startID = FB_GetPointer(fb); 1.539 + state = GET_QUOTED_VAL_STATE; 1.540 + PORT_Assert(quotechar == '\0'); 1.541 + quotechar = curchar; /* look for matching quote type */ 1.542 + } else { 1.543 + /* just more value */ 1.544 + } 1.545 + break; 1.546 + case GET_QUOTED_VAL_STATE: 1.547 + PORT_Assert(quotechar != '\0'); 1.548 + if (curchar == quotechar) { 1.549 + /* end of quoted value */ 1.550 + curPos = FB_GetPointer(fb) - 2; 1.551 + if (curPos >= startID) { 1.552 + /* Grab the value */ 1.553 + FB_GetRange(fb, startID, curPos, 1.554 + &curPair->value); 1.555 + curPair->valueLine = linenum; 1.556 + } else { 1.557 + /* empty value, leave it as NULL */ 1.558 + } 1.559 + state = GET_ATT_STATE; 1.560 + quotechar = '\0'; 1.561 + startID = FB_GetPointer(fb); 1.562 + } else { 1.563 + /* more quoted value, continue */ 1.564 + } 1.565 + break; 1.566 + case DONE_STATE: 1.567 + case ERR_STATE: 1.568 + default: 1.569 + ; /* should never get here */ 1.570 + } 1.571 + } 1.572 + 1.573 + if (state == DONE_STATE) { 1.574 + /* Get the text of the tag */ 1.575 + curPos = FB_GetPointer(fb) - 1; 1.576 + FB_GetRange(fb, startText, curPos, &ti->text); 1.577 + 1.578 + /* Return the tag */ 1.579 + return ti; 1.580 + } 1.581 + 1.582 + /* Uh oh, an error. Kill the tag item*/ 1.583 + DestroyTagItem(ti); 1.584 + return NULL; 1.585 +} 1.586 + 1.587 + 1.588 +/************************************************************************ 1.589 + * 1.590 + * D e s t r o y H T M L I t e m 1.591 + */ 1.592 +static void 1.593 +DestroyHTMLItem(HTMLItem *item) 1.594 +{ 1.595 + if (item->type == TAG_ITEM) { 1.596 + DestroyTagItem(item->item.tag); 1.597 + } else { 1.598 + if (item->item.text) { 1.599 + PR_Free(item->item.text); 1.600 + } 1.601 + } 1.602 +} 1.603 + 1.604 + 1.605 +/************************************************************************ 1.606 + * 1.607 + * D e s t r o y T a g I t e m 1.608 + */ 1.609 +static void 1.610 +DestroyTagItem(TagItem*ti) 1.611 +{ 1.612 + AVPair * temp; 1.613 + 1.614 + if (ti->text) { 1.615 + PR_Free(ti->text); 1.616 + ti->text = NULL; 1.617 + } 1.618 + 1.619 + while (ti->attList) { 1.620 + temp = ti->attList; 1.621 + ti->attList = ti->attList->next; 1.622 + 1.623 + if (temp->attribute) { 1.624 + PR_Free(temp->attribute); 1.625 + temp->attribute = NULL; 1.626 + } 1.627 + if (temp->value) { 1.628 + PR_Free(temp->value); 1.629 + temp->value = NULL; 1.630 + } 1.631 + PR_Free(temp); 1.632 + } 1.633 + 1.634 + PR_Free(ti); 1.635 +} 1.636 + 1.637 + 1.638 +/************************************************************************ 1.639 + * 1.640 + * G e t T a g T y p e 1.641 + */ 1.642 +static TAG_TYPE 1.643 +GetTagType(char *att) 1.644 +{ 1.645 + if (!PORT_Strcasecmp(att, "APPLET")) { 1.646 + return APPLET_TAG; 1.647 + } 1.648 + if (!PORT_Strcasecmp(att, "SCRIPT")) { 1.649 + return SCRIPT_TAG; 1.650 + } 1.651 + if (!PORT_Strcasecmp(att, "LINK")) { 1.652 + return LINK_TAG; 1.653 + } 1.654 + if (!PORT_Strcasecmp(att, "STYLE")) { 1.655 + return STYLE_TAG; 1.656 + } 1.657 + return OTHER_TAG; 1.658 +} 1.659 + 1.660 + 1.661 +/************************************************************************ 1.662 + * 1.663 + * F B _ C r e a t e 1.664 + */ 1.665 +static FileBuffer* 1.666 +FB_Create(PRFileDesc*fd) 1.667 +{ 1.668 + FileBuffer * fb; 1.669 + PRInt32 amountRead; 1.670 + PRInt32 storedOffset; 1.671 + 1.672 + fb = (FileBuffer * ) PR_Malloc(sizeof(FileBuffer)); 1.673 + fb->fd = fd; 1.674 + storedOffset = PR_Seek(fd, 0, PR_SEEK_CUR); 1.675 + PR_Seek(fd, 0, PR_SEEK_SET); 1.676 + fb->startOffset = 0; 1.677 + amountRead = PR_Read(fd, fb->buf, FILE_BUFFER_BUFSIZE); 1.678 + if (amountRead == -1) 1.679 + goto loser; 1.680 + fb->maxIndex = amountRead - 1; 1.681 + fb->curIndex = 0; 1.682 + fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE; 1.683 + fb->lineNum = 1; 1.684 + 1.685 + PR_Seek(fd, storedOffset, PR_SEEK_SET); 1.686 + return fb; 1.687 +loser: 1.688 + PR_Seek(fd, storedOffset, PR_SEEK_SET); 1.689 + PR_Free(fb); 1.690 + return NULL; 1.691 +} 1.692 + 1.693 + 1.694 +/************************************************************************ 1.695 + * 1.696 + * F B _ G e t C h a r 1.697 + */ 1.698 +static int 1.699 +FB_GetChar(FileBuffer *fb) 1.700 +{ 1.701 + PRInt32 storedOffset; 1.702 + PRInt32 amountRead; 1.703 + int retval = -1; 1.704 + 1.705 + if (fb->IsEOF) { 1.706 + return EOF; 1.707 + } 1.708 + 1.709 + storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR); 1.710 + 1.711 + retval = (unsigned char) fb->buf[fb->curIndex++]; 1.712 + if (retval == '\n') 1.713 + fb->lineNum++; 1.714 + 1.715 + if (fb->curIndex > fb->maxIndex) { 1.716 + /* We're at the end of the buffer. Try to get some new data from the 1.717 + * file */ 1.718 + fb->startOffset += fb->maxIndex + 1; 1.719 + PR_Seek(fb->fd, fb->startOffset, PR_SEEK_SET); 1.720 + amountRead = PR_Read(fb->fd, fb->buf, FILE_BUFFER_BUFSIZE); 1.721 + if (amountRead == -1) 1.722 + goto loser; 1.723 + fb->maxIndex = amountRead - 1; 1.724 + fb->curIndex = 0; 1.725 + } 1.726 + 1.727 + fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE; 1.728 + 1.729 +loser: 1.730 + PR_Seek(fb->fd, storedOffset, PR_SEEK_SET); 1.731 + return retval; 1.732 +} 1.733 + 1.734 + 1.735 +/************************************************************************ 1.736 + * 1.737 + * F B _ G e t L i n e N u m 1.738 + * 1.739 + */ 1.740 +static unsigned int 1.741 +FB_GetLineNum(FileBuffer *fb) 1.742 +{ 1.743 + return fb->lineNum; 1.744 +} 1.745 + 1.746 + 1.747 +/************************************************************************ 1.748 + * 1.749 + * F B _ G e t P o i n t e r 1.750 + * 1.751 + */ 1.752 +static PRInt32 1.753 +FB_GetPointer(FileBuffer *fb) 1.754 +{ 1.755 + return fb->startOffset + fb->curIndex; 1.756 +} 1.757 + 1.758 + 1.759 +/************************************************************************ 1.760 + * 1.761 + * F B _ G e t R a n g e 1.762 + * 1.763 + */ 1.764 +static PRInt32 1.765 +FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, char **buf) 1.766 +{ 1.767 + PRInt32 amountRead; 1.768 + PRInt32 storedOffset; 1.769 + 1.770 + *buf = PR_Malloc(end - start + 2); 1.771 + if (*buf == NULL) { 1.772 + return 0; 1.773 + } 1.774 + 1.775 + storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR); 1.776 + PR_Seek(fb->fd, start, PR_SEEK_SET); 1.777 + amountRead = PR_Read(fb->fd, *buf, end - start + 1); 1.778 + PR_Seek(fb->fd, storedOffset, PR_SEEK_SET); 1.779 + if (amountRead == -1) { 1.780 + PR_Free(*buf); 1.781 + *buf = NULL; 1.782 + return 0; 1.783 + } 1.784 + 1.785 + (*buf)[end-start+1] = '\0'; 1.786 + return amountRead; 1.787 +} 1.788 + 1.789 + 1.790 +/************************************************************************ 1.791 + * 1.792 + * F B _ D e s t r o y 1.793 + * 1.794 + */ 1.795 +static void 1.796 +FB_Destroy(FileBuffer *fb) 1.797 +{ 1.798 + if (fb) { 1.799 + PR_Free(fb); 1.800 + } 1.801 +} 1.802 + 1.803 + 1.804 +/************************************************************************ 1.805 + * 1.806 + * P r i n t T a g I t e m 1.807 + * 1.808 + */ 1.809 +static void 1.810 +PrintTagItem(PRFileDesc *fd, TagItem *ti) 1.811 +{ 1.812 + AVPair * pair; 1.813 + 1.814 + PR_fprintf(fd, "TAG:\n----\nType: "); 1.815 + switch (ti->type) { 1.816 + case APPLET_TAG: 1.817 + PR_fprintf(fd, "applet\n"); 1.818 + break; 1.819 + case SCRIPT_TAG: 1.820 + PR_fprintf(fd, "script\n"); 1.821 + break; 1.822 + case LINK_TAG: 1.823 + PR_fprintf(fd, "link\n"); 1.824 + break; 1.825 + case STYLE_TAG: 1.826 + PR_fprintf(fd, "style\n"); 1.827 + break; 1.828 + case COMMENT_TAG: 1.829 + PR_fprintf(fd, "comment\n"); 1.830 + break; 1.831 + case OTHER_TAG: 1.832 + default: 1.833 + PR_fprintf(fd, "other\n"); 1.834 + break; 1.835 + } 1.836 + 1.837 + PR_fprintf(fd, "Attributes:\n"); 1.838 + for (pair = ti->attList; pair; pair = pair->next) { 1.839 + PR_fprintf(fd, "\t%s=%s\n", pair->attribute, 1.840 + pair->value ? pair->value : ""); 1.841 + } 1.842 + PR_fprintf(fd, "Text:%s\n", ti->text ? ti->text : ""); 1.843 + 1.844 + PR_fprintf(fd, "---End of tag---\n"); 1.845 +} 1.846 + 1.847 + 1.848 +/************************************************************************ 1.849 + * 1.850 + * P r i n t H T M L S t r e a m 1.851 + * 1.852 + */ 1.853 +static void 1.854 +PrintHTMLStream(PRFileDesc *fd, HTMLItem *head) 1.855 +{ 1.856 + while (head) { 1.857 + if (head->type == TAG_ITEM) { 1.858 + PrintTagItem(fd, head->item.tag); 1.859 + } else { 1.860 + PR_fprintf(fd, "\nTEXT:\n-----\n%s\n-----\n\n", head->item.text); 1.861 + } 1.862 + head = head->next; 1.863 + } 1.864 +} 1.865 + 1.866 + 1.867 +/************************************************************************ 1.868 + * 1.869 + * S a v e I n l i n e S c r i p t 1.870 + * 1.871 + */ 1.872 +static int 1.873 +SaveInlineScript(char *text, char *id, char *basedir, char *archiveDir) 1.874 +{ 1.875 + char *filename = NULL; 1.876 + PRFileDesc * fd = NULL; 1.877 + int retval = -1; 1.878 + PRInt32 writeLen; 1.879 + char *ilDir = NULL; 1.880 + 1.881 + if (!text || !id || !archiveDir) { 1.882 + return - 1; 1.883 + } 1.884 + 1.885 + if (dumpParse) { 1.886 + PR_fprintf(outputFD, "SaveInlineScript: text=%s, id=%s, \n" 1.887 + "basedir=%s, archiveDir=%s\n", 1.888 + text, id, basedir, archiveDir); 1.889 + } 1.890 + 1.891 + /* Make sure the archive directory is around */ 1.892 + if (ensureExists(basedir, archiveDir) != PR_SUCCESS) { 1.893 + PR_fprintf(errorFD, 1.894 + "ERROR: Unable to create archive directory %s.\n", archiveDir); 1.895 + errorCount++; 1.896 + return - 1; 1.897 + } 1.898 + 1.899 + /* Make sure the inline script directory is around */ 1.900 + ilDir = PR_smprintf("%s/inlineScripts", archiveDir); 1.901 + scriptdir = "inlineScripts"; 1.902 + if (ensureExists(basedir, ilDir) != PR_SUCCESS) { 1.903 + PR_fprintf(errorFD, 1.904 + "ERROR: Unable to create directory %s.\n", ilDir); 1.905 + errorCount++; 1.906 + return - 1; 1.907 + } 1.908 + 1.909 + filename = PR_smprintf("%s/%s/%s", basedir, ilDir, id); 1.910 + 1.911 + /* If the file already exists, give a warning, then blow it away */ 1.912 + if (PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) { 1.913 + PR_fprintf(errorFD, 1.914 + "warning: file \"%s\" already exists--will overwrite.\n", 1.915 + filename); 1.916 + warningCount++; 1.917 + if (rm_dash_r(filename)) { 1.918 + PR_fprintf(errorFD, "ERROR: Unable to delete %s.\n", filename); 1.919 + errorCount++; 1.920 + goto finish; 1.921 + } 1.922 + } 1.923 + 1.924 + /* Write text into file with name id */ 1.925 + fd = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777); 1.926 + if (!fd) { 1.927 + PR_fprintf(errorFD, "ERROR: Unable to create file \"%s\".\n", 1.928 + filename); 1.929 + errorCount++; 1.930 + goto finish; 1.931 + } 1.932 + writeLen = strlen(text); 1.933 + if ( PR_Write(fd, text, writeLen) != writeLen) { 1.934 + PR_fprintf(errorFD, "ERROR: Unable to write to file \"%s\".\n", 1.935 + filename); 1.936 + errorCount++; 1.937 + goto finish; 1.938 + } 1.939 + 1.940 + retval = 0; 1.941 +finish: 1.942 + if (filename) { 1.943 + PR_smprintf_free(filename); 1.944 + } 1.945 + if (ilDir) { 1.946 + PR_smprintf_free(ilDir); 1.947 + } 1.948 + if (fd) { 1.949 + PR_Close(fd); 1.950 + } 1.951 + return retval; 1.952 +} 1.953 + 1.954 + 1.955 +/************************************************************************ 1.956 + * 1.957 + * S a v e U n n a m a b l e S c r i p t 1.958 + * 1.959 + */ 1.960 +static int 1.961 +SaveUnnamableScript(char *text, char *basedir, char *archiveDir, 1.962 +char *HTMLfilename) 1.963 +{ 1.964 + char *id = NULL; 1.965 + char *ext = NULL; 1.966 + char *start = NULL; 1.967 + int retval = -1; 1.968 + 1.969 + if (!text || !archiveDir || !HTMLfilename) { 1.970 + return - 1; 1.971 + } 1.972 + 1.973 + if (dumpParse) { 1.974 + PR_fprintf(outputFD, "SaveUnnamableScript: text=%s, basedir=%s,\n" 1.975 + "archiveDir=%s, filename=%s\n", text, basedir, archiveDir, 1.976 + HTMLfilename); 1.977 + } 1.978 + 1.979 + /* Construct the filename */ 1.980 + ext = PL_strrchr(HTMLfilename, '.'); 1.981 + if (ext) { 1.982 + *ext = '\0'; 1.983 + } 1.984 + for (start = HTMLfilename; strpbrk(start, "/\\"); 1.985 + start = strpbrk(start, "/\\") + 1) 1.986 + /* do nothing */; 1.987 + if (*start == '\0') 1.988 + start = HTMLfilename; 1.989 + id = PR_smprintf("_%s%d", start, idOrdinal++); 1.990 + if (ext) { 1.991 + *ext = '.'; 1.992 + } 1.993 + 1.994 + /* Now call SaveInlineScript to do the work */ 1.995 + retval = SaveInlineScript(text, id, basedir, archiveDir); 1.996 + 1.997 + PR_Free(id); 1.998 + 1.999 + return retval; 1.1000 +} 1.1001 + 1.1002 + 1.1003 +/************************************************************************ 1.1004 + * 1.1005 + * S a v e S o u r c e 1.1006 + * 1.1007 + */ 1.1008 +static int 1.1009 +SaveSource(char *src, char *codebase, char *basedir, char *archiveDir) 1.1010 +{ 1.1011 + char *from = NULL, *to = NULL; 1.1012 + int retval = -1; 1.1013 + char *arcDir = NULL; 1.1014 + 1.1015 + if (!src || !archiveDir) { 1.1016 + return - 1; 1.1017 + } 1.1018 + 1.1019 + if (dumpParse) { 1.1020 + PR_fprintf(outputFD, "SaveSource: src=%s, codebase=%s, basedir=%s,\n" 1.1021 + "archiveDir=%s\n", src, codebase, basedir, archiveDir); 1.1022 + } 1.1023 + 1.1024 + if (codebase) { 1.1025 + arcDir = PR_smprintf("%s/%s/%s/", basedir, codebase, archiveDir); 1.1026 + } else { 1.1027 + arcDir = PR_smprintf("%s/%s/", basedir, archiveDir); 1.1028 + } 1.1029 + 1.1030 + if (codebase) { 1.1031 + from = PR_smprintf("%s/%s/%s", basedir, codebase, src); 1.1032 + to = PR_smprintf("%s%s", arcDir, src); 1.1033 + } else { 1.1034 + from = PR_smprintf("%s/%s", basedir, src); 1.1035 + to = PR_smprintf("%s%s", arcDir, src); 1.1036 + } 1.1037 + 1.1038 + if (make_dirs(to, 0777)) { 1.1039 + PR_fprintf(errorFD, 1.1040 + "ERROR: Unable to create archive directory %s.\n", archiveDir); 1.1041 + errorCount++; 1.1042 + goto finish; 1.1043 + } 1.1044 + 1.1045 + retval = copyinto(from, to); 1.1046 +finish: 1.1047 + if (from) 1.1048 + PR_Free(from); 1.1049 + if (to) 1.1050 + PR_Free(to); 1.1051 + if (arcDir) 1.1052 + PR_Free(arcDir); 1.1053 + return retval; 1.1054 +} 1.1055 + 1.1056 + 1.1057 +/************************************************************************ 1.1058 + * 1.1059 + * T a g T y p e T o S t r i n g 1.1060 + * 1.1061 + */ 1.1062 +char * 1.1063 +TagTypeToString(TAG_TYPE type) 1.1064 +{ 1.1065 + switch (type) { 1.1066 + case APPLET_TAG: 1.1067 + return "APPLET"; 1.1068 + case SCRIPT_TAG: 1.1069 + return "SCRIPT"; 1.1070 + case LINK_TAG: 1.1071 + return "LINK"; 1.1072 + case STYLE_TAG: 1.1073 + return "STYLE"; 1.1074 + default: 1.1075 + break; 1.1076 + } 1.1077 + return "unknown"; 1.1078 +} 1.1079 + 1.1080 + 1.1081 +/************************************************************************ 1.1082 + * 1.1083 + * e x t r a c t _ j s 1.1084 + * 1.1085 + */ 1.1086 +static int 1.1087 +extract_js(char *filename) 1.1088 +{ 1.1089 + PRFileDesc * fd = NULL; 1.1090 + FileBuffer * fb = NULL; 1.1091 + HTMLItem * head = NULL; 1.1092 + HTMLItem * tail = NULL; 1.1093 + HTMLItem * curitem = NULL; 1.1094 + HTMLItem * styleList = NULL; 1.1095 + HTMLItem * styleListTail = NULL; 1.1096 + HTMLItem * entityList = NULL; 1.1097 + HTMLItem * entityListTail = NULL; 1.1098 + TagItem * tagp = NULL; 1.1099 + char *text = NULL; 1.1100 + char *tagerr = NULL; 1.1101 + char *archiveDir = NULL; 1.1102 + char *firstArchiveDir = NULL; 1.1103 + char *basedir = NULL; 1.1104 + PRInt32 textStart; 1.1105 + PRInt32 curOffset; 1.1106 + HTML_STATE state; 1.1107 + int curchar; 1.1108 + int retval = -1; 1.1109 + unsigned int linenum, startLine; 1.1110 + 1.1111 + /* Initialize the implicit ID counter for each file */ 1.1112 + idOrdinal = 0; 1.1113 + 1.1114 + /* 1.1115 + * First, parse the HTML into a stream of tags and text. 1.1116 + */ 1.1117 + 1.1118 + fd = PR_Open(filename, PR_RDONLY, 0); 1.1119 + if (!fd) { 1.1120 + PR_fprintf(errorFD, "Unable to open %s for reading.\n", filename); 1.1121 + errorCount++; 1.1122 + return - 1; 1.1123 + } 1.1124 + 1.1125 + /* Construct base directory of filename. */ 1.1126 + { 1.1127 + char *cp; 1.1128 + 1.1129 + basedir = PL_strdup(filename); 1.1130 + 1.1131 + /* Remove trailing slashes */ 1.1132 + while ( (cp = PL_strprbrk(basedir, "/\\")) == 1.1133 + (basedir + strlen(basedir) - 1)) { 1.1134 + *cp = '\0'; 1.1135 + } 1.1136 + 1.1137 + /* Now remove everything from the last slash (which will be followed 1.1138 + * by a filename) to the end */ 1.1139 + cp = PL_strprbrk(basedir, "/\\"); 1.1140 + if (cp) { 1.1141 + *cp = '\0'; 1.1142 + } 1.1143 + } 1.1144 + 1.1145 + state = TEXT_HTML_STATE; 1.1146 + 1.1147 + fb = FB_Create(fd); 1.1148 + 1.1149 + textStart = 0; 1.1150 + startLine = 0; 1.1151 + while (linenum = FB_GetLineNum(fb), (curchar = FB_GetChar(fb)) != 1.1152 + EOF) { 1.1153 + switch (state) { 1.1154 + case TEXT_HTML_STATE: 1.1155 + if (curchar == '<') { 1.1156 + /* 1.1157 + * Found a tag 1.1158 + */ 1.1159 + /* Save the text so far to a new text item */ 1.1160 + curOffset = FB_GetPointer(fb) - 2; 1.1161 + if (curOffset >= textStart) { 1.1162 + if (FB_GetRange(fb, textStart, curOffset, 1.1163 + &text) != 1.1164 + curOffset - textStart + 1) { 1.1165 + PR_fprintf(errorFD, 1.1166 + "Unable to read from %s.\n", 1.1167 + filename); 1.1168 + errorCount++; 1.1169 + goto loser; 1.1170 + } 1.1171 + /* little fudge here. If the first character on a line 1.1172 + * is '<', meaning a new tag, the preceding text item 1.1173 + * actually ends on the previous line. In this case 1.1174 + * we will be saying that the text segment ends on the 1.1175 + * next line. I don't think this matters for text items. */ 1.1176 + curitem = CreateTextItem(text, startLine, 1.1177 + linenum); 1.1178 + text = NULL; 1.1179 + if (tail == NULL) { 1.1180 + head = tail = curitem; 1.1181 + } else { 1.1182 + tail->next = curitem; 1.1183 + tail = curitem; 1.1184 + } 1.1185 + } 1.1186 + 1.1187 + /* Process the tag */ 1.1188 + tagp = ProcessTag(fb, &tagerr); 1.1189 + if (!tagp) { 1.1190 + if (tagerr) { 1.1191 + PR_fprintf(errorFD, "Error in file %s: %s\n", 1.1192 + filename, tagerr); 1.1193 + errorCount++; 1.1194 + } else { 1.1195 + PR_fprintf(errorFD, 1.1196 + "Error in file %s, in tag starting at line %d\n", 1.1197 + filename, linenum); 1.1198 + errorCount++; 1.1199 + } 1.1200 + goto loser; 1.1201 + } 1.1202 + /* Add the tag to the list */ 1.1203 + curitem = CreateTagItem(tagp, linenum, FB_GetLineNum(fb)); 1.1204 + if (tail == NULL) { 1.1205 + head = tail = curitem; 1.1206 + } else { 1.1207 + tail->next = curitem; 1.1208 + tail = curitem; 1.1209 + } 1.1210 + 1.1211 + /* What's the next state */ 1.1212 + if (tagp->type == SCRIPT_TAG) { 1.1213 + state = SCRIPT_HTML_STATE; 1.1214 + } 1.1215 + 1.1216 + /* Start recording text from the new offset */ 1.1217 + textStart = FB_GetPointer(fb); 1.1218 + startLine = FB_GetLineNum(fb); 1.1219 + } else { 1.1220 + /* regular character. Next! */ 1.1221 + } 1.1222 + break; 1.1223 + case SCRIPT_HTML_STATE: 1.1224 + if (curchar == '<') { 1.1225 + char *cp; 1.1226 + /* 1.1227 + * If this is a </script> tag, then we're at the end of the 1.1228 + * script. Otherwise, ignore 1.1229 + */ 1.1230 + curOffset = FB_GetPointer(fb) - 1; 1.1231 + cp = NULL; 1.1232 + if (FB_GetRange(fb, curOffset, curOffset + 8, &cp) != 9) { 1.1233 + if (cp) { 1.1234 + PR_Free(cp); 1.1235 + cp = NULL; 1.1236 + } 1.1237 + } else { 1.1238 + /* compare the strings */ 1.1239 + if ( !PORT_Strncasecmp(cp, "</script>", 9) ) { 1.1240 + /* This is the end of the script. Record the text. */ 1.1241 + curOffset--; 1.1242 + if (curOffset >= textStart) { 1.1243 + if (FB_GetRange(fb, textStart, curOffset, &text) != 1.1244 + curOffset - textStart + 1) { 1.1245 + PR_fprintf(errorFD, "Unable to read from %s.\n", 1.1246 + filename); 1.1247 + errorCount++; 1.1248 + goto loser; 1.1249 + } 1.1250 + curitem = CreateTextItem(text, startLine, linenum); 1.1251 + text = NULL; 1.1252 + if (tail == NULL) { 1.1253 + head = tail = curitem; 1.1254 + } else { 1.1255 + tail->next = curitem; 1.1256 + tail = curitem; 1.1257 + } 1.1258 + } 1.1259 + 1.1260 + /* Now parse the /script tag and put it on the list */ 1.1261 + tagp = ProcessTag(fb, &tagerr); 1.1262 + if (!tagp) { 1.1263 + if (tagerr) { 1.1264 + PR_fprintf(errorFD, "Error in file %s: %s\n", 1.1265 + filename, tagerr); 1.1266 + } else { 1.1267 + PR_fprintf(errorFD, 1.1268 + "Error in file %s, in tag starting at" 1.1269 + " line %d\n", filename, linenum); 1.1270 + } 1.1271 + errorCount++; 1.1272 + goto loser; 1.1273 + } 1.1274 + curitem = CreateTagItem(tagp, linenum, 1.1275 + FB_GetLineNum(fb)); 1.1276 + if (tail == NULL) { 1.1277 + head = tail = curitem; 1.1278 + } else { 1.1279 + tail->next = curitem; 1.1280 + tail = curitem; 1.1281 + } 1.1282 + 1.1283 + /* go back to text state */ 1.1284 + state = TEXT_HTML_STATE; 1.1285 + 1.1286 + textStart = FB_GetPointer(fb); 1.1287 + startLine = FB_GetLineNum(fb); 1.1288 + } 1.1289 + } 1.1290 + } 1.1291 + break; 1.1292 + } 1.1293 + } 1.1294 + 1.1295 + /* End of the file. Wrap up any remaining text */ 1.1296 + if (state == SCRIPT_HTML_STATE) { 1.1297 + if (tail && tail->type == TAG_ITEM) { 1.1298 + PR_fprintf(errorFD, "ERROR: <SCRIPT> tag at %s:%d is not followed " 1.1299 + "by a </SCRIPT> tag.\n", filename, tail->startLine); 1.1300 + } else { 1.1301 + PR_fprintf(errorFD, "ERROR: <SCRIPT> tag in file %s is not followed" 1.1302 + " by a </SCRIPT tag.\n", filename); 1.1303 + } 1.1304 + errorCount++; 1.1305 + goto loser; 1.1306 + } 1.1307 + curOffset = FB_GetPointer(fb) - 1; 1.1308 + if (curOffset >= textStart) { 1.1309 + text = NULL; 1.1310 + if ( FB_GetRange(fb, textStart, curOffset, &text) != 1.1311 + curOffset - textStart + 1) { 1.1312 + PR_fprintf(errorFD, "Unable to read from %s.\n", filename); 1.1313 + errorCount++; 1.1314 + goto loser; 1.1315 + } 1.1316 + curitem = CreateTextItem(text, startLine, linenum); 1.1317 + text = NULL; 1.1318 + if (tail == NULL) { 1.1319 + head = tail = curitem; 1.1320 + } else { 1.1321 + tail->next = curitem; 1.1322 + tail = curitem; 1.1323 + } 1.1324 + } 1.1325 + 1.1326 + if (dumpParse) { 1.1327 + PrintHTMLStream(outputFD, head); 1.1328 + } 1.1329 + 1.1330 + /* 1.1331 + * Now we have a stream of tags and text. Go through and deal with each. 1.1332 + */ 1.1333 + for (curitem = head; curitem; curitem = curitem->next) { 1.1334 + TagItem * tagp = NULL; 1.1335 + AVPair * pairp = NULL; 1.1336 + char *src = NULL, *id = NULL, *codebase = NULL; 1.1337 + PRBool hasEventHandler = PR_FALSE; 1.1338 + int i; 1.1339 + 1.1340 + /* Reset archive directory for each tag */ 1.1341 + if (archiveDir) { 1.1342 + PR_Free(archiveDir); 1.1343 + archiveDir = NULL; 1.1344 + } 1.1345 + 1.1346 + /* We only analyze tags */ 1.1347 + if (curitem->type != TAG_ITEM) { 1.1348 + continue; 1.1349 + } 1.1350 + 1.1351 + tagp = curitem->item.tag; 1.1352 + 1.1353 + /* go through the attributes to get information */ 1.1354 + for (pairp = tagp->attList; pairp; pairp = pairp->next) { 1.1355 + 1.1356 + /* ARCHIVE= */ 1.1357 + if ( !PL_strcasecmp(pairp->attribute, "archive")) { 1.1358 + if (archiveDir) { 1.1359 + /* Duplicate attribute. Print warning */ 1.1360 + PR_fprintf(errorFD, 1.1361 + "warning: \"%s\" attribute overwrites previous attribute" 1.1362 + " in tag starting at %s:%d.\n", 1.1363 + pairp->attribute, filename, curitem->startLine); 1.1364 + warningCount++; 1.1365 + PR_Free(archiveDir); 1.1366 + } 1.1367 + archiveDir = PL_strdup(pairp->value); 1.1368 + 1.1369 + /* Substiture ".arc" for ".jar" */ 1.1370 + if ( (PL_strlen(archiveDir) < 4) || 1.1371 + PL_strcasecmp((archiveDir + strlen(archiveDir) -4), 1.1372 + ".jar")) { 1.1373 + PR_fprintf(errorFD, 1.1374 + "warning: ARCHIVE attribute should end in \".jar\" in tag" 1.1375 + " starting on %s:%d.\n", filename, curitem->startLine); 1.1376 + warningCount++; 1.1377 + PR_Free(archiveDir); 1.1378 + archiveDir = PR_smprintf("%s.arc", archiveDir); 1.1379 + } else { 1.1380 + PL_strcpy(archiveDir + strlen(archiveDir) -4, ".arc"); 1.1381 + } 1.1382 + 1.1383 + /* Record the first archive. This will be used later if 1.1384 + * the archive is not specified */ 1.1385 + if (firstArchiveDir == NULL) { 1.1386 + firstArchiveDir = PL_strdup(archiveDir); 1.1387 + } 1.1388 + } 1.1389 + /* CODEBASE= */ 1.1390 + else if ( !PL_strcasecmp(pairp->attribute, "codebase")) { 1.1391 + if (codebase) { 1.1392 + /* Duplicate attribute. Print warning */ 1.1393 + PR_fprintf(errorFD, 1.1394 + "warning: \"%s\" attribute overwrites previous attribute" 1.1395 + " in tag staring at %s:%d.\n", 1.1396 + pairp->attribute, filename, curitem->startLine); 1.1397 + warningCount++; 1.1398 + } 1.1399 + codebase = pairp->value; 1.1400 + } 1.1401 + /* SRC= and HREF= */ 1.1402 + else if ( !PORT_Strcasecmp(pairp->attribute, "src") || 1.1403 + !PORT_Strcasecmp(pairp->attribute, "href") ) { 1.1404 + if (src) { 1.1405 + /* Duplicate attribute. Print warning */ 1.1406 + PR_fprintf(errorFD, 1.1407 + "warning: \"%s\" attribute overwrites previous attribute" 1.1408 + " in tag staring at %s:%d.\n", 1.1409 + pairp->attribute, filename, curitem->startLine); 1.1410 + warningCount++; 1.1411 + } 1.1412 + src = pairp->value; 1.1413 + } 1.1414 + /* CODE= */ 1.1415 + else if (!PORT_Strcasecmp(pairp->attribute, "code") ) { 1.1416 + /*!!!XXX Change PORT to PL all over this code !!! */ 1.1417 + if (src) { 1.1418 + /* Duplicate attribute. Print warning */ 1.1419 + PR_fprintf(errorFD, 1.1420 + "warning: \"%s\" attribute overwrites previous attribute" 1.1421 + " ,in tag staring at %s:%d.\n", 1.1422 + pairp->attribute, filename, curitem->startLine); 1.1423 + warningCount++; 1.1424 + } 1.1425 + src = pairp->value; 1.1426 + 1.1427 + /* Append a .class if one is not already present */ 1.1428 + if ( (PL_strlen(src) < 6) || 1.1429 + PL_strcasecmp( (src + PL_strlen(src) - 6), ".class") ) { 1.1430 + src = PR_smprintf("%s.class", src); 1.1431 + /* Put this string back into the data structure so it 1.1432 + * will be deallocated properly */ 1.1433 + PR_Free(pairp->value); 1.1434 + pairp->value = src; 1.1435 + } 1.1436 + } 1.1437 + /* ID= */ 1.1438 + else if (!PL_strcasecmp(pairp->attribute, "id") ) { 1.1439 + if (id) { 1.1440 + /* Duplicate attribute. Print warning */ 1.1441 + PR_fprintf(errorFD, 1.1442 + "warning: \"%s\" attribute overwrites previous attribute" 1.1443 + " in tag staring at %s:%d.\n", 1.1444 + pairp->attribute, filename, curitem->startLine); 1.1445 + warningCount++; 1.1446 + } 1.1447 + id = pairp->value; 1.1448 + } 1.1449 + 1.1450 + /* STYLE= */ 1.1451 + /* style= attributes, along with JS entities, are stored into 1.1452 + * files with dynamically generated names. The filenames are 1.1453 + * based on the order in which the text is found in the file. 1.1454 + * All JS entities on all lines up to and including the line 1.1455 + * containing the end of the tag that has this style= attribute 1.1456 + * will be processed before this style=attribute. So we need 1.1457 + * to record the line that this _tag_ (not the attribute) ends on. 1.1458 + */ 1.1459 + else if (!PL_strcasecmp(pairp->attribute, "style") && pairp->value) 1.1460 + { 1.1461 + HTMLItem * styleItem; 1.1462 + /* Put this item on the style list */ 1.1463 + styleItem = CreateTextItem(PL_strdup(pairp->value), 1.1464 + curitem->startLine, curitem->endLine); 1.1465 + if (styleListTail == NULL) { 1.1466 + styleList = styleListTail = styleItem; 1.1467 + } else { 1.1468 + styleListTail->next = styleItem; 1.1469 + styleListTail = styleItem; 1.1470 + } 1.1471 + } 1.1472 + /* Event handlers */ 1.1473 + else { 1.1474 + for (i = 0; i < num_handlers; i++) { 1.1475 + if (!PL_strcasecmp(event_handlers[i], pairp->attribute)) { 1.1476 + hasEventHandler = PR_TRUE; 1.1477 + break; 1.1478 + } 1.1479 + } 1.1480 + } 1.1481 + 1.1482 + 1.1483 + /* JS Entity */ 1.1484 + { 1.1485 + char *entityStart, *entityEnd; 1.1486 + HTMLItem * entityItem; 1.1487 + 1.1488 + /* go through each JavaScript entity ( &{...}; ) and store it 1.1489 + * in the entityList. The important thing is to record what 1.1490 + * line number it's on, so we can get it in the right order 1.1491 + * in relation to style= attributes. 1.1492 + * Apparently, these can't flow across lines, so the start and 1.1493 + * end line will be the same. That helps matters. 1.1494 + */ 1.1495 + entityEnd = pairp->value; 1.1496 + while ( entityEnd && 1.1497 + (entityStart = PL_strstr(entityEnd, "&{")) /*}*/ != NULL) { 1.1498 + entityStart += 2; /* point at beginning of actual entity */ 1.1499 + entityEnd = PL_strchr(entityStart, '}'); 1.1500 + if (entityEnd) { 1.1501 + /* Put this item on the entity list */ 1.1502 + *entityEnd = '\0'; 1.1503 + entityItem = CreateTextItem(PL_strdup(entityStart), 1.1504 + pairp->valueLine, pairp->valueLine); 1.1505 + *entityEnd = /* { */ '}'; 1.1506 + if (entityListTail) { 1.1507 + entityListTail->next = entityItem; 1.1508 + entityListTail = entityItem; 1.1509 + } else { 1.1510 + entityList = entityListTail = entityItem; 1.1511 + } 1.1512 + } 1.1513 + } 1.1514 + } 1.1515 + } 1.1516 + 1.1517 + /* If no archive was supplied, we use the first one of the file */ 1.1518 + if (!archiveDir && firstArchiveDir) { 1.1519 + archiveDir = PL_strdup(firstArchiveDir); 1.1520 + } 1.1521 + 1.1522 + /* If we have an event handler, we need to archive this tag */ 1.1523 + if (hasEventHandler) { 1.1524 + if (!id) { 1.1525 + PR_fprintf(errorFD, 1.1526 + "warning: tag starting at %s:%d has event handler but" 1.1527 + " no ID attribute. The tag will not be signed.\n", 1.1528 + filename, curitem->startLine); 1.1529 + warningCount++; 1.1530 + } else if (!archiveDir) { 1.1531 + PR_fprintf(errorFD, 1.1532 + "warning: tag starting at %s:%d has event handler but" 1.1533 + " no ARCHIVE attribute. The tag will not be signed.\n", 1.1534 + filename, curitem->startLine); 1.1535 + warningCount++; 1.1536 + } else { 1.1537 + if (SaveInlineScript(tagp->text, id, basedir, archiveDir)) { 1.1538 + goto loser; 1.1539 + } 1.1540 + } 1.1541 + } 1.1542 + 1.1543 + switch (tagp->type) { 1.1544 + case APPLET_TAG: 1.1545 + if (!src) { 1.1546 + PR_fprintf(errorFD, 1.1547 + "error: APPLET tag starting on %s:%d has no CODE " 1.1548 + "attribute.\n", filename, curitem->startLine); 1.1549 + errorCount++; 1.1550 + goto loser; 1.1551 + } else if (!archiveDir) { 1.1552 + PR_fprintf(errorFD, 1.1553 + "error: APPLET tag starting on %s:%d has no ARCHIVE " 1.1554 + "attribute.\n", filename, curitem->startLine); 1.1555 + errorCount++; 1.1556 + goto loser; 1.1557 + } else { 1.1558 + if (SaveSource(src, codebase, basedir, archiveDir)) { 1.1559 + goto loser; 1.1560 + } 1.1561 + } 1.1562 + break; 1.1563 + case SCRIPT_TAG: 1.1564 + case LINK_TAG: 1.1565 + case STYLE_TAG: 1.1566 + if (!archiveDir) { 1.1567 + PR_fprintf(errorFD, 1.1568 + "error: %s tag starting on %s:%d has no ARCHIVE " 1.1569 + "attribute.\n", TagTypeToString(tagp->type), 1.1570 + filename, curitem->startLine); 1.1571 + errorCount++; 1.1572 + goto loser; 1.1573 + } else if (src) { 1.1574 + if (SaveSource(src, codebase, basedir, archiveDir)) { 1.1575 + goto loser; 1.1576 + } 1.1577 + } else if (id) { 1.1578 + /* Save the next text item */ 1.1579 + if (!curitem->next || (curitem->next->type != 1.1580 + TEXT_ITEM)) { 1.1581 + PR_fprintf(errorFD, 1.1582 + "warning: %s tag starting on %s:%d is not followed" 1.1583 + " by script text.\n", TagTypeToString(tagp->type), 1.1584 + filename, curitem->startLine); 1.1585 + warningCount++; 1.1586 + /* just create empty file */ 1.1587 + if (SaveInlineScript("", id, basedir, archiveDir)) { 1.1588 + goto loser; 1.1589 + } 1.1590 + } else { 1.1591 + curitem = curitem->next; 1.1592 + if (SaveInlineScript(curitem->item.text, 1.1593 + id, basedir, 1.1594 + archiveDir)) { 1.1595 + goto loser; 1.1596 + } 1.1597 + } 1.1598 + } else { 1.1599 + /* No src or id tag--warning */ 1.1600 + PR_fprintf(errorFD, 1.1601 + "warning: %s tag starting on %s:%d has no SRC or" 1.1602 + " ID attributes. Will not sign.\n", 1.1603 + TagTypeToString(tagp->type), filename, curitem->startLine); 1.1604 + warningCount++; 1.1605 + } 1.1606 + break; 1.1607 + default: 1.1608 + /* do nothing for other tags */ 1.1609 + break; 1.1610 + } 1.1611 + 1.1612 + } 1.1613 + 1.1614 + /* Now deal with all the unnamable scripts */ 1.1615 + if (firstArchiveDir) { 1.1616 + HTMLItem * style, *entity; 1.1617 + 1.1618 + /* Go through the lists of JS entities and style attributes. Do them 1.1619 + * in chronological order within a list. Pick the list with the lower 1.1620 + * endLine. In case of a tie, entities come first. 1.1621 + */ 1.1622 + style = styleList; 1.1623 + entity = entityList; 1.1624 + while (style || entity) { 1.1625 + if (!entity || (style && (style->endLine < entity->endLine))) { 1.1626 + /* Process style */ 1.1627 + SaveUnnamableScript(style->item.text, basedir, firstArchiveDir, 1.1628 + filename); 1.1629 + style = style->next; 1.1630 + } else { 1.1631 + /* Process entity */ 1.1632 + SaveUnnamableScript(entity->item.text, basedir, firstArchiveDir, 1.1633 + filename); 1.1634 + entity = entity->next; 1.1635 + } 1.1636 + } 1.1637 + } 1.1638 + 1.1639 + 1.1640 + retval = 0; 1.1641 +loser: 1.1642 + /* Blow away the stream */ 1.1643 + while (head) { 1.1644 + curitem = head; 1.1645 + head = head->next; 1.1646 + DestroyHTMLItem(curitem); 1.1647 + } 1.1648 + while (styleList) { 1.1649 + curitem = styleList; 1.1650 + styleList = styleList->next; 1.1651 + DestroyHTMLItem(curitem); 1.1652 + } 1.1653 + while (entityList) { 1.1654 + curitem = entityList; 1.1655 + entityList = entityList->next; 1.1656 + DestroyHTMLItem(curitem); 1.1657 + } 1.1658 + if (text) { 1.1659 + PR_Free(text); 1.1660 + text = NULL; 1.1661 + } 1.1662 + if (fb) { 1.1663 + FB_Destroy(fb); 1.1664 + fb = NULL; 1.1665 + } 1.1666 + if (fd) { 1.1667 + PR_Close(fd); 1.1668 + } 1.1669 + if (tagerr) { 1.1670 + PR_smprintf_free(tagerr); 1.1671 + tagerr = NULL; 1.1672 + } 1.1673 + if (archiveDir) { 1.1674 + PR_Free(archiveDir); 1.1675 + archiveDir = NULL; 1.1676 + } 1.1677 + if (firstArchiveDir) { 1.1678 + PR_Free(firstArchiveDir); 1.1679 + firstArchiveDir = NULL; 1.1680 + } 1.1681 + return retval; 1.1682 +} 1.1683 + 1.1684 + 1.1685 +/********************************************************************** 1.1686 + * 1.1687 + * e n s u r e E x i s t s 1.1688 + * 1.1689 + * Check for existence of indicated directory. If it doesn't exist, 1.1690 + * it will be created. 1.1691 + * Returns PR_SUCCESS if the directory is present, PR_FAILURE otherwise. 1.1692 + */ 1.1693 +static PRStatus 1.1694 +ensureExists (char *base, char *path) 1.1695 +{ 1.1696 + char fn [FNSIZE]; 1.1697 + PRDir * dir; 1.1698 + sprintf (fn, "%s/%s", base, path); 1.1699 + 1.1700 + /*PR_fprintf(outputFD, "Trying to open directory %s.\n", fn);*/ 1.1701 + 1.1702 + if ( (dir = PR_OpenDir(fn)) ) { 1.1703 + PR_CloseDir(dir); 1.1704 + return PR_SUCCESS; 1.1705 + } 1.1706 + return PR_MkDir(fn, 0777); 1.1707 +} 1.1708 + 1.1709 + 1.1710 +/*************************************************************************** 1.1711 + * 1.1712 + * m a k e _ d i r s 1.1713 + * 1.1714 + * Ensure that the directory portion of the path exists. This may require 1.1715 + * making the directory, and its parent, and its parent's parent, etc. 1.1716 + */ 1.1717 +static int 1.1718 +make_dirs(char *path, int file_perms) 1.1719 +{ 1.1720 + char *Path; 1.1721 + char *start; 1.1722 + char *sep; 1.1723 + int ret = 0; 1.1724 + PRFileInfo info; 1.1725 + 1.1726 + if (!path) { 1.1727 + return 0; 1.1728 + } 1.1729 + 1.1730 + Path = PL_strdup(path); 1.1731 + start = strpbrk(Path, "/\\"); 1.1732 + if (!start) { 1.1733 + return 0; 1.1734 + } 1.1735 + start++; /* start right after first slash */ 1.1736 + 1.1737 + /* Each time through the loop add one more directory. */ 1.1738 + while ( (sep = strpbrk(start, "/\\")) ) { 1.1739 + *sep = '\0'; 1.1740 + 1.1741 + if ( PR_GetFileInfo(Path, &info) != PR_SUCCESS) { 1.1742 + /* No such dir, we have to create it */ 1.1743 + if ( PR_MkDir(Path, file_perms) != PR_SUCCESS) { 1.1744 + PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n", 1.1745 + Path); 1.1746 + errorCount++; 1.1747 + ret = -1; 1.1748 + goto loser; 1.1749 + } 1.1750 + } else { 1.1751 + /* something exists by this name, make sure it's a directory */ 1.1752 + if ( info.type != PR_FILE_DIRECTORY ) { 1.1753 + PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n", 1.1754 + Path); 1.1755 + errorCount++; 1.1756 + ret = -1; 1.1757 + goto loser; 1.1758 + } 1.1759 + } 1.1760 + 1.1761 + start = sep + 1; /* start after the next slash */ 1.1762 + *sep = '/'; 1.1763 + } 1.1764 + 1.1765 +loser: 1.1766 + PR_Free(Path); 1.1767 + return ret; 1.1768 +} 1.1769 + 1.1770 + 1.1771 +/* 1.1772 + * c o p y i n t o 1.1773 + * 1.1774 + * Function to copy file "from" to path "to". 1.1775 + * 1.1776 + */ 1.1777 +static int 1.1778 +copyinto (char *from, char *to) 1.1779 +{ 1.1780 + PRInt32 num; 1.1781 + char buf [BUFSIZ]; 1.1782 + PRFileDesc * infp = NULL, *outfp = NULL; 1.1783 + int retval = -1; 1.1784 + 1.1785 + if ((infp = PR_Open(from, PR_RDONLY, 0777)) == NULL) { 1.1786 + PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for reading.\n", 1.1787 + from); 1.1788 + errorCount++; 1.1789 + goto finish; 1.1790 + } 1.1791 + 1.1792 + /* If to already exists, print a warning before deleting it */ 1.1793 + if (PR_Access(to, PR_ACCESS_EXISTS) == PR_SUCCESS) { 1.1794 + PR_fprintf(errorFD, "warning: %s already exists--will overwrite\n", to); 1.1795 + warningCount++; 1.1796 + if (rm_dash_r(to)) { 1.1797 + PR_fprintf(errorFD, 1.1798 + "ERROR: Unable to remove %s.\n", to); 1.1799 + errorCount++; 1.1800 + goto finish; 1.1801 + } 1.1802 + } 1.1803 + 1.1804 + if ((outfp = PR_Open(to, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777)) 1.1805 + == NULL) { 1.1806 + char *errBuf = NULL; 1.1807 + 1.1808 + errBuf = PR_Malloc(PR_GetErrorTextLength() + 1); 1.1809 + PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for writing.\n", to); 1.1810 + if (PR_GetErrorText(errBuf)) { 1.1811 + PR_fprintf(errorFD, "Cause: %s\n", errBuf); 1.1812 + } 1.1813 + if (errBuf) { 1.1814 + PR_Free(errBuf); 1.1815 + } 1.1816 + errorCount++; 1.1817 + goto finish; 1.1818 + } 1.1819 + 1.1820 + while ( (num = PR_Read(infp, buf, BUFSIZ)) > 0) { 1.1821 + if (PR_Write(outfp, buf, num) != num) { 1.1822 + PR_fprintf(errorFD, "ERROR: Error writing to %s.\n", to); 1.1823 + errorCount++; 1.1824 + goto finish; 1.1825 + } 1.1826 + } 1.1827 + 1.1828 + retval = 0; 1.1829 +finish: 1.1830 + if (infp) 1.1831 + PR_Close(infp); 1.1832 + if (outfp) 1.1833 + PR_Close(outfp); 1.1834 + 1.1835 + return retval; 1.1836 +} 1.1837 + 1.1838 +