]> sjero.net Git - wget/blob - src/css-url.c
Ted Mielczarek's CSS wonder-patch, applied against the source from around the time...
[wget] / src / css-url.c
1 /* Collect URLs from CSS source.
2    Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 /*
31   Note that this is not an actual CSS parser, but just a lexical
32   scanner with a tiny bit more smarts bolted on top.  A full parser
33   is somewhat overkill for this job.  The only things we're interested
34   in are @import rules and url() tokens, so it's easy enough to
35   grab those without truly understanding the input.  The only downside
36   to this is that we might be coerced into downloading files that
37   a browser would ignore.  That might merit some more investigation.
38  */
39
40 #include <config.h>
41
42 #include <stdio.h>
43 #ifdef HAVE_STRING_H
44 # include <string.h>
45 #else
46 # include <strings.h>
47 #endif
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include <assert.h>
52
53 #include "wget.h"
54 #include "utils.h"
55 #include "convert.h"
56 #include "html-url.h"
57 #include "css-tokens.h"
58
59 /* from lex.yy.c */
60 extern char *yytext;
61 extern int yyleng;
62 typedef struct yy_buffer_state *YY_BUFFER_STATE;
63 extern YY_BUFFER_STATE yy_scan_bytes (const char *bytes,int len  );
64 extern int yylex (void);
65
66 #if 1
67 const char *token_names[] = {
68   "CSSEOF",
69   "S",
70   "CDO",
71   "CDC",
72   "INCLUDES",
73   "DASHMATCH",
74   "LBRACE",
75   "PLUS",
76   "GREATER",
77   "COMMA",
78   "STRING",
79   "INVALID",
80   "IDENT",
81   "HASH",
82   "IMPORT_SYM",
83   "PAGE_SYM",
84   "MEDIA_SYM",
85   "CHARSET_SYM",
86   "IMPORTANT_SYM",
87   "EMS",
88   "EXS",
89   "LENGTH",
90   "ANGLE",
91   "TIME",
92   "FREQ",
93   "DIMENSION",
94   "PERCENTAGE",
95   "NUMBER",
96   "URI",
97   "FUNCTION"
98 };
99 #endif
100
101 /*
102   Given a detected URI token, get only the URI specified within.
103   Also adjust the starting position and length of the string.
104
105   A URI can be specified with or without quotes, and the quotes
106   can be single or double quotes.  In addition there can be
107   whitespace after the opening parenthesis and before the closing
108   parenthesis.
109 */
110 char *
111 get_uri_string (const char *at, int *pos, int *length)
112 {
113   char *uri;
114   /*char buf[1024];
115   strncpy(buf,at + *pos, *length);
116   buf[*length] = '\0';
117   DEBUGP (("get_uri_string: \"%s\"\n", buf));*/
118
119   if (0 != strncasecmp (at + *pos, "url(", 4))
120     return NULL;
121
122   *pos += 4;
123   *length -= 5; /* url() */
124   /* skip leading space */
125   while (isspace (at[*pos]))
126     {
127     (*pos)++;
128     (*length)--;
129     }
130   /* skip trailing space */
131   while (isspace (at[*pos + *length - 1]))
132     {
133       (*length)--;
134     }
135   /* trim off quotes */
136   if (at[*pos] == '\'' || at[*pos] == '"')
137     {
138       (*pos)++;
139       *length -= 2;
140     }
141
142   uri = xmalloc (*length + 1);
143   if (uri)
144     {
145       strncpy (uri, at + *pos, *length);
146       uri[*length] = '\0';      
147     }
148
149   return uri;
150 }
151
152 void
153 get_urls_css (struct map_context *ctx, int offset, int buf_length)
154 {
155   int token;
156   /*char tmp[2048];*/
157   int buffer_pos = 0;
158   int pos, length;
159   char *uri;
160
161   /*
162   strncpy(tmp,ctx->text + offset, buf_length);
163   tmp[buf_length] = '\0';
164   DEBUGP (("get_urls_css: \"%s\"\n", tmp));
165   */
166
167   /* tell flex to scan from this buffer */
168   yy_scan_bytes (ctx->text + offset, buf_length);
169
170   while((token = yylex()) != CSSEOF)
171     {
172       /*DEBUGP (("%s ", token_names[token]));*/
173       /* @import "foo.css"
174          or @import url(foo.css)
175       */
176       if(token == IMPORT_SYM)
177         {
178           do {
179             buffer_pos += yyleng;
180           } while((token = yylex()) == S);
181
182           /*DEBUGP (("%s ", token_names[token]));*/
183
184           if (token == STRING || token == URI)
185             {
186               /*DEBUGP (("Got URI "));*/
187               pos = buffer_pos + offset;
188               length = yyleng;
189
190               if (token == URI)
191                 {
192                   uri = get_uri_string (ctx->text, &pos, &length);
193                 }
194               else
195                 {
196                   /* cut out quote characters */
197                   pos++;
198                   length -= 2;
199                   uri = xmalloc (length + 1);
200                   strncpy (uri, yytext + 1, length);
201                   uri[length] = '\0';
202                 }
203
204               if (uri)
205                 {
206                   struct urlpos *up = append_url (uri, pos, length, ctx);
207                   DEBUGP (("Found @import: [%s] at %d [%s]\n", yytext, buffer_pos, uri));
208
209                   if (up)
210                     {
211                       up->link_inline_p = 1;
212                       up->link_css_p = 1;
213                       up->link_expect_css = 1;
214                     }
215
216                   xfree(uri);
217                 }
218             }
219         }
220       /* background-image: url(foo.png)
221          note that we don't care what
222          property this is actually on.
223       */
224       else if(token == URI)
225         {
226           pos = buffer_pos + offset;
227           length = yyleng;
228           uri = get_uri_string (ctx->text, &pos, &length);
229
230           if (uri)
231             {
232               struct urlpos *up = append_url (uri, pos, length, ctx);
233               DEBUGP (("Found URI: [%s] at %d [%s]\n", yytext, buffer_pos, uri));
234               if (up)
235                 {
236                   up->link_inline_p = 1;
237                   up->link_css_p = 1;
238                 }
239
240               xfree (uri);
241             }
242         }
243       buffer_pos += yyleng;
244     }
245   DEBUGP (("\n"));
246 }
247
248 struct urlpos *
249 get_urls_css_file (const char *file, const char *url)
250 {
251   struct file_memory *fm;
252   struct map_context ctx;
253
254   /* Load the file. */
255   fm = read_file (file);
256   if (!fm)
257     {
258       logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
259       return NULL;
260     }
261   DEBUGP (("Loaded %s (size %s).\n", file, number_to_static_string (fm->length)));
262
263   ctx.text = fm->content;
264   ctx.head = ctx.tail = NULL;
265   ctx.base = NULL;
266   ctx.parent_base = url ? url : opt.base_href;
267   ctx.document_file = file;
268   ctx.nofollow = 0;
269
270   get_urls_css (&ctx, 0, fm->length);
271   read_file_free (fm);
272   return ctx.head;
273 }