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