javascript.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:43k
源码类别:

CA认证

开发平台:

WINDOWS

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