Logo Search packages:      
Sourcecode: xulrunner-1.9 version File versions

javascript.c

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Netscape security libraries.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "signtool.h"
#include <prmem.h>
#include <prio.h>
#include <prenv.h>

static int  javascript_fn(char *relpath, char *basedir, char *reldir,
char *filename, void *arg);
static int  extract_js (char *filename);
static int  copyinto (char *from, char *to);
static PRStatus ensureExists (char *base, char *path);
static int  make_dirs(char *path, PRInt32 file_perms);

static char *jartree = NULL;
static int  idOrdinal;
static PRBool dumpParse = PR_FALSE;

static char *event_handlers[] = {
    "onAbort",
    "onBlur",
    "onChange",
    "onClick",
    "onDblClick",
    "onDragDrop",
    "onError",
    "onFocus",
    "onKeyDown",
    "onKeyPress",
    "onKeyUp",
    "onLoad",
    "onMouseDown",
    "onMouseMove",
    "onMouseOut",
    "onMouseOver",
    "onMouseUp",
    "onMove",
    "onReset",
    "onResize",
    "onSelect",
    "onSubmit",
    "onUnload"
};


static int  num_handlers = 23;

/*
 *  I n l i n e J a v a S c r i p t
 *
 *  Javascript signing. Instead of passing an archive to signtool,
 *  a directory containing html files is given. Archives are created
 *  from the archive= and src= tag attributes inside the html,
 *  as appropriate. Then the archives are signed.
 *
 */
int
InlineJavaScript(char *dir, PRBool recurse)
{
    jartree = dir;
    if (verbosity >= 0) {
      PR_fprintf(outputFD, "\nGenerating inline signatures from HTML files in: %s\n",
           dir);
    }
    if (PR_GetEnv("SIGNTOOL_DUMP_PARSE")) {
      dumpParse = PR_TRUE;
    }

    return foreach(dir, "", javascript_fn, recurse, PR_FALSE /*include dirs*/,
                  (void * )NULL);

}


/************************************************************************
 *
 * j a v a s c r i p t _ f n
 */
static int  javascript_fn
(char *relpath, char *basedir, char *reldir, char *filename, void *arg)
{
    char    fullname [FNSIZE];

    /* only process inline scripts from .htm, .html, and .shtml*/

    if (!(PL_strcaserstr(filename, ".htm") == filename + strlen(filename) -
        4) && 
        !(PL_strcaserstr(filename, ".html") == filename + strlen(filename) -
        5) && 
        !(PL_strcaserstr(filename, ".shtml") == filename + strlen(filename)
        -6)) {
      return 0;
    }

    /* don't process scripts that signtool has already
     extracted (those that are inside .arc directories) */

    if (PL_strcaserstr(filename, ".arc") == filename + strlen(filename) - 4)
      return 0;

    if (verbosity >= 0) {
      PR_fprintf(outputFD, "Processing HTML file: %s\n", relpath);
    }

    /* reset firstArchive at top of each HTML file */

    /* skip directories that contain extracted scripts */

    if (PL_strcaserstr(reldir, ".arc") == reldir + strlen(reldir) - 4)
      return 0;

    sprintf (fullname, "%s/%s", basedir, relpath);
    return extract_js (fullname);
}


/*===========================================================================
 =
 = D A T A   S T R U C T U R E S
 =
*/
typedef enum {
    TEXT_HTML_STATE = 0,
    SCRIPT_HTML_STATE
} 


HTML_STATE ;

typedef enum {
    /* we start in the start state */
    START_STATE,

    /* We are looking for or reading in an attribute */
    GET_ATT_STATE,

    /* We're burning ws before finding an attribute */
    PRE_ATT_WS_STATE,

    /* We're burning ws after an attribute.  Looking for an '='. */
    POST_ATT_WS_STATE,

    /* We're burning ws after an '=', waiting for a value */
    PRE_VAL_WS_STATE,

    /* We're reading in a value */
    GET_VALUE_STATE,

    /* We're reading in a value that's inside quotes */
    GET_QUOTED_VAL_STATE,

    /* We've encountered the closing '>' */
    DONE_STATE,

    /* Error state */
    ERR_STATE
} 


TAG_STATE ;

typedef struct AVPair_Str {
    char    *attribute;
    char    *value;
    unsigned int  valueLine; /* the line that the value ends on */
    struct AVPair_Str *next;
} AVPair;

typedef enum {
    APPLET_TAG,
    SCRIPT_TAG,
    LINK_TAG,
    STYLE_TAG,
    COMMENT_TAG,
    OTHER_TAG
} 


TAG_TYPE ;

typedef struct {
    TAG_TYPE type;
    AVPair * attList;
    AVPair * attListTail;
    char    *text;
} TagItem;

typedef enum {
    TAG_ITEM,
    TEXT_ITEM
} 


ITEM_TYPE ;

typedef struct HTMLItem_Str {
    unsigned int  startLine;
    unsigned int  endLine;
    ITEM_TYPE type;
    union {
      TagItem *tag;
      char  *text;
    } item;
    struct HTMLItem_Str *next;
} HTMLItem;

typedef struct {
    PRFileDesc *fd;
    PRInt32 curIndex;
    PRBool IsEOF;
#define FILE_BUFFER_BUFSIZE 512
    char    buf[FILE_BUFFER_BUFSIZE];
    PRInt32 startOffset;
    PRInt32 maxIndex;
    unsigned int  lineNum;
} FileBuffer;

/*===========================================================================
 =
 = F U N C T I O N S
 =
*/
static HTMLItem*CreateTextItem(char *text, unsigned int startline,
unsigned int endline);
static HTMLItem*CreateTagItem(TagItem*ti, unsigned int startline,
unsigned int endline);
static TagItem*ProcessTag(FileBuffer*fb, char **errStr);
static void DestroyHTMLItem(HTMLItem *item);
static void DestroyTagItem(TagItem*ti);
static TAG_TYPE GetTagType(char *att);
static FileBuffer*FB_Create(PRFileDesc*fd);
static int  FB_GetChar(FileBuffer *fb);
static PRInt32 FB_GetPointer(FileBuffer *fb);
static PRInt32 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end,
char **buf);
static unsigned int     FB_GetLineNum(FileBuffer *fb);
static void FB_Destroy(FileBuffer *fb);
static void PrintTagItem(PRFileDesc *fd, TagItem *ti);
static void PrintHTMLStream(PRFileDesc *fd, HTMLItem *head);

/************************************************************************
 *
 * C r e a t e T e x t I t e m
 */
static HTMLItem*
CreateTextItem(char *text, unsigned int startline, unsigned int endline)
{
    HTMLItem * item;

    item = PR_Malloc(sizeof(HTMLItem));
    if (!item) {
      return NULL;
    }

    item->type = TEXT_ITEM;
    item->item.text = text;
    item->next = NULL;
    item->startLine = startline;
    item->endLine = endline;

    return item;
}


/************************************************************************
 *
 * C r e a t e T a g I t e m
 */
static HTMLItem*
CreateTagItem(TagItem*ti, unsigned int startline, unsigned int endline)
{
    HTMLItem * item;

    item = PR_Malloc(sizeof(HTMLItem));
    if (!item) {
      return NULL;
    }

    item->type = TAG_ITEM;
    item->item.tag = ti;
    item->next = NULL;
    item->startLine = startline;
    item->endLine = endline;

    return item;
}


static PRBool
isAttChar(int c)
{
    return (isalnum(c) || c == '/' || c == '-');
}


/************************************************************************
 *
 * P r o c e s s T a g
 */
static TagItem*
ProcessTag(FileBuffer*fb, char **errStr)
{
    TAG_STATE state;
    PRInt32 startText, startID, curPos;
    PRBool firstAtt;
    int     curchar;
    TagItem * ti = NULL;
    AVPair * curPair = NULL;
    char    quotechar = '\0';
    unsigned int  linenum;
    unsigned int  startline;

    state = START_STATE;

    startID = FB_GetPointer(fb);
    startText = startID;
    firstAtt = PR_TRUE;

    ti = (TagItem * ) PR_Malloc(sizeof(TagItem));
    if (!ti) 
      out_of_memory();
    ti->type = OTHER_TAG;
    ti->attList = NULL;
    ti->attListTail = NULL;
    ti->text = NULL;

    startline = FB_GetLineNum(fb);

    while (state != DONE_STATE && state != ERR_STATE) {
      linenum = FB_GetLineNum(fb);
      curchar = FB_GetChar(fb);
      if (curchar == EOF) {
          *errStr = PR_smprintf(
              "line %d: Unexpected end-of-file while parsing tag starting at line %d.\n",
               linenum, startline);
          state = ERR_STATE;
          continue;
      }

      switch (state) {
      case START_STATE:
          if (curchar == '!') {
            /*
             * SGML tag or comment
             * Here's the general rule for SGML tags.  Everything from
             * <! to > is the tag.  Inside the tag, comments are
             * delimited with --.  So we are looking for the first '>'
             * that is not commented out, that is, not inside a pair
             * of --: <!DOCTYPE --this is a comment >(psyche!)   -->
             */

            PRBool inComment = PR_FALSE;
            short hyphenCount = 0; /* number of consecutive hyphens */

            while (1) {
                linenum = FB_GetLineNum(fb);
                curchar = FB_GetChar(fb);
                if (curchar == EOF) {
                  /* Uh oh, EOF inside comment */
                  *errStr = PR_smprintf(
    "line %d: Unexpected end-of-file inside comment starting at line %d.\n",
                                    linenum, startline);
                  state = ERR_STATE;
                  break;
                }
                if (curchar == '-') {
                  if (hyphenCount == 1) {
                      /* This is a comment delimiter */
                      inComment = !inComment;
                      hyphenCount = 0;
                  } else {
                      /* beginning of a comment delimiter? */
                      hyphenCount = 1;
                  }
                } else if (curchar == '>') {
                  if (!inComment) {
                      /* This is the end of the tag */
                      state = DONE_STATE;
                      break;
                  } else {
                      /* The > is inside a comment, so it's not
                                           * really the end of the tag */
                      hyphenCount = 0;
                  }
                } else {
                  hyphenCount = 0;
                }
            }
            ti->type = COMMENT_TAG;
            break;
          }
          /* fall through */
      case GET_ATT_STATE:
          if (isspace(curchar) || curchar == '=' || curchar
              == '>') {
            /* end of the current attribute */
            curPos = FB_GetPointer(fb) - 2;
            if (curPos >= startID) {
                /* We have an attribute */
                curPair = (AVPair * )PR_Malloc(sizeof(AVPair));
                if (!curPair) 
                  out_of_memory();
                curPair->value = NULL;
                curPair->next = NULL;
                FB_GetRange(fb, startID, curPos,
                    &curPair->attribute);

                /* Stick this attribute on the list */
                if (ti->attListTail) {
                  ti->attListTail->next = curPair;
                  ti->attListTail = curPair;
                } else {
                  ti->attList = ti->attListTail =
                      curPair;
                }

                /* If this is the first attribute, find the type of tag
                 * based on it. Also, start saving the text of the tag. */
                if (firstAtt) {
                  ti->type = GetTagType(curPair->attribute);
                  startText = FB_GetPointer(fb)
                      -1;
                  firstAtt = PR_FALSE;
                }
            } else {
                if (curchar == '=') {
                  /* If we don't have any attribute but we do have an
                   * equal sign, that's an error */
                  *errStr = PR_smprintf("line %d: Malformed tag starting at line %d.\n",
                       linenum, startline);
                  state = ERR_STATE;
                  break;
                }
            }

            /* Compute next state */
            if (curchar == '=') {
                startID = FB_GetPointer(fb);
                state = PRE_VAL_WS_STATE;
            } else if (curchar == '>') {
                state = DONE_STATE;
            } else if (curPair) {
                state = POST_ATT_WS_STATE;
            } else {
                state = PRE_ATT_WS_STATE;
            }
          } else if (isAttChar(curchar)) {
            /* Just another char in the attribute. Do nothing */
            state = GET_ATT_STATE;
          } else {
            /* bogus char */
            *errStr = PR_smprintf("line %d: Bogus chararacter '%c' in tag.\n",
                              linenum, curchar);
            state = ERR_STATE;
            break;
          }
          break;
      case PRE_ATT_WS_STATE:
          if (curchar == '>') {
            state = DONE_STATE;
          } else if (isspace(curchar)) {
            /* more whitespace, do nothing */
          } else if (isAttChar(curchar)) {
            /* starting another attribute */
            startID = FB_GetPointer(fb) - 1;
            state = GET_ATT_STATE;
          } else {
            /* bogus char */
            *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
                              linenum, curchar);
            state = ERR_STATE;
            break;
          }
          break;
      case POST_ATT_WS_STATE:
          if (curchar == '>') {
            state = DONE_STATE;
          } else if (isspace(curchar)) {
            /* more whitespace, do nothing */
          } else if (isAttChar(curchar)) {
            /* starting another attribute */
            startID = FB_GetPointer(fb) - 1;
            state = GET_ATT_STATE;
          } else if (curchar == '=') {
            /* there was whitespace between the attribute and its equal
             * sign, which means there's a value coming up */
            state = PRE_VAL_WS_STATE;
          } else {
            /* bogus char */
            *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
                                          linenum, curchar);
            state = ERR_STATE;
            break;
          }
          break;
      case PRE_VAL_WS_STATE:
          if (curchar == '>') {
            /* premature end-of-tag (sounds like a personal problem). */
            *errStr = PR_smprintf(
                "line %d: End of tag while waiting for value.\n",
                 linenum);
            state = ERR_STATE;
            break;
          } else if (isspace(curchar)) {
            /* more whitespace, do nothing */
            break;
          } else {
            /* this must be some sort of value. Fall through
                         * to GET_VALUE_STATE */
            startID = FB_GetPointer(fb) - 1;
            state = GET_VALUE_STATE;
          }
          /* Fall through if we didn't break on '>' or whitespace */
      case GET_VALUE_STATE:
          if (isspace(curchar) || curchar == '>') {
            /* end of value */
            curPos = FB_GetPointer(fb) - 2;
            if (curPos >= startID) {
                /* Grab the value */
                FB_GetRange(fb, startID, curPos,
                    &curPair->value);
                curPair->valueLine = linenum;
            } else {
                /* empty value, leave as NULL */
            }
            if (isspace(curchar)) {
                state = PRE_ATT_WS_STATE;
            } else {
                state = DONE_STATE;
            }
          } else if (curchar == '\"' || curchar == '\'') {
            /* quoted value.  Start recording the value inside the quote*/
            startID = FB_GetPointer(fb);
            state = GET_QUOTED_VAL_STATE;
            PORT_Assert(quotechar == '\0');
            quotechar = curchar; /* look for matching quote type */
          } else {
            /* just more value */
          }
          break;
      case GET_QUOTED_VAL_STATE:
          PORT_Assert(quotechar != '\0');
          if (curchar == quotechar) {
            /* end of quoted value */
            curPos = FB_GetPointer(fb) - 2;
            if (curPos >= startID) {
                /* Grab the value */
                FB_GetRange(fb, startID, curPos,
                    &curPair->value);
                curPair->valueLine = linenum;
            } else {
                /* empty value, leave it as NULL */
            }
            state = GET_ATT_STATE;
            quotechar = '\0';
            startID = FB_GetPointer(fb);
          } else {
            /* more quoted value, continue */
          }
          break;
      case DONE_STATE:
      case ERR_STATE:
      default:
          ; /* should never get here */
      }
    }

    if (state == DONE_STATE) {
      /* Get the text of the tag */
      curPos = FB_GetPointer(fb) - 1;
      FB_GetRange(fb, startText, curPos, &ti->text);

      /* Return the tag */
      return ti;
    }

    /* Uh oh, an error.  Kill the tag item*/
    DestroyTagItem(ti);
    return NULL;
}


/************************************************************************
 *
 * D e s t r o y H T M L I t e m
 */
static void 
DestroyHTMLItem(HTMLItem *item)
{
    if (item->type == TAG_ITEM) {
      DestroyTagItem(item->item.tag);
    } else {
      if (item->item.text) {
          PR_Free(item->item.text);
      }
    }
}


/************************************************************************
 *
 * D e s t r o y T a g I t e m
 */
static void 
DestroyTagItem(TagItem*ti)
{
    AVPair * temp;

    if (ti->text) {
      PR_Free(ti->text); 
      ti->text = NULL;
    }

    while (ti->attList) {
      temp = ti->attList;
      ti->attList = ti->attList->next;

      if (temp->attribute) {
          PR_Free(temp->attribute); 
          temp->attribute = NULL;
      }
      if (temp->value) {
          PR_Free(temp->value); 
          temp->value = NULL;
      }
      PR_Free(temp);
    }

    PR_Free(ti);
}


/************************************************************************
 *
 * G e t T a g T y p e
 */
static TAG_TYPE
GetTagType(char *att)
{
    if (!PORT_Strcasecmp(att, "APPLET")) {
      return APPLET_TAG;
    }
    if (!PORT_Strcasecmp(att, "SCRIPT")) {
      return SCRIPT_TAG;
    }
    if (!PORT_Strcasecmp(att, "LINK")) {
      return LINK_TAG;
    }
    if (!PORT_Strcasecmp(att, "STYLE")) {
      return STYLE_TAG;
    }
    return OTHER_TAG;
}


/************************************************************************
 *
 * F B _ C r e a t e
 */
static FileBuffer*
FB_Create(PRFileDesc*fd)
{
    FileBuffer * fb;
    PRInt32 amountRead;
    PRInt32 storedOffset;

    fb = (FileBuffer * ) PR_Malloc(sizeof(FileBuffer));
    fb->fd = fd;
    storedOffset = PR_Seek(fd, 0, PR_SEEK_CUR);
    PR_Seek(fd, 0, PR_SEEK_SET);
    fb->startOffset = 0;
    amountRead = PR_Read(fd, fb->buf, FILE_BUFFER_BUFSIZE);
    if (amountRead == -1) 
      goto loser;
    fb->maxIndex = amountRead - 1;
    fb->curIndex = 0;
    fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;
    fb->lineNum = 1;

    PR_Seek(fd, storedOffset, PR_SEEK_SET);
    return fb;
loser:
    PR_Seek(fd, storedOffset, PR_SEEK_SET);
    PR_Free(fb);
    return NULL;
}


/************************************************************************
 *
 * F B _ G e t C h a r
 */
static int  
FB_GetChar(FileBuffer *fb)
{
    PRInt32 storedOffset;
    PRInt32 amountRead;
    int     retval = -1;

    if (fb->IsEOF) {
      return EOF;
    }

    storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);

    retval = (unsigned char) fb->buf[fb->curIndex++];
    if (retval == '\n') 
      fb->lineNum++;

    if (fb->curIndex > fb->maxIndex) {
      /* We're at the end of the buffer. Try to get some new data from the
             * file */
      fb->startOffset += fb->maxIndex + 1;
      PR_Seek(fb->fd, fb->startOffset, PR_SEEK_SET);
      amountRead = PR_Read(fb->fd, fb->buf, FILE_BUFFER_BUFSIZE);
      if (amountRead == -1)  
          goto loser;
      fb->maxIndex = amountRead - 1;
      fb->curIndex = 0;
    }

    fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;

loser:
    PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
    return retval;
}


/************************************************************************
 *
 * F B _ G e t L i n e N u m
 *
 */
static unsigned int     
FB_GetLineNum(FileBuffer *fb)
{
    return fb->lineNum;
}


/************************************************************************
 *
 * F B _ G e t P o i n t e r
 *
 */
static PRInt32
FB_GetPointer(FileBuffer *fb)
{
    return fb->startOffset + fb->curIndex;
}


/************************************************************************
 *
 * F B _ G e t R a n g e
 *
 */
static PRInt32
FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, char **buf)
{
    PRInt32 amountRead;
    PRInt32 storedOffset;

    *buf = PR_Malloc(end - start + 2);
    if (*buf == NULL) {
      return 0;
    }

    storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);
    PR_Seek(fb->fd, start, PR_SEEK_SET);
    amountRead = PR_Read(fb->fd, *buf, end - start + 1);
    PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
    if (amountRead == -1) {
      PR_Free(*buf);
      *buf = NULL;
      return 0;
    }

    (*buf)[end-start+1] = '\0';
    return amountRead;
}


/************************************************************************
 *
 * F B _ D e s t r o y
 *
 */
static void 
FB_Destroy(FileBuffer *fb)
{
    if (fb) {
      PR_Free(fb);
    }
}


/************************************************************************
 *
 * P r i n t T a g I t e m
 *
 */
static void 
PrintTagItem(PRFileDesc *fd, TagItem *ti)
{
    AVPair * pair;

    PR_fprintf(fd, "TAG:\n----\nType: ");
    switch (ti->type) {
    case APPLET_TAG:
      PR_fprintf(fd, "applet\n");
      break;
    case SCRIPT_TAG:
      PR_fprintf(fd, "script\n");
      break;
    case LINK_TAG:
      PR_fprintf(fd, "link\n");
      break;
    case STYLE_TAG:
      PR_fprintf(fd, "style\n");
      break;
    case COMMENT_TAG:
      PR_fprintf(fd, "comment\n");
      break;
    case OTHER_TAG:
    default:
      PR_fprintf(fd, "other\n");
      break;
    }

    PR_fprintf(fd, "Attributes:\n");
    for (pair = ti->attList; pair; pair = pair->next) {
      PR_fprintf(fd, "\t%s=%s\n", pair->attribute,
          pair->value ? pair->value : "");
    }
    PR_fprintf(fd, "Text:%s\n", ti->text ? ti->text : "");

    PR_fprintf(fd, "---End of tag---\n");
}


/************************************************************************
 *
 * P r i n t H T M L S t r e a m
 *
 */
static void 
PrintHTMLStream(PRFileDesc *fd, HTMLItem *head)
{
    while (head) {
      if (head->type == TAG_ITEM) {
          PrintTagItem(fd, head->item.tag);
      } else {
          PR_fprintf(fd, "\nTEXT:\n-----\n%s\n-----\n\n", head->item.text);
      }
      head = head->next;
    }
}


/************************************************************************
 *
 * S a v e I n l i n e S c r i p t
 *
 */
static int  
SaveInlineScript(char *text, char *id, char *basedir, char *archiveDir)
{
    char    *filename = NULL;
    PRFileDesc * fd = NULL;
    int     retval = -1;
    PRInt32 writeLen;
    char    *ilDir = NULL;

    if (!text || !id || !archiveDir) {
      return - 1;
    }

    if (dumpParse) {
      PR_fprintf(outputFD, "SaveInlineScript: text=%s, id=%s, \n"
          "basedir=%s, archiveDir=%s\n",
          text, id, basedir, archiveDir);
    }

    /* Make sure the archive directory is around */
    if (ensureExists(basedir, archiveDir) != PR_SUCCESS) {
      PR_fprintf(errorFD,
          "ERROR: Unable to create archive directory %s.\n", archiveDir);
      errorCount++;
      return - 1;
    }

    /* Make sure the inline script directory is around */
    ilDir = PR_smprintf("%s/inlineScripts", archiveDir);
    scriptdir = "inlineScripts";
    if (ensureExists(basedir, ilDir) != PR_SUCCESS) {
      PR_fprintf(errorFD,
          "ERROR: Unable to create directory %s.\n", ilDir);
      errorCount++;
      return - 1;
    }

    filename = PR_smprintf("%s/%s/%s", basedir, ilDir, id);

    /* If the file already exists, give a warning, then blow it away */
    if (PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) {
      PR_fprintf(errorFD,
          "warning: file \"%s\" already exists--will overwrite.\n",
                        filename);
      warningCount++;
      if (rm_dash_r(filename)) {
          PR_fprintf(errorFD, "ERROR: Unable to delete %s.\n", filename);
          errorCount++;
          goto finish;
      }
    }

    /* Write text into file with name id */
    fd = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
    if (!fd) {
      PR_fprintf(errorFD, "ERROR: Unable to create file \"%s\".\n",
                        filename);
      errorCount++;
      goto finish;
    }
    writeLen = strlen(text);
    if ( PR_Write(fd, text, writeLen) != writeLen) {
      PR_fprintf(errorFD, "ERROR: Unable to write to file \"%s\".\n",
                        filename);
      errorCount++;
      goto finish;
    }

    retval = 0;
finish:
    if (filename) {
      PR_smprintf_free(filename);
    }
    if (ilDir) {
      PR_smprintf_free(ilDir);
    }
    if (fd) {
      PR_Close(fd);
    }
    return retval;
}


/************************************************************************
 *
 * S a v e U n n a m a b l e S c r i p t
 *
 */
static int  
SaveUnnamableScript(char *text, char *basedir, char *archiveDir,
char *HTMLfilename)
{
    char    *id = NULL;
    char    *ext = NULL;
    char    *start = NULL;
    int     retval = -1;

    if (!text || !archiveDir || !HTMLfilename) {
      return - 1;
    }

    if (dumpParse) {
      PR_fprintf(outputFD, "SaveUnnamableScript: text=%s, basedir=%s,\n"
          "archiveDir=%s, filename=%s\n", text, basedir, archiveDir,
                        HTMLfilename);
    }

    /* Construct the filename */
    ext = PL_strrchr(HTMLfilename, '.');
    if (ext) {
      *ext = '\0';
    }
    for (start = HTMLfilename; strpbrk(start, "/\\"); 
         start = strpbrk(start, "/\\") + 1)
      /* do nothing */;
    if (*start == '\0') 
      start = HTMLfilename;
    id = PR_smprintf("_%s%d", start, idOrdinal++);
    if (ext) {
      *ext = '.';
    }

    /* Now call SaveInlineScript to do the work */
    retval = SaveInlineScript(text, id, basedir, archiveDir);

    PR_Free(id);

    return retval;
}


/************************************************************************
 *
 * S a v e S o u r c e
 *
 */
static int  
SaveSource(char *src, char *codebase, char *basedir, char *archiveDir)
{
    char    *from = NULL, *to = NULL;
    int     retval = -1;
    char    *arcDir = NULL;

    if (!src || !archiveDir) {
      return - 1;
    }

    if (dumpParse) {
      PR_fprintf(outputFD, "SaveSource: src=%s, codebase=%s, basedir=%s,\n"
          "archiveDir=%s\n", src, codebase, basedir, archiveDir);
    }

    if (codebase) {
      arcDir = PR_smprintf("%s/%s/%s/", basedir, codebase, archiveDir);
    } else {
      arcDir = PR_smprintf("%s/%s/", basedir, archiveDir);
    }

    if (codebase) {
      from = PR_smprintf("%s/%s/%s", basedir, codebase, src);
      to = PR_smprintf("%s%s", arcDir, src);
    } else {
      from = PR_smprintf("%s/%s", basedir, src);
      to = PR_smprintf("%s%s", arcDir, src);
    }

    if (make_dirs(to, 0777)) {
      PR_fprintf(errorFD,
          "ERROR: Unable to create archive directory %s.\n", archiveDir);
      errorCount++;
      goto finish;
    }

    retval = copyinto(from, to);
finish:
    if (from) 
      PR_Free(from);
    if (to) 
      PR_Free(to);
    if (arcDir) 
      PR_Free(arcDir);
    return retval;
}


/************************************************************************
 *
 * T a g T y p e T o S t r i n g
 *
 */
char  *
TagTypeToString(TAG_TYPE type)
{
    switch (type) {
    case APPLET_TAG:
      return "APPLET";
    case SCRIPT_TAG:
      return "SCRIPT";
    case LINK_TAG:
      return "LINK";
    case STYLE_TAG:
      return "STYLE";
    default:
      break;
    }
    return "unknown";
}


/************************************************************************
 *
 * e x t r a c t _ j s
 *
 */
static int  
extract_js(char *filename)
{
    PRFileDesc * fd = NULL;
    FileBuffer * fb = NULL;
    HTMLItem * head = NULL;
    HTMLItem * tail = NULL;
    HTMLItem * curitem = NULL;
    HTMLItem * styleList      = NULL;
    HTMLItem * styleListTail  = NULL;
    HTMLItem * entityList     = NULL;
    HTMLItem * entityListTail = NULL;
    TagItem * tagp = NULL;
    char    *text = NULL;
    char    *tagerr = NULL;
    char    *archiveDir = NULL;
    char    *firstArchiveDir = NULL;
    char    *basedir = NULL;
    PRInt32    textStart;
    PRInt32    curOffset;
    HTML_STATE state;
    int            curchar;
    int            retval = -1;
    unsigned int linenum, startLine;

    /* Initialize the implicit ID counter for each file */
    idOrdinal = 0;

    /*
     * First, parse the HTML into a stream of tags and text.
     */

    fd = PR_Open(filename, PR_RDONLY, 0);
    if (!fd) {
      PR_fprintf(errorFD, "Unable to open %s for reading.\n", filename);
      errorCount++;
      return - 1;
    }

    /* Construct base directory of filename. */
     {
      char  *cp;

      basedir = PL_strdup(filename);

      /* Remove trailing slashes */
      while ( (cp = PL_strprbrk(basedir, "/\\")) == 
          (basedir + strlen(basedir) - 1)) {
          *cp = '\0';
      }

      /* Now remove everything from the last slash (which will be followed
       * by a filename) to the end */
      cp = PL_strprbrk(basedir, "/\\");
      if (cp) {
          *cp = '\0';
      }
    }

    state = TEXT_HTML_STATE;

    fb = FB_Create(fd);

    textStart = 0;
    startLine = 0;
    while (linenum = FB_GetLineNum(fb), (curchar = FB_GetChar(fb)) !=
        EOF) {
      switch (state) {
      case TEXT_HTML_STATE:
          if (curchar == '<') {
            /*
             * Found a tag
             */
            /* Save the text so far to a new text item */
            curOffset = FB_GetPointer(fb) - 2;
            if (curOffset >= textStart) {
                if (FB_GetRange(fb, textStart, curOffset,
                     &text) != 
                    curOffset - textStart + 1)  {
                  PR_fprintf(errorFD,
                      "Unable to read from %s.\n",
                       filename);
                  errorCount++;
                  goto loser;
                }
                /* little fudge here.  If the first character on a line
                 * is '<', meaning a new tag, the preceding text item
                 * actually ends on the previous line.  In this case
                 * we will be saying that the text segment ends on the
                 * next line. I don't think this matters for text items. */
                curitem = CreateTextItem(text, startLine,
                     linenum);
                text = NULL;
                if (tail == NULL) {
                  head = tail = curitem;
                } else {
                  tail->next = curitem;
                  tail = curitem;
                }
            }

            /* Process the tag */
            tagp = ProcessTag(fb, &tagerr);
            if (!tagp) {
                if (tagerr) {
                  PR_fprintf(errorFD, "Error in file %s: %s\n",
                                      filename, tagerr);
                  errorCount++;
                } else {
                  PR_fprintf(errorFD,
                      "Error in file %s, in tag starting at line %d\n",
                                      filename, linenum);
                  errorCount++;
                }
                goto loser;
            }
            /* Add the tag to the list */
            curitem = CreateTagItem(tagp, linenum, FB_GetLineNum(fb));
            if (tail == NULL) {
                head = tail = curitem;
            } else {
                tail->next = curitem;
                tail = curitem;
            }

            /* What's the next state */
            if (tagp->type == SCRIPT_TAG) {
                state = SCRIPT_HTML_STATE;
            }

            /* Start recording text from the new offset */
            textStart = FB_GetPointer(fb);
            startLine = FB_GetLineNum(fb);
          } else {
            /* regular character.  Next! */
          }
          break;
      case SCRIPT_HTML_STATE:
          if (curchar == '<') {
            char  *cp;
            /*
             * If this is a </script> tag, then we're at the end of the
             * script.  Otherwise, ignore
             */
            curOffset = FB_GetPointer(fb) - 1;
            cp = NULL;
            if (FB_GetRange(fb, curOffset, curOffset + 8, &cp) != 9) {
                if (cp) { 
                  PR_Free(cp); 
                  cp = NULL; 
                }
            } else {
                /* compare the strings */
                if ( !PORT_Strncasecmp(cp, "</script>", 9) ) {
                  /* This is the end of the script. Record the text. */
                  curOffset--;
                  if (curOffset >= textStart) {
                      if (FB_GetRange(fb, textStart, curOffset, &text) != 
                          curOffset - textStart + 1) {
                        PR_fprintf(errorFD, "Unable to read from %s.\n",
                             filename);
                        errorCount++;
                        goto loser;
                      }
                      curitem = CreateTextItem(text, startLine, linenum);
                      text = NULL;
                      if (tail == NULL) {
                        head = tail = curitem;
                      } else {
                        tail->next = curitem;
                        tail = curitem;
                      }
                  }

                  /* Now parse the /script tag and put it on the list */
                  tagp = ProcessTag(fb, &tagerr);
                  if (!tagp) {
                      if (tagerr) {
                        PR_fprintf(errorFD, "Error in file %s: %s\n",
                             filename, tagerr);
                      } else {
                        PR_fprintf(errorFD, 
                            "Error in file %s, in tag starting at"
                            " line %d\n", filename, linenum);
                      }
                      errorCount++;
                      goto loser;
                  }
                  curitem = CreateTagItem(tagp, linenum,
                                    FB_GetLineNum(fb));
                  if (tail == NULL) {
                      head = tail = curitem;
                  } else {
                      tail->next = curitem;
                      tail = curitem;
                  }

                  /* go back to text state */
                  state = TEXT_HTML_STATE;

                  textStart = FB_GetPointer(fb);
                  startLine = FB_GetLineNum(fb);
                }
            }
          }
          break;
      }
    }

    /* End of the file.  Wrap up any remaining text */
    if (state == SCRIPT_HTML_STATE) {
      if (tail && tail->type == TAG_ITEM) {
          PR_fprintf(errorFD, "ERROR: <SCRIPT> tag at %s:%d is not followed "
              "by a </SCRIPT> tag.\n", filename, tail->startLine);
      } else {
          PR_fprintf(errorFD, "ERROR: <SCRIPT> tag in file %s is not followed"
              " by a </SCRIPT tag.\n", filename);
      }
      errorCount++;
      goto loser;
    }
    curOffset = FB_GetPointer(fb) - 1;
    if (curOffset >= textStart) {
      text = NULL;
      if ( FB_GetRange(fb, textStart, curOffset, &text) != 
          curOffset - textStart + 1) {
          PR_fprintf(errorFD, "Unable to read from %s.\n", filename);
          errorCount++;
          goto loser;
      }
      curitem = CreateTextItem(text, startLine, linenum);
      text = NULL;
      if (tail == NULL) {
          head = tail = curitem;
      } else {
          tail->next = curitem;
          tail = curitem;
      }
    }

    if (dumpParse) {
      PrintHTMLStream(outputFD, head);
    }

    /*
     * Now we have a stream of tags and text.  Go through and deal with each.
     */
    for (curitem = head; curitem; curitem = curitem->next) {
      TagItem * tagp = NULL;
      AVPair * pairp = NULL;
      char  *src = NULL, *id = NULL, *codebase = NULL;
      PRBool hasEventHandler = PR_FALSE;
      int   i;

      /* Reset archive directory for each tag */
      if (archiveDir) {
          PR_Free(archiveDir); 
          archiveDir = NULL;
      }

      /* We only analyze tags */
      if (curitem->type != TAG_ITEM) {
          continue;
      }

      tagp = curitem->item.tag;

      /* go through the attributes to get information */
      for (pairp = tagp->attList; pairp; pairp = pairp->next) {

          /* ARCHIVE= */
          if ( !PL_strcasecmp(pairp->attribute, "archive")) {
            if (archiveDir) {
                /* Duplicate attribute.  Print warning */
                PR_fprintf(errorFD,
                    "warning: \"%s\" attribute overwrites previous attribute"
                    " in tag starting at %s:%d.\n",
                    pairp->attribute, filename, curitem->startLine);
                warningCount++;
                PR_Free(archiveDir);
            }
            archiveDir = PL_strdup(pairp->value);

            /* Substiture ".arc" for ".jar" */
            if ( (PL_strlen(archiveDir) < 4) || 
                PL_strcasecmp((archiveDir + strlen(archiveDir) -4), 
                  ".jar")) {
                PR_fprintf(errorFD,
                    "warning: ARCHIVE attribute should end in \".jar\" in tag"
                    " starting on %s:%d.\n", filename, curitem->startLine);
                warningCount++;
                PR_Free(archiveDir);
                archiveDir = PR_smprintf("%s.arc", archiveDir);
            } else {
                PL_strcpy(archiveDir + strlen(archiveDir) -4, ".arc");
            }

            /* Record the first archive.  This will be used later if
             * the archive is not specified */
            if (firstArchiveDir == NULL) {
                firstArchiveDir = PL_strdup(archiveDir);
            }
          } 
          /* CODEBASE= */
          else if ( !PL_strcasecmp(pairp->attribute, "codebase")) {
            if (codebase) {
                /* Duplicate attribute.  Print warning */
                PR_fprintf(errorFD,
                    "warning: \"%s\" attribute overwrites previous attribute"
                    " in tag staring at %s:%d.\n",
                    pairp->attribute, filename, curitem->startLine);
                warningCount++;
            }
            codebase = pairp->value;
          } 
          /* SRC= and HREF= */
          else if ( !PORT_Strcasecmp(pairp->attribute, "src") ||
              !PORT_Strcasecmp(pairp->attribute, "href") ) {
            if (src) {
                /* Duplicate attribute.  Print warning */
                PR_fprintf(errorFD,
                    "warning: \"%s\" attribute overwrites previous attribute"
                    " in tag staring at %s:%d.\n",
                    pairp->attribute, filename, curitem->startLine);
                warningCount++;
            }
            src = pairp->value;
          } 
          /* CODE= */
          else if (!PORT_Strcasecmp(pairp->attribute, "code") ) {
            /*!!!XXX Change PORT to PL all over this code !!! */
            if (src) {
                /* Duplicate attribute.  Print warning */
                PR_fprintf(errorFD,
                    "warning: \"%s\" attribute overwrites previous attribute"
                    " ,in tag staring at %s:%d.\n",
                    pairp->attribute, filename, curitem->startLine);
                warningCount++;
            }
            src = pairp->value;

            /* Append a .class if one is not already present */
            if ( (PL_strlen(src) < 6) || 
                PL_strcasecmp( (src + PL_strlen(src) - 6), ".class") ) {
                src = PR_smprintf("%s.class", src);
                /* Put this string back into the data structure so it
                 * will be deallocated properly */
                PR_Free(pairp->value);
                pairp->value = src;
            }
          } 
          /* ID= */
          else if (!PL_strcasecmp(pairp->attribute, "id") ) {
            if (id) {
                /* Duplicate attribute.  Print warning */
                PR_fprintf(errorFD,
                    "warning: \"%s\" attribute overwrites previous attribute"
                    " in tag staring at %s:%d.\n",
                    pairp->attribute, filename, curitem->startLine);
                warningCount++;
            }
            id = pairp->value;
          }

          /* STYLE= */
          /* style= attributes, along with JS entities, are stored into
           * files with dynamically generated names. The filenames are
           * based on the order in which the text is found in the file.
           * All JS entities on all lines up to and including the line
           * containing the end of the tag that has this style= attribute
           * will be processed before this style=attribute.  So we need
           * to record the line that this _tag_ (not the attribute) ends on.
           */
          else if (!PL_strcasecmp(pairp->attribute, "style") && pairp->value) 
          {
            HTMLItem * styleItem;
            /* Put this item on the style list */
            styleItem = CreateTextItem(PL_strdup(pairp->value),
                curitem->startLine, curitem->endLine);
            if (styleListTail == NULL) {
                styleList = styleListTail = styleItem;
            } else {
                styleListTail->next = styleItem;
                styleListTail = styleItem;
            }
          } 
          /* Event handlers */
          else {
            for (i = 0; i < num_handlers; i++) {
                if (!PL_strcasecmp(event_handlers[i], pairp->attribute)) {
                  hasEventHandler = PR_TRUE;
                  break;
                }
            }
          }


          /* JS Entity */
          {
            char  *entityStart, *entityEnd;
            HTMLItem * entityItem;

            /* go through each JavaScript entity ( &{...}; ) and store it
             * in the entityList.  The important thing is to record what
             * line number it's on, so we can get it in the right order
             * in relation to style= attributes.
             * Apparently, these can't flow across lines, so the start and
             * end line will be the same.  That helps matters.
             */
            entityEnd = pairp->value;
            while ( entityEnd && 
                (entityStart = PL_strstr(entityEnd, "&{")) /*}*/ != NULL) {
                entityStart += 2; /* point at beginning of actual entity */
                entityEnd = PL_strstr(entityStart, /*{*/ "}");
                if (entityEnd) {
                  /* Put this item on the entity list */
                  *entityEnd = '\0';
                  entityItem = CreateTextItem(PL_strdup(entityStart),
                                  pairp->valueLine, pairp->valueLine);
                  *entityEnd = /* { */ '}';
                  if (entityListTail) {
                      entityListTail->next = entityItem;
                      entityListTail = entityItem;
                  } else {
                      entityList = entityListTail = entityItem;
                  }
                }
            }
          }
      }

      /* If no archive was supplied, we use the first one of the file */
      if (!archiveDir && firstArchiveDir) {
          archiveDir = PL_strdup(firstArchiveDir);
      }

      /* If we have an event handler, we need to archive this tag */
      if (hasEventHandler) {
          if (!id) {
            PR_fprintf(errorFD,
                "warning: tag starting at %s:%d has event handler but"
                " no ID attribute.  The tag will not be signed.\n",
                              filename, curitem->startLine);
            warningCount++;
          } else if (!archiveDir) {
            PR_fprintf(errorFD,
                "warning: tag starting at %s:%d has event handler but"
                " no ARCHIVE attribute.  The tag will not be signed.\n",
                                  filename, curitem->startLine);
            warningCount++;
          } else {
            if (SaveInlineScript(tagp->text, id, basedir, archiveDir)) {
                goto loser;
            }
          }
      }

      switch (tagp->type) {
      case APPLET_TAG:
          if (!src) {
            PR_fprintf(errorFD,
                "error: APPLET tag starting on %s:%d has no CODE "
                "attribute.\n", filename, curitem->startLine);
            errorCount++;
            goto loser;
          } else if (!archiveDir) {
            PR_fprintf(errorFD,
                "error: APPLET tag starting on %s:%d has no ARCHIVE "
                "attribute.\n", filename, curitem->startLine);
            errorCount++;
            goto loser;
          } else {
            if (SaveSource(src, codebase, basedir, archiveDir)) {
                goto loser;
            }
          }
          break;
      case SCRIPT_TAG:
      case LINK_TAG:
      case STYLE_TAG:
          if (!archiveDir) {
            PR_fprintf(errorFD,
                "error: %s tag starting on %s:%d has no ARCHIVE "
                "attribute.\n", TagTypeToString(tagp->type),
                                  filename, curitem->startLine);
            errorCount++;
            goto loser;
          } else if (src) {
            if (SaveSource(src, codebase, basedir, archiveDir)) {
                goto loser;
            }
          } else if (id) {
            /* Save the next text item */
            if (!curitem->next || (curitem->next->type !=
                TEXT_ITEM)) {
                PR_fprintf(errorFD,
                    "warning: %s tag starting on %s:%d is not followed"
                    " by script text.\n", TagTypeToString(tagp->type),
                                  filename, curitem->startLine);
                warningCount++;
                /* just create empty file */
                if (SaveInlineScript("", id, basedir, archiveDir)) {
                  goto loser;
                }
            } else {
                curitem = curitem->next;
                if (SaveInlineScript(curitem->item.text,
                     id, basedir,
                    archiveDir)) {
                  goto loser;
                }
            }
          } else {
            /* No src or id tag--warning */
            PR_fprintf(errorFD,
                "warning: %s tag starting on %s:%d has no SRC or"
                " ID attributes.  Will not sign.\n",
                TagTypeToString(tagp->type), filename, curitem->startLine);
            warningCount++;
          }
          break;
      default:
          /* do nothing for other tags */
          break;
      }

    }

    /* Now deal with all the unnamable scripts */
    if (firstArchiveDir) {
      HTMLItem * style, *entity;

      /* Go through the lists of JS entities and style attributes.  Do them
       * in chronological order within a list.  Pick the list with the lower
       * endLine. In case of a tie, entities come first.
       */
      style = styleList; 
      entity = entityList;
      while (style || entity) {
          if (!entity || (style && (style->endLine < entity->endLine))) {
            /* Process style */
            SaveUnnamableScript(style->item.text, basedir, firstArchiveDir,
                            filename);
            style = style->next;
          } else {
            /* Process entity */
            SaveUnnamableScript(entity->item.text, basedir, firstArchiveDir,
                            filename);
            entity = entity->next;
          }
      }
    }


    retval = 0;
loser:
    /* Blow away the stream */
    while (head) {
      curitem = head;
      head = head->next;
      DestroyHTMLItem(curitem);
    }
    while (styleList) {
      curitem = styleList;
      styleList = styleList->next;
      DestroyHTMLItem(curitem);
    }
    while (entityList) {
      curitem = entityList;
      entityList = entityList->next;
      DestroyHTMLItem(curitem);
    }
    if (text) {
      PR_Free(text); 
      text = NULL;
    }
    if (fb) {
      FB_Destroy(fb); 
      fb = NULL;
    }
    if (fd) {
      PR_Close(fd);
    }
    if (tagerr) {
      PR_smprintf_free(tagerr); 
      tagerr = NULL;
    }
    if (archiveDir) {
      PR_Free(archiveDir); 
      archiveDir = NULL;
    }
    if (firstArchiveDir) {
      PR_Free(firstArchiveDir); 
      firstArchiveDir = NULL;
    }
    return retval;
}


/**********************************************************************
 *
 * e n s u r e E x i s t s
 *
 * Check for existence of indicated directory.  If it doesn't exist,
 * it will be created.
 * Returns PR_SUCCESS if the directory is present, PR_FAILURE otherwise.
 */
static PRStatus
ensureExists (char *base, char *path)
{
    char    fn [FNSIZE];
    PRDir * dir;
    sprintf (fn, "%s/%s", base, path);

    /*PR_fprintf(outputFD, "Trying to open directory %s.\n", fn);*/

    if ( (dir = PR_OpenDir(fn)) ) {
      PR_CloseDir(dir);
      return PR_SUCCESS;
    }
    return PR_MkDir(fn, 0777);
}


/***************************************************************************
 *
 * m a k e _ d i r s
 *
 * Ensure that the directory portion of the path exists.  This may require
 * making the directory, and its parent, and its parent's parent, etc.
 */
static int  
make_dirs(char *path, int file_perms)
{
    char    *Path;
    char    *start;
    char    *sep;
    int     ret = 0;
    PRFileInfo info;

    if (!path) {
      return 0;
    }

    Path = PL_strdup(path);
    start = strpbrk(Path, "/\\");
    if (!start) {
      return 0;
    }
    start++; /* start right after first slash */

    /* Each time through the loop add one more directory. */
    while ( (sep = strpbrk(start, "/\\")) ) {
      *sep = '\0';

      if ( PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
          /* No such dir, we have to create it */
          if ( PR_MkDir(Path, file_perms) != PR_SUCCESS) {
            PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
                                          Path);
            errorCount++;
            ret = -1;
            goto loser;
          }
      } else {
          /* something exists by this name, make sure it's a directory */
          if ( info.type != PR_FILE_DIRECTORY ) {
            PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
                                          Path);
            errorCount++;
            ret = -1;
            goto loser;
          }
      }

      start = sep + 1; /* start after the next slash */
      *sep = '/';
    }

loser:
    PR_Free(Path);
    return ret;
}


/*
 *  c o p y i n t o
 *
 *  Function to copy file "from" to path "to".
 *
 */
static int  
copyinto (char *from, char *to)
{
    PRInt32 num;
    char    buf [BUFSIZ];
    PRFileDesc * infp = NULL, *outfp = NULL;
    int     retval = -1;

    if ((infp = PR_Open(from, PR_RDONLY, 0777)) == NULL) {
      PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for reading.\n",
                        from);
      errorCount++;
      goto finish;
    }

    /* If to already exists, print a warning before deleting it */
    if (PR_Access(to, PR_ACCESS_EXISTS) == PR_SUCCESS) {
      PR_fprintf(errorFD, "warning: %s already exists--will overwrite\n", to);
      warningCount++;
      if (rm_dash_r(to)) {
          PR_fprintf(errorFD,
              "ERROR: Unable to remove %s.\n", to);
          errorCount++;
          goto finish;
      }
    }

    if ((outfp = PR_Open(to, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777))
         == NULL) {
      char  *errBuf = NULL;

      errBuf = PR_Malloc(PR_GetErrorTextLength());
      PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for writing.\n", to);
      if (PR_GetErrorText(errBuf)) {
          PR_fprintf(errorFD, "Cause: %s\n", errBuf);
      }
      if (errBuf) {
          PR_Free(errBuf);
      }
      errorCount++;
      goto finish;
    }

    while ( (num = PR_Read(infp, buf, BUFSIZ)) > 0) {
      if (PR_Write(outfp, buf, num) != num) {
          PR_fprintf(errorFD, "ERROR: Error writing to %s.\n", to);
          errorCount++;
          goto finish;
      }
    }

    retval = 0;
finish:
    if (infp) 
      PR_Close(infp);
    if (outfp) 
      PR_Close(outfp);

    return retval;
}



Generated by  Doxygen 1.6.0   Back to index