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