security/nss/cmd/signtool/javascript.c

changeset 0
6474c204b198
     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 +

mercurial