Tiny bugfix in AC_ARG_WITH(debug)
[privoxy.git] / encode.c
1 const char encode_rcs[] = "$Id: encode.c,v 1.4 2002/01/22 23:28:07 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/encode.c,v $
5  *
6  * Purpose     :  Functions to encode and decode URLs, and also to
7  *                encode cookies and HTML text.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                IJBSWA team.  http://ijbswa.sourceforge.net
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: encode.c,v $
36  *    Revision 1.4  2002/01/22 23:28:07  jongfoster
37  *    Adding convenience function html_encode_and_free_original()
38  *    Making all functions accept NULL paramaters - in this case, they
39  *    simply return NULL.  This allows error-checking to be deferred.
40  *
41  *    Revision 1.3  2001/11/13 00:16:40  jongfoster
42  *    Replacing references to malloc.h with the standard stdlib.h
43  *    (See ANSI or K&R 2nd Ed)
44  *
45  *    Revision 1.2  2001/05/17 22:52:35  oes
46  *     - Cleaned CRLF's from the sources and related files
47  *
48  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
49  *    Initial import of version 2.9.3 source tree
50  *
51  *
52  *********************************************************************/
53 \f
54
55 #include "config.h"
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 #include "encode.h"
62
63 const char encode_h_rcs[] = ENCODE_H_VERSION;
64
65 /* Maps special characters in a URL to their equivalent % codes. */
66 static const char * const url_code_map[256] = {
67    NULL, "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09",
68    "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13",
69    "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D",
70    "%1E", "%1F", "+",   "%21", "%22", "%23", "%24", "%25", "%26", "%27",
71    "%28", "%29", NULL,  "%2B", "%2C", NULL,  NULL,  "%2F", NULL,  NULL,
72    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  "%3A", "%3B",
73    "%3C", "%3D", "%3E", "%3F", NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
74    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
75    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
76    NULL,  "%5B", "%5C", "%5D", "%5E", NULL,  "%60", NULL,  NULL,  NULL,
77    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
78    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
79    NULL,  NULL,  NULL,  "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81",
80    "%82", "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8A", "%8B",
81    "%8C", "%8D", "%8E", "%8F", "%90", "%91", "%92", "%93", "%94", "%95",
82    "%96", "%97", "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
83    "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", "%A8", "%A9",
84    "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", "%B0", "%B1", "%B2", "%B3",
85    "%B4", "%B5", "%B6", "%B7", "%B8", "%B9", "%BA", "%BB", "%BC", "%BD",
86    "%BE", "%BF", "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
87    "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", "%D0", "%D1",
88    "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", "%D8", "%D9", "%DA", "%DB",
89    "%DC", "%DD", "%DE", "%DF", "%E0", "%E1", "%E2", "%E3", "%E4", "%E5",
90    "%E6", "%E7", "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
91    "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", "%F8", "%F9",
92    "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
93 };
94
95 /* Maps special characters in HTML to their equivalent entites. */
96 static const char * const html_code_map[256] = {
97    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
98    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
99    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
100    NULL, NULL, NULL, NULL,"&quot;",NULL,NULL,NULL,"&amp;",NULL,
101    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
102    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
103    "&lt;",NULL,"&gt;",NULL,NULL, NULL, NULL, NULL, NULL, NULL,
104    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
105    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
106    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
107    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
108    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
109    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
110    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
111    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
112    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
113    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
115    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
116    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
117    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
118    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
119    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
120    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
121    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
122    NULL, NULL, NULL, NULL, NULL, NULL
123 };
124
125 /* Maps special characters in a cookie to their equivalent % codes. */
126 static const char * const cookie_code_map[256] = {
127    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
128    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
129    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
130    NULL, NULL, "+",  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
131    NULL, NULL, NULL, NULL, "%2C",NULL, NULL, NULL, NULL, NULL,
132    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "%3B",
133    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
134    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
135    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
136    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
137    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
138    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
139    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
140    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
141    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
142    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
143    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
144    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
145    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
146    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
147    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
148    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
149    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
150    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
151    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
152    NULL, NULL, NULL, NULL, NULL, NULL
153 };
154
155
156 /*********************************************************************
157  *
158  * Function    :  html_encode
159  *
160  * Description :  Encodes a string so it's not interpreted as
161  *                containing HTML tags or entities.
162  *                Replaces <, >, &, and " with the appropriate HTML
163  *                entities.
164  *
165  * Parameters  :
166  *          1  :  s = String to encode.  Null-terminated.
167  *
168  * Returns     :  Encoded string, newly allocated on the heap. 
169  *                Caller is responsible for freeing it with free().
170  *                If s is NULL, or on out-of memory, returns NULL.
171  *
172  *********************************************************************/
173 char * html_encode(const char *s)
174 {
175    char * buf;
176    
177    if (s == NULL)
178    {
179       return NULL;
180    }
181
182    /* each input char can expand to at most 6 chars */
183    buf = (char *) malloc((strlen(s) * 6) + 1);
184
185    if (buf)
186    {
187       char c;
188       char * p = buf;
189       while ( (c = *s++) != '\0')
190       {
191          const char * replace_with = html_code_map[(unsigned char) c];
192          if(replace_with != NULL)
193          {
194             strcpy(p, replace_with);
195             p += strlen(replace_with);
196          }
197          else
198          {
199             *p++ = c;
200          }
201       }
202
203       *p = '\0';
204    }
205
206    return(buf);
207 }
208
209
210 /*********************************************************************
211  *
212  * Function    :  html_encode_and_free_original
213  *
214  * Description :  Encodes a string so it's not interpreted as
215  *                containing HTML tags or entities.
216  *                Replaces <, >, &, and " with the appropriate HTML
217  *                entities.  Free()s original string.
218  *                If original string is NULL, simply returns NULL.
219  *
220  * Parameters  :
221  *          1  :  s = String to encode.  Null-terminated.
222  *
223  * Returns     :  Encoded string, newly allocated on the heap. 
224  *                Caller is responsible for freeing it with free().
225  *                If s is NULL, or on out-of memory, returns NULL.
226  *
227  *********************************************************************/
228 char * html_encode_and_free_original(char *s)
229 {
230    char * result;
231    
232    if (s == NULL)
233    {
234       return NULL;
235    }
236
237    result = html_encode(s);
238    free(s);
239
240    return result;
241 }
242
243
244 /*********************************************************************
245  *
246  * Function    :  cookie_encode
247  *
248  * Description :  Encodes a string so it can be used in a cookie.
249  *                Replaces " ", ",", and ";" with the appropriate
250  *                codes.
251  *
252  * Parameters  :
253  *          1  :  s = String to encode.  Null-terminated.
254  *
255  * Returns     :  Encoded string, newly allocated on the heap. 
256  *                Caller is responsible for freeing it with free().
257  *                If s is NULL, or on out-of memory, returns NULL.
258  *
259  *********************************************************************/
260 char * cookie_encode(const char *s)
261 {
262    char * buf;
263
264    if (s == NULL)
265    {
266       return NULL;
267    }
268
269    /* each input char can expand to at most 3 chars */
270    buf = (char *) malloc((strlen(s) * 3) + 1);
271
272    if (buf)
273    {
274       char c;
275       char * p = buf;
276       while ( (c = *s++) != '\0')
277       {
278          const char * replace_with = cookie_code_map[(unsigned char) c];
279          if (replace_with != NULL)
280          {
281             strcpy(p, replace_with);
282             p += strlen(replace_with);
283          }
284          else
285          {
286             *p++ = c;
287          }
288       }
289
290       *p = '\0';
291    }
292
293    return(buf);
294 }
295
296 /*********************************************************************
297  *
298  * Function    :  url_encode
299  *
300  * Description :  Encodes a string so it can be used in a URL
301  *                query string.  Replaces special characters with
302  *                the appropriate %xx codes.
303  *
304  * Parameters  :
305  *          1  :  s = String to encode.  Null-terminated.
306  *
307  * Returns     :  Encoded string, newly allocated on the heap. 
308  *                Caller is responsible for freeing it with free().
309  *                If s is NULL, or on out-of memory, returns NULL.
310  *
311  *********************************************************************/
312 char * url_encode(const char *s)
313 {
314    char * buf;
315
316    if (s == NULL)
317    {
318       return NULL;
319    }
320
321    /* each input char can expand to at most 3 chars */
322    buf = (char *) malloc((strlen(s) * 3) + 1);
323
324    if (buf)
325    {
326       char c;
327       char * p = buf;
328       while( (c = *s++) != '\0')
329       {
330          const char * replace_with = url_code_map[(unsigned char) c];
331          if (replace_with != NULL)
332          {
333             strcpy(p, replace_with);
334             p += strlen(replace_with);
335          }
336          else
337          {
338             *p++ = c;
339          }
340       }
341
342       *p = '\0';
343
344    }
345
346    return(buf);
347 }
348
349
350 /*********************************************************************
351  *
352  * Function    :  xdtoi
353  *
354  * Description :  Converts a single hex digit to an integer.
355  *
356  * Parameters  :
357  *          1  :  d = in the range of ['0'..'9', 'A'..'F', 'a'..'f']
358  *
359  * Returns     :  The integer value, or -1 for non-hex characters.
360  *
361  *********************************************************************/
362 static int xdtoi(const int d)
363 {
364    if ((d >= '0') && (d <= '9'))
365    {
366       return(d - '0');
367    }
368    else if ((d >= 'a') && (d <= 'f')) 
369    {
370       return(d - 'a' + 10);
371    }
372    else if ((d >= 'A') && (d <= 'F'))
373    {
374       return(d - 'A' + 10);
375    }
376    else
377    {
378       return(-1);
379    }
380 }
381
382
383 /*********************************************************************
384  *
385  * Function    :  xtoi
386  *
387  * Description :  Hex string to integer conversion.
388  *
389  * Parameters  :
390  *          1  :  s = a 2 digit hex string (e.g. "1f").  Only the
391  *                    first two characters will be looked at.
392  *
393  * Returns     :  The integer value, or 0 for non-hex strings.
394  *
395  *********************************************************************/
396 static int xtoi(const char *s)
397 {
398    int d1, d2;
399
400    d1 = xdtoi(*s);
401    if(d1 >= 0)
402    {
403       d2 = xdtoi(*(s+1));
404       if(d2 >= 0)
405       {
406          return (d1 << 4) + d2;
407       }
408    }
409
410    return 0;
411 }
412
413
414 /*********************************************************************
415  *
416  * Function    :  url_decode
417  *
418  * Description :  Decodes a URL query string, replacing %xx codes
419  *                with their decoded form.
420  *
421  * Parameters  :
422  *          1  :  s = String to decode.  Null-terminated.
423  *
424  * Returns     :  Decoded string, newly allocated on the heap. 
425  *                Caller is responsible for freeing it with free().
426  *
427  *********************************************************************/
428 char *url_decode(const char * s)
429 {
430    char *buf = malloc(strlen(s) + 1);
431    char *q = buf;
432
433    if (buf)
434    {
435       while (*s)
436       {
437          switch (*s)
438          {
439             case '+':
440                s++;
441                *q++ = ' ';
442                break;
443
444             case '%':
445                if ((*q = xtoi(s + 1)))
446                {
447                   s += 3;
448                   q++;
449                }
450                else
451                {
452                   /* malformed, just use it */
453                   *q++ = *s++;
454                }
455                break;
456
457             default:
458                *q++ = *s++;
459                break;
460          }
461       }
462       *q = '\0';
463    }
464
465    return(buf);
466
467 }
468
469
470 /*
471   Local Variables:
472   tab-width: 3
473   end:
474 */