security/nss/cmd/signtool/javascript.c

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

mercurial