• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Collabora, Ltd.
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  * Copyright (C) 1997-2000 The GLib Team
5  * Copyright (C) 2006-2007 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include "config.h"
24 #include "guriescape.h"
25 
26 #include <string.h>
27 
28 #if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0)
29 
30 /* is_valid, gunichar_ok and g_string_append_uri_escaped were copied for glib/gstring.c
31  * in the glib package.
32  *
33  * Original copyright:
34  *   Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
35  *
36  *   Modified by the GLib Team and others 1997-2000.  See the AUTHORS
37  *   file for a list of people on the GLib Team.  See the ChangeLog
38  *   files for a list of changes.  These files are distributed with
39  *   GLib at ftp://ftp.gtk.org/pub/gtk/.
40  *
41  * Please don't change the indentation so it's easier to update these functions
42  * if they are changed in glib.
43  */
44 static gboolean
is_valid(char c,const char * reserved_chars_allowed)45 is_valid (char c, const char *reserved_chars_allowed)
46 {
47   if (g_ascii_isalnum (c) ||
48       c == '-' ||
49       c == '.' ||
50       c == '_' ||
51       c == '~')
52     return TRUE;
53 
54   if (reserved_chars_allowed &&
55       strchr (reserved_chars_allowed, c) != NULL)
56     return TRUE;
57 
58   return FALSE;
59 }
60 
61 static gboolean
gunichar_ok(gunichar c)62 gunichar_ok (gunichar c)
63 {
64   return
65     (c != (gunichar) -2) &&
66     (c != (gunichar) -1);
67 }
68 
69 static GString *
_webcore_g_string_append_uri_escaped(GString * string,const char * unescaped,const char * reserved_chars_allowed,gboolean allow_utf8)70 _webcore_g_string_append_uri_escaped (GString *string,
71                              const char *unescaped,
72                              const char *reserved_chars_allowed,
73                              gboolean allow_utf8)
74 {
75   unsigned char c;
76   const char *end;
77   static const gchar hex[16] = "0123456789ABCDEF";
78 
79   g_return_val_if_fail (string != NULL, NULL);
80   g_return_val_if_fail (unescaped != NULL, NULL);
81 
82   end = unescaped + strlen (unescaped);
83 
84   while ((c = *unescaped) != 0)
85     {
86       if (c >= 0x80 && allow_utf8 &&
87           gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped)))
88         {
89           int len = g_utf8_skip [c];
90           g_string_append_len (string, unescaped, len);
91           unescaped += len;
92         }
93       else if (is_valid (c, reserved_chars_allowed))
94         {
95           g_string_append_c (string, c);
96           unescaped++;
97         }
98       else
99         {
100           g_string_append_c (string, '%');
101           g_string_append_c (string, hex[((guchar)c) >> 4]);
102           g_string_append_c (string, hex[((guchar)c) & 0xf]);
103           unescaped++;
104         }
105     }
106 
107   return string;
108 }
109 
110 /* g_uri_escape_string, unescape_character, g_uri_unescape_segment and
111  * g_uri_unescape_string were copied for glib/gurifuncs.c in the glib package
112  * and prefixed with _webcore (if necessary) to avoid exporting a symbol with
113  * the "g_" prefix.
114  *
115  * Original copyright:
116  *   Copyright (C) 2006-2007 Red Hat, Inc.
117  *   Author: Alexander Larsson <alexl@redhat.com>
118  *
119  * Please don't change the indentation so it's easier to update this function
120  * if it's changed in glib.
121  */
122 char *
_webcore_g_uri_escape_string(const char * unescaped,const char * reserved_chars_allowed,gboolean allow_utf8)123 _webcore_g_uri_escape_string (const char *unescaped,
124                      const char  *reserved_chars_allowed,
125                      gboolean     allow_utf8)
126 {
127   GString *s;
128 
129   g_return_val_if_fail (unescaped != NULL, NULL);
130 
131   s = g_string_sized_new (strlen (unescaped) + 10);
132 
133   _webcore_g_string_append_uri_escaped (s, unescaped, reserved_chars_allowed, allow_utf8);
134 
135   return g_string_free (s, FALSE);
136 }
137 
138 static int
unescape_character(const char * scanner)139 unescape_character (const char *scanner)
140 {
141   int first_digit;
142   int second_digit;
143 
144   first_digit = g_ascii_xdigit_value (*scanner++);
145   if (first_digit < 0)
146     return -1;
147 
148   second_digit = g_ascii_xdigit_value (*scanner++);
149   if (second_digit < 0)
150     return -1;
151 
152   return (first_digit << 4) | second_digit;
153 }
154 
155 
156 
157 static char *
_webcore_g_uri_unescape_segment(const char * escaped_string,const char * escaped_string_end,const char * illegal_characters)158 _webcore_g_uri_unescape_segment (const char *escaped_string,
159       const char *escaped_string_end,
160       const char *illegal_characters)
161 {
162   const char *in;
163   char *out, *result;
164   gint character;
165 
166   if (escaped_string == NULL)
167     return NULL;
168 
169   if (escaped_string_end == NULL)
170     escaped_string_end = escaped_string + strlen (escaped_string);
171 
172   result = g_malloc (escaped_string_end - escaped_string + 1);
173 
174   out = result;
175   for (in = escaped_string; in < escaped_string_end; in++)
176     {
177       character = *in;
178 
179       if (*in == '%')
180   {
181     in++;
182 
183     if (escaped_string_end - in < 2)
184       {
185         /* Invalid escaped char (to short) */
186         g_free (result);
187         return NULL;
188       }
189 
190     character = unescape_character (in);
191 
192     /* Check for an illegal character. We consider '\0' illegal here. */
193     if (character <= 0 ||
194         (illegal_characters != NULL &&
195          strchr (illegal_characters, (char)character) != NULL))
196       {
197         g_free (result);
198         return NULL;
199       }
200 
201     in++; /* The other char will be eaten in the loop header */
202   }
203       *out++ = (char)character;
204     }
205 
206   *out = '\0';
207 
208   return result;
209 }
210 
211 
212 char *
_webcore_g_uri_unescape_string(const char * escaped_string,const char * illegal_characters)213 _webcore_g_uri_unescape_string (const char *escaped_string,
214            const char *illegal_characters)
215 {
216   return _webcore_g_uri_unescape_segment (escaped_string, NULL, illegal_characters);
217 }
218 
219 #endif /* #if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) */
220