security/nss/cmd/signtool/javascript.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "signtool.h"
michael@0 6 #include <prmem.h>
michael@0 7 #include <prio.h>
michael@0 8 #include <prenv.h>
michael@0 9
michael@0 10 static int javascript_fn(char *relpath, char *basedir, char *reldir,
michael@0 11 char *filename, void *arg);
michael@0 12 static int extract_js (char *filename);
michael@0 13 static int copyinto (char *from, char *to);
michael@0 14 static PRStatus ensureExists (char *base, char *path);
michael@0 15 static int make_dirs(char *path, PRInt32 file_perms);
michael@0 16
michael@0 17 static char *jartree = NULL;
michael@0 18 static int idOrdinal;
michael@0 19 static PRBool dumpParse = PR_FALSE;
michael@0 20
michael@0 21 static char *event_handlers[] = {
michael@0 22 "onAbort",
michael@0 23 "onBlur",
michael@0 24 "onChange",
michael@0 25 "onClick",
michael@0 26 "onDblClick",
michael@0 27 "onDragDrop",
michael@0 28 "onError",
michael@0 29 "onFocus",
michael@0 30 "onKeyDown",
michael@0 31 "onKeyPress",
michael@0 32 "onKeyUp",
michael@0 33 "onLoad",
michael@0 34 "onMouseDown",
michael@0 35 "onMouseMove",
michael@0 36 "onMouseOut",
michael@0 37 "onMouseOver",
michael@0 38 "onMouseUp",
michael@0 39 "onMove",
michael@0 40 "onReset",
michael@0 41 "onResize",
michael@0 42 "onSelect",
michael@0 43 "onSubmit",
michael@0 44 "onUnload"
michael@0 45 };
michael@0 46
michael@0 47
michael@0 48 static int num_handlers = 23;
michael@0 49
michael@0 50 /*
michael@0 51 * I n l i n e J a v a S c r i p t
michael@0 52 *
michael@0 53 * Javascript signing. Instead of passing an archive to signtool,
michael@0 54 * a directory containing html files is given. Archives are created
michael@0 55 * from the archive= and src= tag attributes inside the html,
michael@0 56 * as appropriate. Then the archives are signed.
michael@0 57 *
michael@0 58 */
michael@0 59 int
michael@0 60 InlineJavaScript(char *dir, PRBool recurse)
michael@0 61 {
michael@0 62 jartree = dir;
michael@0 63 if (verbosity >= 0) {
michael@0 64 PR_fprintf(outputFD, "\nGenerating inline signatures from HTML files in: %s\n",
michael@0 65 dir);
michael@0 66 }
michael@0 67 if (PR_GetEnv("SIGNTOOL_DUMP_PARSE")) {
michael@0 68 dumpParse = PR_TRUE;
michael@0 69 }
michael@0 70
michael@0 71 return foreach(dir, "", javascript_fn, recurse, PR_FALSE /*include dirs*/,
michael@0 72 (void * )NULL);
michael@0 73
michael@0 74 }
michael@0 75
michael@0 76
michael@0 77 /************************************************************************
michael@0 78 *
michael@0 79 * j a v a s c r i p t _ f n
michael@0 80 */
michael@0 81 static int javascript_fn
michael@0 82 (char *relpath, char *basedir, char *reldir, char *filename, void *arg)
michael@0 83 {
michael@0 84 char fullname [FNSIZE];
michael@0 85
michael@0 86 /* only process inline scripts from .htm, .html, and .shtml*/
michael@0 87
michael@0 88 if (!(PL_strcaserstr(filename, ".htm") == filename + strlen(filename) -
michael@0 89 4) &&
michael@0 90 !(PL_strcaserstr(filename, ".html") == filename + strlen(filename) -
michael@0 91 5) &&
michael@0 92 !(PL_strcaserstr(filename, ".shtml") == filename + strlen(filename)
michael@0 93 -6)) {
michael@0 94 return 0;
michael@0 95 }
michael@0 96
michael@0 97 /* don't process scripts that signtool has already
michael@0 98 extracted (those that are inside .arc directories) */
michael@0 99
michael@0 100 if (PL_strcaserstr(filename, ".arc") == filename + strlen(filename) - 4)
michael@0 101 return 0;
michael@0 102
michael@0 103 if (verbosity >= 0) {
michael@0 104 PR_fprintf(outputFD, "Processing HTML file: %s\n", relpath);
michael@0 105 }
michael@0 106
michael@0 107 /* reset firstArchive at top of each HTML file */
michael@0 108
michael@0 109 /* skip directories that contain extracted scripts */
michael@0 110
michael@0 111 if (PL_strcaserstr(reldir, ".arc") == reldir + strlen(reldir) - 4)
michael@0 112 return 0;
michael@0 113
michael@0 114 sprintf (fullname, "%s/%s", basedir, relpath);
michael@0 115 return extract_js (fullname);
michael@0 116 }
michael@0 117
michael@0 118
michael@0 119 /*===========================================================================
michael@0 120 =
michael@0 121 = D A T A S T R U C T U R E S
michael@0 122 =
michael@0 123 */
michael@0 124 typedef enum {
michael@0 125 TEXT_HTML_STATE = 0,
michael@0 126 SCRIPT_HTML_STATE
michael@0 127 }
michael@0 128
michael@0 129
michael@0 130 HTML_STATE ;
michael@0 131
michael@0 132 typedef enum {
michael@0 133 /* we start in the start state */
michael@0 134 START_STATE,
michael@0 135
michael@0 136 /* We are looking for or reading in an attribute */
michael@0 137 GET_ATT_STATE,
michael@0 138
michael@0 139 /* We're burning ws before finding an attribute */
michael@0 140 PRE_ATT_WS_STATE,
michael@0 141
michael@0 142 /* We're burning ws after an attribute. Looking for an '='. */
michael@0 143 POST_ATT_WS_STATE,
michael@0 144
michael@0 145 /* We're burning ws after an '=', waiting for a value */
michael@0 146 PRE_VAL_WS_STATE,
michael@0 147
michael@0 148 /* We're reading in a value */
michael@0 149 GET_VALUE_STATE,
michael@0 150
michael@0 151 /* We're reading in a value that's inside quotes */
michael@0 152 GET_QUOTED_VAL_STATE,
michael@0 153
michael@0 154 /* We've encountered the closing '>' */
michael@0 155 DONE_STATE,
michael@0 156
michael@0 157 /* Error state */
michael@0 158 ERR_STATE
michael@0 159 }
michael@0 160
michael@0 161
michael@0 162 TAG_STATE ;
michael@0 163
michael@0 164 typedef struct AVPair_Str {
michael@0 165 char *attribute;
michael@0 166 char *value;
michael@0 167 unsigned int valueLine; /* the line that the value ends on */
michael@0 168 struct AVPair_Str *next;
michael@0 169 } AVPair;
michael@0 170
michael@0 171 typedef enum {
michael@0 172 APPLET_TAG,
michael@0 173 SCRIPT_TAG,
michael@0 174 LINK_TAG,
michael@0 175 STYLE_TAG,
michael@0 176 COMMENT_TAG,
michael@0 177 OTHER_TAG
michael@0 178 }
michael@0 179
michael@0 180
michael@0 181 TAG_TYPE ;
michael@0 182
michael@0 183 typedef struct {
michael@0 184 TAG_TYPE type;
michael@0 185 AVPair * attList;
michael@0 186 AVPair * attListTail;
michael@0 187 char *text;
michael@0 188 } TagItem;
michael@0 189
michael@0 190 typedef enum {
michael@0 191 TAG_ITEM,
michael@0 192 TEXT_ITEM
michael@0 193 }
michael@0 194
michael@0 195
michael@0 196 ITEM_TYPE ;
michael@0 197
michael@0 198 typedef struct HTMLItem_Str {
michael@0 199 unsigned int startLine;
michael@0 200 unsigned int endLine;
michael@0 201 ITEM_TYPE type;
michael@0 202 union {
michael@0 203 TagItem *tag;
michael@0 204 char *text;
michael@0 205 } item;
michael@0 206 struct HTMLItem_Str *next;
michael@0 207 } HTMLItem;
michael@0 208
michael@0 209 typedef struct {
michael@0 210 PRFileDesc *fd;
michael@0 211 PRInt32 curIndex;
michael@0 212 PRBool IsEOF;
michael@0 213 #define FILE_BUFFER_BUFSIZE 512
michael@0 214 char buf[FILE_BUFFER_BUFSIZE];
michael@0 215 PRInt32 startOffset;
michael@0 216 PRInt32 maxIndex;
michael@0 217 unsigned int lineNum;
michael@0 218 } FileBuffer;
michael@0 219
michael@0 220 /*===========================================================================
michael@0 221 =
michael@0 222 = F U N C T I O N S
michael@0 223 =
michael@0 224 */
michael@0 225 static HTMLItem*CreateTextItem(char *text, unsigned int startline,
michael@0 226 unsigned int endline);
michael@0 227 static HTMLItem*CreateTagItem(TagItem*ti, unsigned int startline,
michael@0 228 unsigned int endline);
michael@0 229 static TagItem*ProcessTag(FileBuffer*fb, char **errStr);
michael@0 230 static void DestroyHTMLItem(HTMLItem *item);
michael@0 231 static void DestroyTagItem(TagItem*ti);
michael@0 232 static TAG_TYPE GetTagType(char *att);
michael@0 233 static FileBuffer*FB_Create(PRFileDesc*fd);
michael@0 234 static int FB_GetChar(FileBuffer *fb);
michael@0 235 static PRInt32 FB_GetPointer(FileBuffer *fb);
michael@0 236 static PRInt32 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end,
michael@0 237 char **buf);
michael@0 238 static unsigned int FB_GetLineNum(FileBuffer *fb);
michael@0 239 static void FB_Destroy(FileBuffer *fb);
michael@0 240 static void PrintTagItem(PRFileDesc *fd, TagItem *ti);
michael@0 241 static void PrintHTMLStream(PRFileDesc *fd, HTMLItem *head);
michael@0 242
michael@0 243 /************************************************************************
michael@0 244 *
michael@0 245 * C r e a t e T e x t I t e m
michael@0 246 */
michael@0 247 static HTMLItem*
michael@0 248 CreateTextItem(char *text, unsigned int startline, unsigned int endline)
michael@0 249 {
michael@0 250 HTMLItem * item;
michael@0 251
michael@0 252 item = PR_Malloc(sizeof(HTMLItem));
michael@0 253 if (!item) {
michael@0 254 return NULL;
michael@0 255 }
michael@0 256
michael@0 257 item->type = TEXT_ITEM;
michael@0 258 item->item.text = text;
michael@0 259 item->next = NULL;
michael@0 260 item->startLine = startline;
michael@0 261 item->endLine = endline;
michael@0 262
michael@0 263 return item;
michael@0 264 }
michael@0 265
michael@0 266
michael@0 267 /************************************************************************
michael@0 268 *
michael@0 269 * C r e a t e T a g I t e m
michael@0 270 */
michael@0 271 static HTMLItem*
michael@0 272 CreateTagItem(TagItem*ti, unsigned int startline, unsigned int endline)
michael@0 273 {
michael@0 274 HTMLItem * item;
michael@0 275
michael@0 276 item = PR_Malloc(sizeof(HTMLItem));
michael@0 277 if (!item) {
michael@0 278 return NULL;
michael@0 279 }
michael@0 280
michael@0 281 item->type = TAG_ITEM;
michael@0 282 item->item.tag = ti;
michael@0 283 item->next = NULL;
michael@0 284 item->startLine = startline;
michael@0 285 item->endLine = endline;
michael@0 286
michael@0 287 return item;
michael@0 288 }
michael@0 289
michael@0 290
michael@0 291 static PRBool
michael@0 292 isAttChar(int c)
michael@0 293 {
michael@0 294 return (isalnum(c) || c == '/' || c == '-');
michael@0 295 }
michael@0 296
michael@0 297
michael@0 298 /************************************************************************
michael@0 299 *
michael@0 300 * P r o c e s s T a g
michael@0 301 */
michael@0 302 static TagItem*
michael@0 303 ProcessTag(FileBuffer*fb, char **errStr)
michael@0 304 {
michael@0 305 TAG_STATE state;
michael@0 306 PRInt32 startText, startID, curPos;
michael@0 307 PRBool firstAtt;
michael@0 308 int curchar;
michael@0 309 TagItem * ti = NULL;
michael@0 310 AVPair * curPair = NULL;
michael@0 311 char quotechar = '\0';
michael@0 312 unsigned int linenum;
michael@0 313 unsigned int startline;
michael@0 314
michael@0 315 state = START_STATE;
michael@0 316
michael@0 317 startID = FB_GetPointer(fb);
michael@0 318 startText = startID;
michael@0 319 firstAtt = PR_TRUE;
michael@0 320
michael@0 321 ti = (TagItem * ) PR_Malloc(sizeof(TagItem));
michael@0 322 if (!ti)
michael@0 323 out_of_memory();
michael@0 324 ti->type = OTHER_TAG;
michael@0 325 ti->attList = NULL;
michael@0 326 ti->attListTail = NULL;
michael@0 327 ti->text = NULL;
michael@0 328
michael@0 329 startline = FB_GetLineNum(fb);
michael@0 330
michael@0 331 while (state != DONE_STATE && state != ERR_STATE) {
michael@0 332 linenum = FB_GetLineNum(fb);
michael@0 333 curchar = FB_GetChar(fb);
michael@0 334 if (curchar == EOF) {
michael@0 335 *errStr = PR_smprintf(
michael@0 336 "line %d: Unexpected end-of-file while parsing tag starting at line %d.\n",
michael@0 337 linenum, startline);
michael@0 338 state = ERR_STATE;
michael@0 339 continue;
michael@0 340 }
michael@0 341
michael@0 342 switch (state) {
michael@0 343 case START_STATE:
michael@0 344 if (curchar == '!') {
michael@0 345 /*
michael@0 346 * SGML tag or comment
michael@0 347 * Here's the general rule for SGML tags. Everything from
michael@0 348 * <! to > is the tag. Inside the tag, comments are
michael@0 349 * delimited with --. So we are looking for the first '>'
michael@0 350 * that is not commented out, that is, not inside a pair
michael@0 351 * of --: <!DOCTYPE --this is a comment >(psyche!) -->
michael@0 352 */
michael@0 353
michael@0 354 PRBool inComment = PR_FALSE;
michael@0 355 short hyphenCount = 0; /* number of consecutive hyphens */
michael@0 356
michael@0 357 while (1) {
michael@0 358 linenum = FB_GetLineNum(fb);
michael@0 359 curchar = FB_GetChar(fb);
michael@0 360 if (curchar == EOF) {
michael@0 361 /* Uh oh, EOF inside comment */
michael@0 362 *errStr = PR_smprintf(
michael@0 363 "line %d: Unexpected end-of-file inside comment starting at line %d.\n",
michael@0 364 linenum, startline);
michael@0 365 state = ERR_STATE;
michael@0 366 break;
michael@0 367 }
michael@0 368 if (curchar == '-') {
michael@0 369 if (hyphenCount == 1) {
michael@0 370 /* This is a comment delimiter */
michael@0 371 inComment = !inComment;
michael@0 372 hyphenCount = 0;
michael@0 373 } else {
michael@0 374 /* beginning of a comment delimiter? */
michael@0 375 hyphenCount = 1;
michael@0 376 }
michael@0 377 } else if (curchar == '>') {
michael@0 378 if (!inComment) {
michael@0 379 /* This is the end of the tag */
michael@0 380 state = DONE_STATE;
michael@0 381 break;
michael@0 382 } else {
michael@0 383 /* The > is inside a comment, so it's not
michael@0 384 * really the end of the tag */
michael@0 385 hyphenCount = 0;
michael@0 386 }
michael@0 387 } else {
michael@0 388 hyphenCount = 0;
michael@0 389 }
michael@0 390 }
michael@0 391 ti->type = COMMENT_TAG;
michael@0 392 break;
michael@0 393 }
michael@0 394 /* fall through */
michael@0 395 case GET_ATT_STATE:
michael@0 396 if (isspace(curchar) || curchar == '=' || curchar
michael@0 397 == '>') {
michael@0 398 /* end of the current attribute */
michael@0 399 curPos = FB_GetPointer(fb) - 2;
michael@0 400 if (curPos >= startID) {
michael@0 401 /* We have an attribute */
michael@0 402 curPair = (AVPair * )PR_Malloc(sizeof(AVPair));
michael@0 403 if (!curPair)
michael@0 404 out_of_memory();
michael@0 405 curPair->value = NULL;
michael@0 406 curPair->next = NULL;
michael@0 407 FB_GetRange(fb, startID, curPos,
michael@0 408 &curPair->attribute);
michael@0 409
michael@0 410 /* Stick this attribute on the list */
michael@0 411 if (ti->attListTail) {
michael@0 412 ti->attListTail->next = curPair;
michael@0 413 ti->attListTail = curPair;
michael@0 414 } else {
michael@0 415 ti->attList = ti->attListTail =
michael@0 416 curPair;
michael@0 417 }
michael@0 418
michael@0 419 /* If this is the first attribute, find the type of tag
michael@0 420 * based on it. Also, start saving the text of the tag. */
michael@0 421 if (firstAtt) {
michael@0 422 ti->type = GetTagType(curPair->attribute);
michael@0 423 startText = FB_GetPointer(fb)
michael@0 424 -1;
michael@0 425 firstAtt = PR_FALSE;
michael@0 426 }
michael@0 427 } else {
michael@0 428 if (curchar == '=') {
michael@0 429 /* If we don't have any attribute but we do have an
michael@0 430 * equal sign, that's an error */
michael@0 431 *errStr = PR_smprintf("line %d: Malformed tag starting at line %d.\n",
michael@0 432 linenum, startline);
michael@0 433 state = ERR_STATE;
michael@0 434 break;
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 /* Compute next state */
michael@0 439 if (curchar == '=') {
michael@0 440 startID = FB_GetPointer(fb);
michael@0 441 state = PRE_VAL_WS_STATE;
michael@0 442 } else if (curchar == '>') {
michael@0 443 state = DONE_STATE;
michael@0 444 } else if (curPair) {
michael@0 445 state = POST_ATT_WS_STATE;
michael@0 446 } else {
michael@0 447 state = PRE_ATT_WS_STATE;
michael@0 448 }
michael@0 449 } else if (isAttChar(curchar)) {
michael@0 450 /* Just another char in the attribute. Do nothing */
michael@0 451 state = GET_ATT_STATE;
michael@0 452 } else {
michael@0 453 /* bogus char */
michael@0 454 *errStr = PR_smprintf("line %d: Bogus chararacter '%c' in tag.\n",
michael@0 455 linenum, curchar);
michael@0 456 state = ERR_STATE;
michael@0 457 break;
michael@0 458 }
michael@0 459 break;
michael@0 460 case PRE_ATT_WS_STATE:
michael@0 461 if (curchar == '>') {
michael@0 462 state = DONE_STATE;
michael@0 463 } else if (isspace(curchar)) {
michael@0 464 /* more whitespace, do nothing */
michael@0 465 } else if (isAttChar(curchar)) {
michael@0 466 /* starting another attribute */
michael@0 467 startID = FB_GetPointer(fb) - 1;
michael@0 468 state = GET_ATT_STATE;
michael@0 469 } else {
michael@0 470 /* bogus char */
michael@0 471 *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
michael@0 472 linenum, curchar);
michael@0 473 state = ERR_STATE;
michael@0 474 break;
michael@0 475 }
michael@0 476 break;
michael@0 477 case POST_ATT_WS_STATE:
michael@0 478 if (curchar == '>') {
michael@0 479 state = DONE_STATE;
michael@0 480 } else if (isspace(curchar)) {
michael@0 481 /* more whitespace, do nothing */
michael@0 482 } else if (isAttChar(curchar)) {
michael@0 483 /* starting another attribute */
michael@0 484 startID = FB_GetPointer(fb) - 1;
michael@0 485 state = GET_ATT_STATE;
michael@0 486 } else if (curchar == '=') {
michael@0 487 /* there was whitespace between the attribute and its equal
michael@0 488 * sign, which means there's a value coming up */
michael@0 489 state = PRE_VAL_WS_STATE;
michael@0 490 } else {
michael@0 491 /* bogus char */
michael@0 492 *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
michael@0 493 linenum, curchar);
michael@0 494 state = ERR_STATE;
michael@0 495 break;
michael@0 496 }
michael@0 497 break;
michael@0 498 case PRE_VAL_WS_STATE:
michael@0 499 if (curchar == '>') {
michael@0 500 /* premature end-of-tag (sounds like a personal problem). */
michael@0 501 *errStr = PR_smprintf(
michael@0 502 "line %d: End of tag while waiting for value.\n",
michael@0 503 linenum);
michael@0 504 state = ERR_STATE;
michael@0 505 break;
michael@0 506 } else if (isspace(curchar)) {
michael@0 507 /* more whitespace, do nothing */
michael@0 508 break;
michael@0 509 } else {
michael@0 510 /* this must be some sort of value. Fall through
michael@0 511 * to GET_VALUE_STATE */
michael@0 512 startID = FB_GetPointer(fb) - 1;
michael@0 513 state = GET_VALUE_STATE;
michael@0 514 }
michael@0 515 /* Fall through if we didn't break on '>' or whitespace */
michael@0 516 case GET_VALUE_STATE:
michael@0 517 if (isspace(curchar) || curchar == '>') {
michael@0 518 /* end of value */
michael@0 519 curPos = FB_GetPointer(fb) - 2;
michael@0 520 if (curPos >= startID) {
michael@0 521 /* Grab the value */
michael@0 522 FB_GetRange(fb, startID, curPos,
michael@0 523 &curPair->value);
michael@0 524 curPair->valueLine = linenum;
michael@0 525 } else {
michael@0 526 /* empty value, leave as NULL */
michael@0 527 }
michael@0 528 if (isspace(curchar)) {
michael@0 529 state = PRE_ATT_WS_STATE;
michael@0 530 } else {
michael@0 531 state = DONE_STATE;
michael@0 532 }
michael@0 533 } else if (curchar == '\"' || curchar == '\'') {
michael@0 534 /* quoted value. Start recording the value inside the quote*/
michael@0 535 startID = FB_GetPointer(fb);
michael@0 536 state = GET_QUOTED_VAL_STATE;
michael@0 537 PORT_Assert(quotechar == '\0');
michael@0 538 quotechar = curchar; /* look for matching quote type */
michael@0 539 } else {
michael@0 540 /* just more value */
michael@0 541 }
michael@0 542 break;
michael@0 543 case GET_QUOTED_VAL_STATE:
michael@0 544 PORT_Assert(quotechar != '\0');
michael@0 545 if (curchar == quotechar) {
michael@0 546 /* end of quoted value */
michael@0 547 curPos = FB_GetPointer(fb) - 2;
michael@0 548 if (curPos >= startID) {
michael@0 549 /* Grab the value */
michael@0 550 FB_GetRange(fb, startID, curPos,
michael@0 551 &curPair->value);
michael@0 552 curPair->valueLine = linenum;
michael@0 553 } else {
michael@0 554 /* empty value, leave it as NULL */
michael@0 555 }
michael@0 556 state = GET_ATT_STATE;
michael@0 557 quotechar = '\0';
michael@0 558 startID = FB_GetPointer(fb);
michael@0 559 } else {
michael@0 560 /* more quoted value, continue */
michael@0 561 }
michael@0 562 break;
michael@0 563 case DONE_STATE:
michael@0 564 case ERR_STATE:
michael@0 565 default:
michael@0 566 ; /* should never get here */
michael@0 567 }
michael@0 568 }
michael@0 569
michael@0 570 if (state == DONE_STATE) {
michael@0 571 /* Get the text of the tag */
michael@0 572 curPos = FB_GetPointer(fb) - 1;
michael@0 573 FB_GetRange(fb, startText, curPos, &ti->text);
michael@0 574
michael@0 575 /* Return the tag */
michael@0 576 return ti;
michael@0 577 }
michael@0 578
michael@0 579 /* Uh oh, an error. Kill the tag item*/
michael@0 580 DestroyTagItem(ti);
michael@0 581 return NULL;
michael@0 582 }
michael@0 583
michael@0 584
michael@0 585 /************************************************************************
michael@0 586 *
michael@0 587 * D e s t r o y H T M L I t e m
michael@0 588 */
michael@0 589 static void
michael@0 590 DestroyHTMLItem(HTMLItem *item)
michael@0 591 {
michael@0 592 if (item->type == TAG_ITEM) {
michael@0 593 DestroyTagItem(item->item.tag);
michael@0 594 } else {
michael@0 595 if (item->item.text) {
michael@0 596 PR_Free(item->item.text);
michael@0 597 }
michael@0 598 }
michael@0 599 }
michael@0 600
michael@0 601
michael@0 602 /************************************************************************
michael@0 603 *
michael@0 604 * D e s t r o y T a g I t e m
michael@0 605 */
michael@0 606 static void
michael@0 607 DestroyTagItem(TagItem*ti)
michael@0 608 {
michael@0 609 AVPair * temp;
michael@0 610
michael@0 611 if (ti->text) {
michael@0 612 PR_Free(ti->text);
michael@0 613 ti->text = NULL;
michael@0 614 }
michael@0 615
michael@0 616 while (ti->attList) {
michael@0 617 temp = ti->attList;
michael@0 618 ti->attList = ti->attList->next;
michael@0 619
michael@0 620 if (temp->attribute) {
michael@0 621 PR_Free(temp->attribute);
michael@0 622 temp->attribute = NULL;
michael@0 623 }
michael@0 624 if (temp->value) {
michael@0 625 PR_Free(temp->value);
michael@0 626 temp->value = NULL;
michael@0 627 }
michael@0 628 PR_Free(temp);
michael@0 629 }
michael@0 630
michael@0 631 PR_Free(ti);
michael@0 632 }
michael@0 633
michael@0 634
michael@0 635 /************************************************************************
michael@0 636 *
michael@0 637 * G e t T a g T y p e
michael@0 638 */
michael@0 639 static TAG_TYPE
michael@0 640 GetTagType(char *att)
michael@0 641 {
michael@0 642 if (!PORT_Strcasecmp(att, "APPLET")) {
michael@0 643 return APPLET_TAG;
michael@0 644 }
michael@0 645 if (!PORT_Strcasecmp(att, "SCRIPT")) {
michael@0 646 return SCRIPT_TAG;
michael@0 647 }
michael@0 648 if (!PORT_Strcasecmp(att, "LINK")) {
michael@0 649 return LINK_TAG;
michael@0 650 }
michael@0 651 if (!PORT_Strcasecmp(att, "STYLE")) {
michael@0 652 return STYLE_TAG;
michael@0 653 }
michael@0 654 return OTHER_TAG;
michael@0 655 }
michael@0 656
michael@0 657
michael@0 658 /************************************************************************
michael@0 659 *
michael@0 660 * F B _ C r e a t e
michael@0 661 */
michael@0 662 static FileBuffer*
michael@0 663 FB_Create(PRFileDesc*fd)
michael@0 664 {
michael@0 665 FileBuffer * fb;
michael@0 666 PRInt32 amountRead;
michael@0 667 PRInt32 storedOffset;
michael@0 668
michael@0 669 fb = (FileBuffer * ) PR_Malloc(sizeof(FileBuffer));
michael@0 670 fb->fd = fd;
michael@0 671 storedOffset = PR_Seek(fd, 0, PR_SEEK_CUR);
michael@0 672 PR_Seek(fd, 0, PR_SEEK_SET);
michael@0 673 fb->startOffset = 0;
michael@0 674 amountRead = PR_Read(fd, fb->buf, FILE_BUFFER_BUFSIZE);
michael@0 675 if (amountRead == -1)
michael@0 676 goto loser;
michael@0 677 fb->maxIndex = amountRead - 1;
michael@0 678 fb->curIndex = 0;
michael@0 679 fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;
michael@0 680 fb->lineNum = 1;
michael@0 681
michael@0 682 PR_Seek(fd, storedOffset, PR_SEEK_SET);
michael@0 683 return fb;
michael@0 684 loser:
michael@0 685 PR_Seek(fd, storedOffset, PR_SEEK_SET);
michael@0 686 PR_Free(fb);
michael@0 687 return NULL;
michael@0 688 }
michael@0 689
michael@0 690
michael@0 691 /************************************************************************
michael@0 692 *
michael@0 693 * F B _ G e t C h a r
michael@0 694 */
michael@0 695 static int
michael@0 696 FB_GetChar(FileBuffer *fb)
michael@0 697 {
michael@0 698 PRInt32 storedOffset;
michael@0 699 PRInt32 amountRead;
michael@0 700 int retval = -1;
michael@0 701
michael@0 702 if (fb->IsEOF) {
michael@0 703 return EOF;
michael@0 704 }
michael@0 705
michael@0 706 storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);
michael@0 707
michael@0 708 retval = (unsigned char) fb->buf[fb->curIndex++];
michael@0 709 if (retval == '\n')
michael@0 710 fb->lineNum++;
michael@0 711
michael@0 712 if (fb->curIndex > fb->maxIndex) {
michael@0 713 /* We're at the end of the buffer. Try to get some new data from the
michael@0 714 * file */
michael@0 715 fb->startOffset += fb->maxIndex + 1;
michael@0 716 PR_Seek(fb->fd, fb->startOffset, PR_SEEK_SET);
michael@0 717 amountRead = PR_Read(fb->fd, fb->buf, FILE_BUFFER_BUFSIZE);
michael@0 718 if (amountRead == -1)
michael@0 719 goto loser;
michael@0 720 fb->maxIndex = amountRead - 1;
michael@0 721 fb->curIndex = 0;
michael@0 722 }
michael@0 723
michael@0 724 fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;
michael@0 725
michael@0 726 loser:
michael@0 727 PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
michael@0 728 return retval;
michael@0 729 }
michael@0 730
michael@0 731
michael@0 732 /************************************************************************
michael@0 733 *
michael@0 734 * F B _ G e t L i n e N u m
michael@0 735 *
michael@0 736 */
michael@0 737 static unsigned int
michael@0 738 FB_GetLineNum(FileBuffer *fb)
michael@0 739 {
michael@0 740 return fb->lineNum;
michael@0 741 }
michael@0 742
michael@0 743
michael@0 744 /************************************************************************
michael@0 745 *
michael@0 746 * F B _ G e t P o i n t e r
michael@0 747 *
michael@0 748 */
michael@0 749 static PRInt32
michael@0 750 FB_GetPointer(FileBuffer *fb)
michael@0 751 {
michael@0 752 return fb->startOffset + fb->curIndex;
michael@0 753 }
michael@0 754
michael@0 755
michael@0 756 /************************************************************************
michael@0 757 *
michael@0 758 * F B _ G e t R a n g e
michael@0 759 *
michael@0 760 */
michael@0 761 static PRInt32
michael@0 762 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, char **buf)
michael@0 763 {
michael@0 764 PRInt32 amountRead;
michael@0 765 PRInt32 storedOffset;
michael@0 766
michael@0 767 *buf = PR_Malloc(end - start + 2);
michael@0 768 if (*buf == NULL) {
michael@0 769 return 0;
michael@0 770 }
michael@0 771
michael@0 772 storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);
michael@0 773 PR_Seek(fb->fd, start, PR_SEEK_SET);
michael@0 774 amountRead = PR_Read(fb->fd, *buf, end - start + 1);
michael@0 775 PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
michael@0 776 if (amountRead == -1) {
michael@0 777 PR_Free(*buf);
michael@0 778 *buf = NULL;
michael@0 779 return 0;
michael@0 780 }
michael@0 781
michael@0 782 (*buf)[end-start+1] = '\0';
michael@0 783 return amountRead;
michael@0 784 }
michael@0 785
michael@0 786
michael@0 787 /************************************************************************
michael@0 788 *
michael@0 789 * F B _ D e s t r o y
michael@0 790 *
michael@0 791 */
michael@0 792 static void
michael@0 793 FB_Destroy(FileBuffer *fb)
michael@0 794 {
michael@0 795 if (fb) {
michael@0 796 PR_Free(fb);
michael@0 797 }
michael@0 798 }
michael@0 799
michael@0 800
michael@0 801 /************************************************************************
michael@0 802 *
michael@0 803 * P r i n t T a g I t e m
michael@0 804 *
michael@0 805 */
michael@0 806 static void
michael@0 807 PrintTagItem(PRFileDesc *fd, TagItem *ti)
michael@0 808 {
michael@0 809 AVPair * pair;
michael@0 810
michael@0 811 PR_fprintf(fd, "TAG:\n----\nType: ");
michael@0 812 switch (ti->type) {
michael@0 813 case APPLET_TAG:
michael@0 814 PR_fprintf(fd, "applet\n");
michael@0 815 break;
michael@0 816 case SCRIPT_TAG:
michael@0 817 PR_fprintf(fd, "script\n");
michael@0 818 break;
michael@0 819 case LINK_TAG:
michael@0 820 PR_fprintf(fd, "link\n");
michael@0 821 break;
michael@0 822 case STYLE_TAG:
michael@0 823 PR_fprintf(fd, "style\n");
michael@0 824 break;
michael@0 825 case COMMENT_TAG:
michael@0 826 PR_fprintf(fd, "comment\n");
michael@0 827 break;
michael@0 828 case OTHER_TAG:
michael@0 829 default:
michael@0 830 PR_fprintf(fd, "other\n");
michael@0 831 break;
michael@0 832 }
michael@0 833
michael@0 834 PR_fprintf(fd, "Attributes:\n");
michael@0 835 for (pair = ti->attList; pair; pair = pair->next) {
michael@0 836 PR_fprintf(fd, "\t%s=%s\n", pair->attribute,
michael@0 837 pair->value ? pair->value : "");
michael@0 838 }
michael@0 839 PR_fprintf(fd, "Text:%s\n", ti->text ? ti->text : "");
michael@0 840
michael@0 841 PR_fprintf(fd, "---End of tag---\n");
michael@0 842 }
michael@0 843
michael@0 844
michael@0 845 /************************************************************************
michael@0 846 *
michael@0 847 * P r i n t H T M L S t r e a m
michael@0 848 *
michael@0 849 */
michael@0 850 static void
michael@0 851 PrintHTMLStream(PRFileDesc *fd, HTMLItem *head)
michael@0 852 {
michael@0 853 while (head) {
michael@0 854 if (head->type == TAG_ITEM) {
michael@0 855 PrintTagItem(fd, head->item.tag);
michael@0 856 } else {
michael@0 857 PR_fprintf(fd, "\nTEXT:\n-----\n%s\n-----\n\n", head->item.text);
michael@0 858 }
michael@0 859 head = head->next;
michael@0 860 }
michael@0 861 }
michael@0 862
michael@0 863
michael@0 864 /************************************************************************
michael@0 865 *
michael@0 866 * S a v e I n l i n e S c r i p t
michael@0 867 *
michael@0 868 */
michael@0 869 static int
michael@0 870 SaveInlineScript(char *text, char *id, char *basedir, char *archiveDir)
michael@0 871 {
michael@0 872 char *filename = NULL;
michael@0 873 PRFileDesc * fd = NULL;
michael@0 874 int retval = -1;
michael@0 875 PRInt32 writeLen;
michael@0 876 char *ilDir = NULL;
michael@0 877
michael@0 878 if (!text || !id || !archiveDir) {
michael@0 879 return - 1;
michael@0 880 }
michael@0 881
michael@0 882 if (dumpParse) {
michael@0 883 PR_fprintf(outputFD, "SaveInlineScript: text=%s, id=%s, \n"
michael@0 884 "basedir=%s, archiveDir=%s\n",
michael@0 885 text, id, basedir, archiveDir);
michael@0 886 }
michael@0 887
michael@0 888 /* Make sure the archive directory is around */
michael@0 889 if (ensureExists(basedir, archiveDir) != PR_SUCCESS) {
michael@0 890 PR_fprintf(errorFD,
michael@0 891 "ERROR: Unable to create archive directory %s.\n", archiveDir);
michael@0 892 errorCount++;
michael@0 893 return - 1;
michael@0 894 }
michael@0 895
michael@0 896 /* Make sure the inline script directory is around */
michael@0 897 ilDir = PR_smprintf("%s/inlineScripts", archiveDir);
michael@0 898 scriptdir = "inlineScripts";
michael@0 899 if (ensureExists(basedir, ilDir) != PR_SUCCESS) {
michael@0 900 PR_fprintf(errorFD,
michael@0 901 "ERROR: Unable to create directory %s.\n", ilDir);
michael@0 902 errorCount++;
michael@0 903 return - 1;
michael@0 904 }
michael@0 905
michael@0 906 filename = PR_smprintf("%s/%s/%s", basedir, ilDir, id);
michael@0 907
michael@0 908 /* If the file already exists, give a warning, then blow it away */
michael@0 909 if (PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) {
michael@0 910 PR_fprintf(errorFD,
michael@0 911 "warning: file \"%s\" already exists--will overwrite.\n",
michael@0 912 filename);
michael@0 913 warningCount++;
michael@0 914 if (rm_dash_r(filename)) {
michael@0 915 PR_fprintf(errorFD, "ERROR: Unable to delete %s.\n", filename);
michael@0 916 errorCount++;
michael@0 917 goto finish;
michael@0 918 }
michael@0 919 }
michael@0 920
michael@0 921 /* Write text into file with name id */
michael@0 922 fd = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
michael@0 923 if (!fd) {
michael@0 924 PR_fprintf(errorFD, "ERROR: Unable to create file \"%s\".\n",
michael@0 925 filename);
michael@0 926 errorCount++;
michael@0 927 goto finish;
michael@0 928 }
michael@0 929 writeLen = strlen(text);
michael@0 930 if ( PR_Write(fd, text, writeLen) != writeLen) {
michael@0 931 PR_fprintf(errorFD, "ERROR: Unable to write to file \"%s\".\n",
michael@0 932 filename);
michael@0 933 errorCount++;
michael@0 934 goto finish;
michael@0 935 }
michael@0 936
michael@0 937 retval = 0;
michael@0 938 finish:
michael@0 939 if (filename) {
michael@0 940 PR_smprintf_free(filename);
michael@0 941 }
michael@0 942 if (ilDir) {
michael@0 943 PR_smprintf_free(ilDir);
michael@0 944 }
michael@0 945 if (fd) {
michael@0 946 PR_Close(fd);
michael@0 947 }
michael@0 948 return retval;
michael@0 949 }
michael@0 950
michael@0 951
michael@0 952 /************************************************************************
michael@0 953 *
michael@0 954 * S a v e U n n a m a b l e S c r i p t
michael@0 955 *
michael@0 956 */
michael@0 957 static int
michael@0 958 SaveUnnamableScript(char *text, char *basedir, char *archiveDir,
michael@0 959 char *HTMLfilename)
michael@0 960 {
michael@0 961 char *id = NULL;
michael@0 962 char *ext = NULL;
michael@0 963 char *start = NULL;
michael@0 964 int retval = -1;
michael@0 965
michael@0 966 if (!text || !archiveDir || !HTMLfilename) {
michael@0 967 return - 1;
michael@0 968 }
michael@0 969
michael@0 970 if (dumpParse) {
michael@0 971 PR_fprintf(outputFD, "SaveUnnamableScript: text=%s, basedir=%s,\n"
michael@0 972 "archiveDir=%s, filename=%s\n", text, basedir, archiveDir,
michael@0 973 HTMLfilename);
michael@0 974 }
michael@0 975
michael@0 976 /* Construct the filename */
michael@0 977 ext = PL_strrchr(HTMLfilename, '.');
michael@0 978 if (ext) {
michael@0 979 *ext = '\0';
michael@0 980 }
michael@0 981 for (start = HTMLfilename; strpbrk(start, "/\\");
michael@0 982 start = strpbrk(start, "/\\") + 1)
michael@0 983 /* do nothing */;
michael@0 984 if (*start == '\0')
michael@0 985 start = HTMLfilename;
michael@0 986 id = PR_smprintf("_%s%d", start, idOrdinal++);
michael@0 987 if (ext) {
michael@0 988 *ext = '.';
michael@0 989 }
michael@0 990
michael@0 991 /* Now call SaveInlineScript to do the work */
michael@0 992 retval = SaveInlineScript(text, id, basedir, archiveDir);
michael@0 993
michael@0 994 PR_Free(id);
michael@0 995
michael@0 996 return retval;
michael@0 997 }
michael@0 998
michael@0 999
michael@0 1000 /************************************************************************
michael@0 1001 *
michael@0 1002 * S a v e S o u r c e
michael@0 1003 *
michael@0 1004 */
michael@0 1005 static int
michael@0 1006 SaveSource(char *src, char *codebase, char *basedir, char *archiveDir)
michael@0 1007 {
michael@0 1008 char *from = NULL, *to = NULL;
michael@0 1009 int retval = -1;
michael@0 1010 char *arcDir = NULL;
michael@0 1011
michael@0 1012 if (!src || !archiveDir) {
michael@0 1013 return - 1;
michael@0 1014 }
michael@0 1015
michael@0 1016 if (dumpParse) {
michael@0 1017 PR_fprintf(outputFD, "SaveSource: src=%s, codebase=%s, basedir=%s,\n"
michael@0 1018 "archiveDir=%s\n", src, codebase, basedir, archiveDir);
michael@0 1019 }
michael@0 1020
michael@0 1021 if (codebase) {
michael@0 1022 arcDir = PR_smprintf("%s/%s/%s/", basedir, codebase, archiveDir);
michael@0 1023 } else {
michael@0 1024 arcDir = PR_smprintf("%s/%s/", basedir, archiveDir);
michael@0 1025 }
michael@0 1026
michael@0 1027 if (codebase) {
michael@0 1028 from = PR_smprintf("%s/%s/%s", basedir, codebase, src);
michael@0 1029 to = PR_smprintf("%s%s", arcDir, src);
michael@0 1030 } else {
michael@0 1031 from = PR_smprintf("%s/%s", basedir, src);
michael@0 1032 to = PR_smprintf("%s%s", arcDir, src);
michael@0 1033 }
michael@0 1034
michael@0 1035 if (make_dirs(to, 0777)) {
michael@0 1036 PR_fprintf(errorFD,
michael@0 1037 "ERROR: Unable to create archive directory %s.\n", archiveDir);
michael@0 1038 errorCount++;
michael@0 1039 goto finish;
michael@0 1040 }
michael@0 1041
michael@0 1042 retval = copyinto(from, to);
michael@0 1043 finish:
michael@0 1044 if (from)
michael@0 1045 PR_Free(from);
michael@0 1046 if (to)
michael@0 1047 PR_Free(to);
michael@0 1048 if (arcDir)
michael@0 1049 PR_Free(arcDir);
michael@0 1050 return retval;
michael@0 1051 }
michael@0 1052
michael@0 1053
michael@0 1054 /************************************************************************
michael@0 1055 *
michael@0 1056 * T a g T y p e T o S t r i n g
michael@0 1057 *
michael@0 1058 */
michael@0 1059 char *
michael@0 1060 TagTypeToString(TAG_TYPE type)
michael@0 1061 {
michael@0 1062 switch (type) {
michael@0 1063 case APPLET_TAG:
michael@0 1064 return "APPLET";
michael@0 1065 case SCRIPT_TAG:
michael@0 1066 return "SCRIPT";
michael@0 1067 case LINK_TAG:
michael@0 1068 return "LINK";
michael@0 1069 case STYLE_TAG:
michael@0 1070 return "STYLE";
michael@0 1071 default:
michael@0 1072 break;
michael@0 1073 }
michael@0 1074 return "unknown";
michael@0 1075 }
michael@0 1076
michael@0 1077
michael@0 1078 /************************************************************************
michael@0 1079 *
michael@0 1080 * e x t r a c t _ j s
michael@0 1081 *
michael@0 1082 */
michael@0 1083 static int
michael@0 1084 extract_js(char *filename)
michael@0 1085 {
michael@0 1086 PRFileDesc * fd = NULL;
michael@0 1087 FileBuffer * fb = NULL;
michael@0 1088 HTMLItem * head = NULL;
michael@0 1089 HTMLItem * tail = NULL;
michael@0 1090 HTMLItem * curitem = NULL;
michael@0 1091 HTMLItem * styleList = NULL;
michael@0 1092 HTMLItem * styleListTail = NULL;
michael@0 1093 HTMLItem * entityList = NULL;
michael@0 1094 HTMLItem * entityListTail = NULL;
michael@0 1095 TagItem * tagp = NULL;
michael@0 1096 char *text = NULL;
michael@0 1097 char *tagerr = NULL;
michael@0 1098 char *archiveDir = NULL;
michael@0 1099 char *firstArchiveDir = NULL;
michael@0 1100 char *basedir = NULL;
michael@0 1101 PRInt32 textStart;
michael@0 1102 PRInt32 curOffset;
michael@0 1103 HTML_STATE state;
michael@0 1104 int curchar;
michael@0 1105 int retval = -1;
michael@0 1106 unsigned int linenum, startLine;
michael@0 1107
michael@0 1108 /* Initialize the implicit ID counter for each file */
michael@0 1109 idOrdinal = 0;
michael@0 1110
michael@0 1111 /*
michael@0 1112 * First, parse the HTML into a stream of tags and text.
michael@0 1113 */
michael@0 1114
michael@0 1115 fd = PR_Open(filename, PR_RDONLY, 0);
michael@0 1116 if (!fd) {
michael@0 1117 PR_fprintf(errorFD, "Unable to open %s for reading.\n", filename);
michael@0 1118 errorCount++;
michael@0 1119 return - 1;
michael@0 1120 }
michael@0 1121
michael@0 1122 /* Construct base directory of filename. */
michael@0 1123 {
michael@0 1124 char *cp;
michael@0 1125
michael@0 1126 basedir = PL_strdup(filename);
michael@0 1127
michael@0 1128 /* Remove trailing slashes */
michael@0 1129 while ( (cp = PL_strprbrk(basedir, "/\\")) ==
michael@0 1130 (basedir + strlen(basedir) - 1)) {
michael@0 1131 *cp = '\0';
michael@0 1132 }
michael@0 1133
michael@0 1134 /* Now remove everything from the last slash (which will be followed
michael@0 1135 * by a filename) to the end */
michael@0 1136 cp = PL_strprbrk(basedir, "/\\");
michael@0 1137 if (cp) {
michael@0 1138 *cp = '\0';
michael@0 1139 }
michael@0 1140 }
michael@0 1141
michael@0 1142 state = TEXT_HTML_STATE;
michael@0 1143
michael@0 1144 fb = FB_Create(fd);
michael@0 1145
michael@0 1146 textStart = 0;
michael@0 1147 startLine = 0;
michael@0 1148 while (linenum = FB_GetLineNum(fb), (curchar = FB_GetChar(fb)) !=
michael@0 1149 EOF) {
michael@0 1150 switch (state) {
michael@0 1151 case TEXT_HTML_STATE:
michael@0 1152 if (curchar == '<') {
michael@0 1153 /*
michael@0 1154 * Found a tag
michael@0 1155 */
michael@0 1156 /* Save the text so far to a new text item */
michael@0 1157 curOffset = FB_GetPointer(fb) - 2;
michael@0 1158 if (curOffset >= textStart) {
michael@0 1159 if (FB_GetRange(fb, textStart, curOffset,
michael@0 1160 &text) !=
michael@0 1161 curOffset - textStart + 1) {
michael@0 1162 PR_fprintf(errorFD,
michael@0 1163 "Unable to read from %s.\n",
michael@0 1164 filename);
michael@0 1165 errorCount++;
michael@0 1166 goto loser;
michael@0 1167 }
michael@0 1168 /* little fudge here. If the first character on a line
michael@0 1169 * is '<', meaning a new tag, the preceding text item
michael@0 1170 * actually ends on the previous line. In this case
michael@0 1171 * we will be saying that the text segment ends on the
michael@0 1172 * next line. I don't think this matters for text items. */
michael@0 1173 curitem = CreateTextItem(text, startLine,
michael@0 1174 linenum);
michael@0 1175 text = NULL;
michael@0 1176 if (tail == NULL) {
michael@0 1177 head = tail = curitem;
michael@0 1178 } else {
michael@0 1179 tail->next = curitem;
michael@0 1180 tail = curitem;
michael@0 1181 }
michael@0 1182 }
michael@0 1183
michael@0 1184 /* Process the tag */
michael@0 1185 tagp = ProcessTag(fb, &tagerr);
michael@0 1186 if (!tagp) {
michael@0 1187 if (tagerr) {
michael@0 1188 PR_fprintf(errorFD, "Error in file %s: %s\n",
michael@0 1189 filename, tagerr);
michael@0 1190 errorCount++;
michael@0 1191 } else {
michael@0 1192 PR_fprintf(errorFD,
michael@0 1193 "Error in file %s, in tag starting at line %d\n",
michael@0 1194 filename, linenum);
michael@0 1195 errorCount++;
michael@0 1196 }
michael@0 1197 goto loser;
michael@0 1198 }
michael@0 1199 /* Add the tag to the list */
michael@0 1200 curitem = CreateTagItem(tagp, linenum, FB_GetLineNum(fb));
michael@0 1201 if (tail == NULL) {
michael@0 1202 head = tail = curitem;
michael@0 1203 } else {
michael@0 1204 tail->next = curitem;
michael@0 1205 tail = curitem;
michael@0 1206 }
michael@0 1207
michael@0 1208 /* What's the next state */
michael@0 1209 if (tagp->type == SCRIPT_TAG) {
michael@0 1210 state = SCRIPT_HTML_STATE;
michael@0 1211 }
michael@0 1212
michael@0 1213 /* Start recording text from the new offset */
michael@0 1214 textStart = FB_GetPointer(fb);
michael@0 1215 startLine = FB_GetLineNum(fb);
michael@0 1216 } else {
michael@0 1217 /* regular character. Next! */
michael@0 1218 }
michael@0 1219 break;
michael@0 1220 case SCRIPT_HTML_STATE:
michael@0 1221 if (curchar == '<') {
michael@0 1222 char *cp;
michael@0 1223 /*
michael@0 1224 * If this is a </script> tag, then we're at the end of the
michael@0 1225 * script. Otherwise, ignore
michael@0 1226 */
michael@0 1227 curOffset = FB_GetPointer(fb) - 1;
michael@0 1228 cp = NULL;
michael@0 1229 if (FB_GetRange(fb, curOffset, curOffset + 8, &cp) != 9) {
michael@0 1230 if (cp) {
michael@0 1231 PR_Free(cp);
michael@0 1232 cp = NULL;
michael@0 1233 }
michael@0 1234 } else {
michael@0 1235 /* compare the strings */
michael@0 1236 if ( !PORT_Strncasecmp(cp, "</script>", 9) ) {
michael@0 1237 /* This is the end of the script. Record the text. */
michael@0 1238 curOffset--;
michael@0 1239 if (curOffset >= textStart) {
michael@0 1240 if (FB_GetRange(fb, textStart, curOffset, &text) !=
michael@0 1241 curOffset - textStart + 1) {
michael@0 1242 PR_fprintf(errorFD, "Unable to read from %s.\n",
michael@0 1243 filename);
michael@0 1244 errorCount++;
michael@0 1245 goto loser;
michael@0 1246 }
michael@0 1247 curitem = CreateTextItem(text, startLine, linenum);
michael@0 1248 text = NULL;
michael@0 1249 if (tail == NULL) {
michael@0 1250 head = tail = curitem;
michael@0 1251 } else {
michael@0 1252 tail->next = curitem;
michael@0 1253 tail = curitem;
michael@0 1254 }
michael@0 1255 }
michael@0 1256
michael@0 1257 /* Now parse the /script tag and put it on the list */
michael@0 1258 tagp = ProcessTag(fb, &tagerr);
michael@0 1259 if (!tagp) {
michael@0 1260 if (tagerr) {
michael@0 1261 PR_fprintf(errorFD, "Error in file %s: %s\n",
michael@0 1262 filename, tagerr);
michael@0 1263 } else {
michael@0 1264 PR_fprintf(errorFD,
michael@0 1265 "Error in file %s, in tag starting at"
michael@0 1266 " line %d\n", filename, linenum);
michael@0 1267 }
michael@0 1268 errorCount++;
michael@0 1269 goto loser;
michael@0 1270 }
michael@0 1271 curitem = CreateTagItem(tagp, linenum,
michael@0 1272 FB_GetLineNum(fb));
michael@0 1273 if (tail == NULL) {
michael@0 1274 head = tail = curitem;
michael@0 1275 } else {
michael@0 1276 tail->next = curitem;
michael@0 1277 tail = curitem;
michael@0 1278 }
michael@0 1279
michael@0 1280 /* go back to text state */
michael@0 1281 state = TEXT_HTML_STATE;
michael@0 1282
michael@0 1283 textStart = FB_GetPointer(fb);
michael@0 1284 startLine = FB_GetLineNum(fb);
michael@0 1285 }
michael@0 1286 }
michael@0 1287 }
michael@0 1288 break;
michael@0 1289 }
michael@0 1290 }
michael@0 1291
michael@0 1292 /* End of the file. Wrap up any remaining text */
michael@0 1293 if (state == SCRIPT_HTML_STATE) {
michael@0 1294 if (tail && tail->type == TAG_ITEM) {
michael@0 1295 PR_fprintf(errorFD, "ERROR: <SCRIPT> tag at %s:%d is not followed "
michael@0 1296 "by a </SCRIPT> tag.\n", filename, tail->startLine);
michael@0 1297 } else {
michael@0 1298 PR_fprintf(errorFD, "ERROR: <SCRIPT> tag in file %s is not followed"
michael@0 1299 " by a </SCRIPT tag.\n", filename);
michael@0 1300 }
michael@0 1301 errorCount++;
michael@0 1302 goto loser;
michael@0 1303 }
michael@0 1304 curOffset = FB_GetPointer(fb) - 1;
michael@0 1305 if (curOffset >= textStart) {
michael@0 1306 text = NULL;
michael@0 1307 if ( FB_GetRange(fb, textStart, curOffset, &text) !=
michael@0 1308 curOffset - textStart + 1) {
michael@0 1309 PR_fprintf(errorFD, "Unable to read from %s.\n", filename);
michael@0 1310 errorCount++;
michael@0 1311 goto loser;
michael@0 1312 }
michael@0 1313 curitem = CreateTextItem(text, startLine, linenum);
michael@0 1314 text = NULL;
michael@0 1315 if (tail == NULL) {
michael@0 1316 head = tail = curitem;
michael@0 1317 } else {
michael@0 1318 tail->next = curitem;
michael@0 1319 tail = curitem;
michael@0 1320 }
michael@0 1321 }
michael@0 1322
michael@0 1323 if (dumpParse) {
michael@0 1324 PrintHTMLStream(outputFD, head);
michael@0 1325 }
michael@0 1326
michael@0 1327 /*
michael@0 1328 * Now we have a stream of tags and text. Go through and deal with each.
michael@0 1329 */
michael@0 1330 for (curitem = head; curitem; curitem = curitem->next) {
michael@0 1331 TagItem * tagp = NULL;
michael@0 1332 AVPair * pairp = NULL;
michael@0 1333 char *src = NULL, *id = NULL, *codebase = NULL;
michael@0 1334 PRBool hasEventHandler = PR_FALSE;
michael@0 1335 int i;
michael@0 1336
michael@0 1337 /* Reset archive directory for each tag */
michael@0 1338 if (archiveDir) {
michael@0 1339 PR_Free(archiveDir);
michael@0 1340 archiveDir = NULL;
michael@0 1341 }
michael@0 1342
michael@0 1343 /* We only analyze tags */
michael@0 1344 if (curitem->type != TAG_ITEM) {
michael@0 1345 continue;
michael@0 1346 }
michael@0 1347
michael@0 1348 tagp = curitem->item.tag;
michael@0 1349
michael@0 1350 /* go through the attributes to get information */
michael@0 1351 for (pairp = tagp->attList; pairp; pairp = pairp->next) {
michael@0 1352
michael@0 1353 /* ARCHIVE= */
michael@0 1354 if ( !PL_strcasecmp(pairp->attribute, "archive")) {
michael@0 1355 if (archiveDir) {
michael@0 1356 /* Duplicate attribute. Print warning */
michael@0 1357 PR_fprintf(errorFD,
michael@0 1358 "warning: \"%s\" attribute overwrites previous attribute"
michael@0 1359 " in tag starting at %s:%d.\n",
michael@0 1360 pairp->attribute, filename, curitem->startLine);
michael@0 1361 warningCount++;
michael@0 1362 PR_Free(archiveDir);
michael@0 1363 }
michael@0 1364 archiveDir = PL_strdup(pairp->value);
michael@0 1365
michael@0 1366 /* Substiture ".arc" for ".jar" */
michael@0 1367 if ( (PL_strlen(archiveDir) < 4) ||
michael@0 1368 PL_strcasecmp((archiveDir + strlen(archiveDir) -4),
michael@0 1369 ".jar")) {
michael@0 1370 PR_fprintf(errorFD,
michael@0 1371 "warning: ARCHIVE attribute should end in \".jar\" in tag"
michael@0 1372 " starting on %s:%d.\n", filename, curitem->startLine);
michael@0 1373 warningCount++;
michael@0 1374 PR_Free(archiveDir);
michael@0 1375 archiveDir = PR_smprintf("%s.arc", archiveDir);
michael@0 1376 } else {
michael@0 1377 PL_strcpy(archiveDir + strlen(archiveDir) -4, ".arc");
michael@0 1378 }
michael@0 1379
michael@0 1380 /* Record the first archive. This will be used later if
michael@0 1381 * the archive is not specified */
michael@0 1382 if (firstArchiveDir == NULL) {
michael@0 1383 firstArchiveDir = PL_strdup(archiveDir);
michael@0 1384 }
michael@0 1385 }
michael@0 1386 /* CODEBASE= */
michael@0 1387 else if ( !PL_strcasecmp(pairp->attribute, "codebase")) {
michael@0 1388 if (codebase) {
michael@0 1389 /* Duplicate attribute. Print warning */
michael@0 1390 PR_fprintf(errorFD,
michael@0 1391 "warning: \"%s\" attribute overwrites previous attribute"
michael@0 1392 " in tag staring at %s:%d.\n",
michael@0 1393 pairp->attribute, filename, curitem->startLine);
michael@0 1394 warningCount++;
michael@0 1395 }
michael@0 1396 codebase = pairp->value;
michael@0 1397 }
michael@0 1398 /* SRC= and HREF= */
michael@0 1399 else if ( !PORT_Strcasecmp(pairp->attribute, "src") ||
michael@0 1400 !PORT_Strcasecmp(pairp->attribute, "href") ) {
michael@0 1401 if (src) {
michael@0 1402 /* Duplicate attribute. Print warning */
michael@0 1403 PR_fprintf(errorFD,
michael@0 1404 "warning: \"%s\" attribute overwrites previous attribute"
michael@0 1405 " in tag staring at %s:%d.\n",
michael@0 1406 pairp->attribute, filename, curitem->startLine);
michael@0 1407 warningCount++;
michael@0 1408 }
michael@0 1409 src = pairp->value;
michael@0 1410 }
michael@0 1411 /* CODE= */
michael@0 1412 else if (!PORT_Strcasecmp(pairp->attribute, "code") ) {
michael@0 1413 /*!!!XXX Change PORT to PL all over this code !!! */
michael@0 1414 if (src) {
michael@0 1415 /* Duplicate attribute. Print warning */
michael@0 1416 PR_fprintf(errorFD,
michael@0 1417 "warning: \"%s\" attribute overwrites previous attribute"
michael@0 1418 " ,in tag staring at %s:%d.\n",
michael@0 1419 pairp->attribute, filename, curitem->startLine);
michael@0 1420 warningCount++;
michael@0 1421 }
michael@0 1422 src = pairp->value;
michael@0 1423
michael@0 1424 /* Append a .class if one is not already present */
michael@0 1425 if ( (PL_strlen(src) < 6) ||
michael@0 1426 PL_strcasecmp( (src + PL_strlen(src) - 6), ".class") ) {
michael@0 1427 src = PR_smprintf("%s.class", src);
michael@0 1428 /* Put this string back into the data structure so it
michael@0 1429 * will be deallocated properly */
michael@0 1430 PR_Free(pairp->value);
michael@0 1431 pairp->value = src;
michael@0 1432 }
michael@0 1433 }
michael@0 1434 /* ID= */
michael@0 1435 else if (!PL_strcasecmp(pairp->attribute, "id") ) {
michael@0 1436 if (id) {
michael@0 1437 /* Duplicate attribute. Print warning */
michael@0 1438 PR_fprintf(errorFD,
michael@0 1439 "warning: \"%s\" attribute overwrites previous attribute"
michael@0 1440 " in tag staring at %s:%d.\n",
michael@0 1441 pairp->attribute, filename, curitem->startLine);
michael@0 1442 warningCount++;
michael@0 1443 }
michael@0 1444 id = pairp->value;
michael@0 1445 }
michael@0 1446
michael@0 1447 /* STYLE= */
michael@0 1448 /* style= attributes, along with JS entities, are stored into
michael@0 1449 * files with dynamically generated names. The filenames are
michael@0 1450 * based on the order in which the text is found in the file.
michael@0 1451 * All JS entities on all lines up to and including the line
michael@0 1452 * containing the end of the tag that has this style= attribute
michael@0 1453 * will be processed before this style=attribute. So we need
michael@0 1454 * to record the line that this _tag_ (not the attribute) ends on.
michael@0 1455 */
michael@0 1456 else if (!PL_strcasecmp(pairp->attribute, "style") && pairp->value)
michael@0 1457 {
michael@0 1458 HTMLItem * styleItem;
michael@0 1459 /* Put this item on the style list */
michael@0 1460 styleItem = CreateTextItem(PL_strdup(pairp->value),
michael@0 1461 curitem->startLine, curitem->endLine);
michael@0 1462 if (styleListTail == NULL) {
michael@0 1463 styleList = styleListTail = styleItem;
michael@0 1464 } else {
michael@0 1465 styleListTail->next = styleItem;
michael@0 1466 styleListTail = styleItem;
michael@0 1467 }
michael@0 1468 }
michael@0 1469 /* Event handlers */
michael@0 1470 else {
michael@0 1471 for (i = 0; i < num_handlers; i++) {
michael@0 1472 if (!PL_strcasecmp(event_handlers[i], pairp->attribute)) {
michael@0 1473 hasEventHandler = PR_TRUE;
michael@0 1474 break;
michael@0 1475 }
michael@0 1476 }
michael@0 1477 }
michael@0 1478
michael@0 1479
michael@0 1480 /* JS Entity */
michael@0 1481 {
michael@0 1482 char *entityStart, *entityEnd;
michael@0 1483 HTMLItem * entityItem;
michael@0 1484
michael@0 1485 /* go through each JavaScript entity ( &{...}; ) and store it
michael@0 1486 * in the entityList. The important thing is to record what
michael@0 1487 * line number it's on, so we can get it in the right order
michael@0 1488 * in relation to style= attributes.
michael@0 1489 * Apparently, these can't flow across lines, so the start and
michael@0 1490 * end line will be the same. That helps matters.
michael@0 1491 */
michael@0 1492 entityEnd = pairp->value;
michael@0 1493 while ( entityEnd &&
michael@0 1494 (entityStart = PL_strstr(entityEnd, "&{")) /*}*/ != NULL) {
michael@0 1495 entityStart += 2; /* point at beginning of actual entity */
michael@0 1496 entityEnd = PL_strchr(entityStart, '}');
michael@0 1497 if (entityEnd) {
michael@0 1498 /* Put this item on the entity list */
michael@0 1499 *entityEnd = '\0';
michael@0 1500 entityItem = CreateTextItem(PL_strdup(entityStart),
michael@0 1501 pairp->valueLine, pairp->valueLine);
michael@0 1502 *entityEnd = /* { */ '}';
michael@0 1503 if (entityListTail) {
michael@0 1504 entityListTail->next = entityItem;
michael@0 1505 entityListTail = entityItem;
michael@0 1506 } else {
michael@0 1507 entityList = entityListTail = entityItem;
michael@0 1508 }
michael@0 1509 }
michael@0 1510 }
michael@0 1511 }
michael@0 1512 }
michael@0 1513
michael@0 1514 /* If no archive was supplied, we use the first one of the file */
michael@0 1515 if (!archiveDir && firstArchiveDir) {
michael@0 1516 archiveDir = PL_strdup(firstArchiveDir);
michael@0 1517 }
michael@0 1518
michael@0 1519 /* If we have an event handler, we need to archive this tag */
michael@0 1520 if (hasEventHandler) {
michael@0 1521 if (!id) {
michael@0 1522 PR_fprintf(errorFD,
michael@0 1523 "warning: tag starting at %s:%d has event handler but"
michael@0 1524 " no ID attribute. The tag will not be signed.\n",
michael@0 1525 filename, curitem->startLine);
michael@0 1526 warningCount++;
michael@0 1527 } else if (!archiveDir) {
michael@0 1528 PR_fprintf(errorFD,
michael@0 1529 "warning: tag starting at %s:%d has event handler but"
michael@0 1530 " no ARCHIVE attribute. The tag will not be signed.\n",
michael@0 1531 filename, curitem->startLine);
michael@0 1532 warningCount++;
michael@0 1533 } else {
michael@0 1534 if (SaveInlineScript(tagp->text, id, basedir, archiveDir)) {
michael@0 1535 goto loser;
michael@0 1536 }
michael@0 1537 }
michael@0 1538 }
michael@0 1539
michael@0 1540 switch (tagp->type) {
michael@0 1541 case APPLET_TAG:
michael@0 1542 if (!src) {
michael@0 1543 PR_fprintf(errorFD,
michael@0 1544 "error: APPLET tag starting on %s:%d has no CODE "
michael@0 1545 "attribute.\n", filename, curitem->startLine);
michael@0 1546 errorCount++;
michael@0 1547 goto loser;
michael@0 1548 } else if (!archiveDir) {
michael@0 1549 PR_fprintf(errorFD,
michael@0 1550 "error: APPLET tag starting on %s:%d has no ARCHIVE "
michael@0 1551 "attribute.\n", filename, curitem->startLine);
michael@0 1552 errorCount++;
michael@0 1553 goto loser;
michael@0 1554 } else {
michael@0 1555 if (SaveSource(src, codebase, basedir, archiveDir)) {
michael@0 1556 goto loser;
michael@0 1557 }
michael@0 1558 }
michael@0 1559 break;
michael@0 1560 case SCRIPT_TAG:
michael@0 1561 case LINK_TAG:
michael@0 1562 case STYLE_TAG:
michael@0 1563 if (!archiveDir) {
michael@0 1564 PR_fprintf(errorFD,
michael@0 1565 "error: %s tag starting on %s:%d has no ARCHIVE "
michael@0 1566 "attribute.\n", TagTypeToString(tagp->type),
michael@0 1567 filename, curitem->startLine);
michael@0 1568 errorCount++;
michael@0 1569 goto loser;
michael@0 1570 } else if (src) {
michael@0 1571 if (SaveSource(src, codebase, basedir, archiveDir)) {
michael@0 1572 goto loser;
michael@0 1573 }
michael@0 1574 } else if (id) {
michael@0 1575 /* Save the next text item */
michael@0 1576 if (!curitem->next || (curitem->next->type !=
michael@0 1577 TEXT_ITEM)) {
michael@0 1578 PR_fprintf(errorFD,
michael@0 1579 "warning: %s tag starting on %s:%d is not followed"
michael@0 1580 " by script text.\n", TagTypeToString(tagp->type),
michael@0 1581 filename, curitem->startLine);
michael@0 1582 warningCount++;
michael@0 1583 /* just create empty file */
michael@0 1584 if (SaveInlineScript("", id, basedir, archiveDir)) {
michael@0 1585 goto loser;
michael@0 1586 }
michael@0 1587 } else {
michael@0 1588 curitem = curitem->next;
michael@0 1589 if (SaveInlineScript(curitem->item.text,
michael@0 1590 id, basedir,
michael@0 1591 archiveDir)) {
michael@0 1592 goto loser;
michael@0 1593 }
michael@0 1594 }
michael@0 1595 } else {
michael@0 1596 /* No src or id tag--warning */
michael@0 1597 PR_fprintf(errorFD,
michael@0 1598 "warning: %s tag starting on %s:%d has no SRC or"
michael@0 1599 " ID attributes. Will not sign.\n",
michael@0 1600 TagTypeToString(tagp->type), filename, curitem->startLine);
michael@0 1601 warningCount++;
michael@0 1602 }
michael@0 1603 break;
michael@0 1604 default:
michael@0 1605 /* do nothing for other tags */
michael@0 1606 break;
michael@0 1607 }
michael@0 1608
michael@0 1609 }
michael@0 1610
michael@0 1611 /* Now deal with all the unnamable scripts */
michael@0 1612 if (firstArchiveDir) {
michael@0 1613 HTMLItem * style, *entity;
michael@0 1614
michael@0 1615 /* Go through the lists of JS entities and style attributes. Do them
michael@0 1616 * in chronological order within a list. Pick the list with the lower
michael@0 1617 * endLine. In case of a tie, entities come first.
michael@0 1618 */
michael@0 1619 style = styleList;
michael@0 1620 entity = entityList;
michael@0 1621 while (style || entity) {
michael@0 1622 if (!entity || (style && (style->endLine < entity->endLine))) {
michael@0 1623 /* Process style */
michael@0 1624 SaveUnnamableScript(style->item.text, basedir, firstArchiveDir,
michael@0 1625 filename);
michael@0 1626 style = style->next;
michael@0 1627 } else {
michael@0 1628 /* Process entity */
michael@0 1629 SaveUnnamableScript(entity->item.text, basedir, firstArchiveDir,
michael@0 1630 filename);
michael@0 1631 entity = entity->next;
michael@0 1632 }
michael@0 1633 }
michael@0 1634 }
michael@0 1635
michael@0 1636
michael@0 1637 retval = 0;
michael@0 1638 loser:
michael@0 1639 /* Blow away the stream */
michael@0 1640 while (head) {
michael@0 1641 curitem = head;
michael@0 1642 head = head->next;
michael@0 1643 DestroyHTMLItem(curitem);
michael@0 1644 }
michael@0 1645 while (styleList) {
michael@0 1646 curitem = styleList;
michael@0 1647 styleList = styleList->next;
michael@0 1648 DestroyHTMLItem(curitem);
michael@0 1649 }
michael@0 1650 while (entityList) {
michael@0 1651 curitem = entityList;
michael@0 1652 entityList = entityList->next;
michael@0 1653 DestroyHTMLItem(curitem);
michael@0 1654 }
michael@0 1655 if (text) {
michael@0 1656 PR_Free(text);
michael@0 1657 text = NULL;
michael@0 1658 }
michael@0 1659 if (fb) {
michael@0 1660 FB_Destroy(fb);
michael@0 1661 fb = NULL;
michael@0 1662 }
michael@0 1663 if (fd) {
michael@0 1664 PR_Close(fd);
michael@0 1665 }
michael@0 1666 if (tagerr) {
michael@0 1667 PR_smprintf_free(tagerr);
michael@0 1668 tagerr = NULL;
michael@0 1669 }
michael@0 1670 if (archiveDir) {
michael@0 1671 PR_Free(archiveDir);
michael@0 1672 archiveDir = NULL;
michael@0 1673 }
michael@0 1674 if (firstArchiveDir) {
michael@0 1675 PR_Free(firstArchiveDir);
michael@0 1676 firstArchiveDir = NULL;
michael@0 1677 }
michael@0 1678 return retval;
michael@0 1679 }
michael@0 1680
michael@0 1681
michael@0 1682 /**********************************************************************
michael@0 1683 *
michael@0 1684 * e n s u r e E x i s t s
michael@0 1685 *
michael@0 1686 * Check for existence of indicated directory. If it doesn't exist,
michael@0 1687 * it will be created.
michael@0 1688 * Returns PR_SUCCESS if the directory is present, PR_FAILURE otherwise.
michael@0 1689 */
michael@0 1690 static PRStatus
michael@0 1691 ensureExists (char *base, char *path)
michael@0 1692 {
michael@0 1693 char fn [FNSIZE];
michael@0 1694 PRDir * dir;
michael@0 1695 sprintf (fn, "%s/%s", base, path);
michael@0 1696
michael@0 1697 /*PR_fprintf(outputFD, "Trying to open directory %s.\n", fn);*/
michael@0 1698
michael@0 1699 if ( (dir = PR_OpenDir(fn)) ) {
michael@0 1700 PR_CloseDir(dir);
michael@0 1701 return PR_SUCCESS;
michael@0 1702 }
michael@0 1703 return PR_MkDir(fn, 0777);
michael@0 1704 }
michael@0 1705
michael@0 1706
michael@0 1707 /***************************************************************************
michael@0 1708 *
michael@0 1709 * m a k e _ d i r s
michael@0 1710 *
michael@0 1711 * Ensure that the directory portion of the path exists. This may require
michael@0 1712 * making the directory, and its parent, and its parent's parent, etc.
michael@0 1713 */
michael@0 1714 static int
michael@0 1715 make_dirs(char *path, int file_perms)
michael@0 1716 {
michael@0 1717 char *Path;
michael@0 1718 char *start;
michael@0 1719 char *sep;
michael@0 1720 int ret = 0;
michael@0 1721 PRFileInfo info;
michael@0 1722
michael@0 1723 if (!path) {
michael@0 1724 return 0;
michael@0 1725 }
michael@0 1726
michael@0 1727 Path = PL_strdup(path);
michael@0 1728 start = strpbrk(Path, "/\\");
michael@0 1729 if (!start) {
michael@0 1730 return 0;
michael@0 1731 }
michael@0 1732 start++; /* start right after first slash */
michael@0 1733
michael@0 1734 /* Each time through the loop add one more directory. */
michael@0 1735 while ( (sep = strpbrk(start, "/\\")) ) {
michael@0 1736 *sep = '\0';
michael@0 1737
michael@0 1738 if ( PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
michael@0 1739 /* No such dir, we have to create it */
michael@0 1740 if ( PR_MkDir(Path, file_perms) != PR_SUCCESS) {
michael@0 1741 PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
michael@0 1742 Path);
michael@0 1743 errorCount++;
michael@0 1744 ret = -1;
michael@0 1745 goto loser;
michael@0 1746 }
michael@0 1747 } else {
michael@0 1748 /* something exists by this name, make sure it's a directory */
michael@0 1749 if ( info.type != PR_FILE_DIRECTORY ) {
michael@0 1750 PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
michael@0 1751 Path);
michael@0 1752 errorCount++;
michael@0 1753 ret = -1;
michael@0 1754 goto loser;
michael@0 1755 }
michael@0 1756 }
michael@0 1757
michael@0 1758 start = sep + 1; /* start after the next slash */
michael@0 1759 *sep = '/';
michael@0 1760 }
michael@0 1761
michael@0 1762 loser:
michael@0 1763 PR_Free(Path);
michael@0 1764 return ret;
michael@0 1765 }
michael@0 1766
michael@0 1767
michael@0 1768 /*
michael@0 1769 * c o p y i n t o
michael@0 1770 *
michael@0 1771 * Function to copy file "from" to path "to".
michael@0 1772 *
michael@0 1773 */
michael@0 1774 static int
michael@0 1775 copyinto (char *from, char *to)
michael@0 1776 {
michael@0 1777 PRInt32 num;
michael@0 1778 char buf [BUFSIZ];
michael@0 1779 PRFileDesc * infp = NULL, *outfp = NULL;
michael@0 1780 int retval = -1;
michael@0 1781
michael@0 1782 if ((infp = PR_Open(from, PR_RDONLY, 0777)) == NULL) {
michael@0 1783 PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for reading.\n",
michael@0 1784 from);
michael@0 1785 errorCount++;
michael@0 1786 goto finish;
michael@0 1787 }
michael@0 1788
michael@0 1789 /* If to already exists, print a warning before deleting it */
michael@0 1790 if (PR_Access(to, PR_ACCESS_EXISTS) == PR_SUCCESS) {
michael@0 1791 PR_fprintf(errorFD, "warning: %s already exists--will overwrite\n", to);
michael@0 1792 warningCount++;
michael@0 1793 if (rm_dash_r(to)) {
michael@0 1794 PR_fprintf(errorFD,
michael@0 1795 "ERROR: Unable to remove %s.\n", to);
michael@0 1796 errorCount++;
michael@0 1797 goto finish;
michael@0 1798 }
michael@0 1799 }
michael@0 1800
michael@0 1801 if ((outfp = PR_Open(to, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777))
michael@0 1802 == NULL) {
michael@0 1803 char *errBuf = NULL;
michael@0 1804
michael@0 1805 errBuf = PR_Malloc(PR_GetErrorTextLength() + 1);
michael@0 1806 PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for writing.\n", to);
michael@0 1807 if (PR_GetErrorText(errBuf)) {
michael@0 1808 PR_fprintf(errorFD, "Cause: %s\n", errBuf);
michael@0 1809 }
michael@0 1810 if (errBuf) {
michael@0 1811 PR_Free(errBuf);
michael@0 1812 }
michael@0 1813 errorCount++;
michael@0 1814 goto finish;
michael@0 1815 }
michael@0 1816
michael@0 1817 while ( (num = PR_Read(infp, buf, BUFSIZ)) > 0) {
michael@0 1818 if (PR_Write(outfp, buf, num) != num) {
michael@0 1819 PR_fprintf(errorFD, "ERROR: Error writing to %s.\n", to);
michael@0 1820 errorCount++;
michael@0 1821 goto finish;
michael@0 1822 }
michael@0 1823 }
michael@0 1824
michael@0 1825 retval = 0;
michael@0 1826 finish:
michael@0 1827 if (infp)
michael@0 1828 PR_Close(infp);
michael@0 1829 if (outfp)
michael@0 1830 PR_Close(outfp);
michael@0 1831
michael@0 1832 return retval;
michael@0 1833 }
michael@0 1834
michael@0 1835

mercurial