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