e8c49892a310a78f0e33d100e54af931bbe00f70
[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 /*
68   Given a detected URI token, get only the URI specified within.
69   Also adjust the starting position and length of the string.
70
71   A URI can be specified with or without quotes, and the quotes
72   can be single or double quotes.  In addition there can be
73   whitespace after the opening parenthesis and before the closing
74   parenthesis.
75 */
76 static char *
77 get_uri_string (const char *at, int *pos, int *length)
78 {
79   char *uri;
80   /*char buf[1024];
81   strncpy(buf,at + *pos, *length);
82   buf[*length] = '\0';
83   DEBUGP (("get_uri_string: \"%s\"\n", buf));*/
84
85   if (0 != strncasecmp (at + *pos, "url(", 4))
86     return NULL;
87
88   *pos += 4;
89   *length -= 5; /* url() */
90   /* skip leading space */
91   while (isspace (at[*pos]))
92     {
93       (*pos)++;
94       if (--(*length) == 0)
95         return NULL;
96     }
97
98   /* skip trailing space */
99   while (isspace (at[*pos + *length - 1]))
100     {
101       (*length)--;
102     }
103   /* trim off quotes */
104   if (at[*pos] == '\'' || at[*pos] == '"')
105     {
106       (*pos)++;
107       *length -= 2;
108     }
109
110   uri = xmalloc (*length + 1);
111   if (uri)
112     {
113       strncpy (uri, at + *pos, *length);
114       uri[*length] = '\0';
115     }
116
117   return uri;
118 }
119
120 void
121 get_urls_css (struct map_context *ctx, int offset, int buf_length)
122 {
123   int token;
124   /*char tmp[2048];*/
125   int buffer_pos = 0;
126   int pos, length;
127   char *uri;
128
129   /*
130   strncpy(tmp,ctx->text + offset, buf_length);
131   tmp[buf_length] = '\0';
132   DEBUGP (("get_urls_css: \"%s\"\n", tmp));
133   */
134
135   /* tell flex to scan from this buffer */
136   yy_scan_bytes (ctx->text + offset, buf_length);
137
138   while((token = yylex()) != CSSEOF)
139     {
140       /*DEBUGP (("%s ", token_names[token]));*/
141       /* @import "foo.css"
142          or @import url(foo.css)
143       */
144       if(token == IMPORT_SYM)
145         {
146           do {
147             buffer_pos += yyleng;
148           } while((token = yylex()) == S);
149
150           /*DEBUGP (("%s ", token_names[token]));*/
151
152           if (token == STRING || token == URI)
153             {
154               /*DEBUGP (("Got URI "));*/
155               pos = buffer_pos + offset;
156               length = yyleng;
157
158               if (token == URI)
159                 {
160                   uri = get_uri_string (ctx->text, &pos, &length);
161                 }
162               else
163                 {
164                   /* cut out quote characters */
165                   pos++;
166                   length -= 2;
167                   uri = xmalloc (length + 1);
168                   strncpy (uri, yytext + 1, length);
169                   uri[length] = '\0';
170                 }
171
172               if (uri)
173                 {
174                   struct urlpos *up = append_url (uri, pos, length, ctx);
175                   DEBUGP (("Found @import: [%s] at %d [%s]\n", yytext, buffer_pos, uri));
176
177                   if (up)
178                     {
179                       up->link_inline_p = 1;
180                       up->link_css_p = 1;
181                       up->link_expect_css = 1;
182                     }
183
184                   xfree(uri);
185                 }
186             }
187         }
188       /* background-image: url(foo.png)
189          note that we don't care what
190          property this is actually on.
191       */
192       else if(token == URI)
193         {
194           pos = buffer_pos + offset;
195           length = yyleng;
196           uri = get_uri_string (ctx->text, &pos, &length);
197
198           if (uri)
199             {
200               struct urlpos *up = append_url (uri, pos, length, ctx);
201               DEBUGP (("Found URI: [%s] at %d [%s]\n", yytext, buffer_pos, uri));
202               if (up)
203                 {
204                   up->link_inline_p = 1;
205                   up->link_css_p = 1;
206                 }
207
208               xfree (uri);
209             }
210         }
211       buffer_pos += yyleng;
212     }
213   DEBUGP (("\n"));
214 }
215
216 struct urlpos *
217 get_urls_css_file (const char *file, const char *url)
218 {
219   struct file_memory *fm;
220   struct map_context ctx;
221
222   /* Load the file. */
223   fm = wget_read_file (file);
224   if (!fm)
225     {
226       logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
227       return NULL;
228     }
229   DEBUGP (("Loaded %s (size %s).\n", file, number_to_static_string (fm->length)));
230
231   ctx.text = fm->content;
232   ctx.head = NULL;
233   ctx.base = NULL;
234   ctx.parent_base = url ? url : opt.base_href;
235   ctx.document_file = file;
236   ctx.nofollow = 0;
237
238   get_urls_css (&ctx, 0, fm->length);
239   wget_read_file_free (fm);
240   return ctx.head;
241 }