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