updated version and copyright notice
[geeqie.git] / src / uri_utils.c
1 /*
2  * Geeqie
3  * Copyright (C) 2008 - 2012 The Geeqie Team
4  *
5  * Authors: John Ellis, Vladimir Nadvornik, Laurent Monin
6  *
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #include "main.h"
14 #include "uri_utils.h"
15
16 #include "filedata.h"
17 #include "ui_fileops.h"
18
19 /*
20  *-----------------------------------------------------------------------------
21  * drag and drop uri utils
22  *-----------------------------------------------------------------------------
23  */
24
25 /* the following characters are allowed to be unencoded for pathnames:
26  *     $ & + , / : = @
27  */
28 static gint escape_char_list[] = {
29         1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*   0 */
30         1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*  10 */
31         1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /*  20 */
32 /*           spc !  "  #  $  %  &  '           */
33         1, 1, 0, 0, 1, 1, 0, 1, 0, 0,   /*  30 */
34 /*      (  )  *  +  ,  -  .  /  0  1           */
35         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /*  40 */
36 /*      2  3  4  5  6  7  8  9  :  ;           */
37         0, 0, 0, 0, 0, 0, 0, 0, 0, 1,   /*  50 */
38 /*      <  =  >  ?  @  A  B  C  D  E           */
39         1, 0, 1, 1, 0, 0, 0, 0, 0, 0,   /*  60 */
40         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /*  70 */
41         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /*  80 */
42 /*      Z  [  \  ]  ^  _  `  a  b  c           */
43         0, 1, 1, 1, 1, 0, 1, 0, 0, 0,   /*  90 */
44         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 100 */
45         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 110 */
46 /*      x  y  z  {  |  }  ~ del                */
47         0, 0, 0, 1, 1, 1, 0, 0          /* 120, 127 is end */
48 };
49
50 static gchar *hex_char = "0123456789ABCDEF";
51
52 static gboolean escape_test(guchar c)
53 {
54         if (c < 32 || c > 127) return TRUE;
55         return (escape_char_list[c] != 0);
56 }
57
58 static const gchar *escape_code(guchar c)
59 {
60         static gchar text[4];
61
62         text[0] = '%';
63         text[1] = hex_char[c>>4];
64         text[2] = hex_char[c%16];
65         text[3] = '\0';
66
67         return text;
68 }
69
70 gchar *uri_text_escape(const gchar *text)
71 {
72         GString *string;
73         gchar *result;
74         const gchar *p;
75
76         if (!text) return NULL;
77
78         string = g_string_new("");
79
80         p = text;
81         while (*p != '\0')
82                 {
83                 if (escape_test(*p))
84                         {
85                         g_string_append(string, escape_code(*p));
86                         }
87                 else
88                         {
89                         g_string_append_c(string, *p);
90                         }
91                 p++;
92                 }
93
94         result = string->str;
95         g_string_free(string, FALSE);
96
97         /* dropped filenames are expected to be utf-8 compatible */
98         if (!g_utf8_validate(result, -1, NULL))
99                 {
100                 gchar *tmp;
101
102                 tmp = g_locale_to_utf8(result, -1, NULL, NULL, NULL);
103                 if (tmp)
104                         {
105                         g_free(result);
106                         result = tmp;
107                         }
108                 }
109
110         return result;
111 }
112
113 /* this operates on the passed string, decoding escaped characters */
114 void uri_text_decode(gchar *text)
115 {
116         if (strchr(text, '%'))
117                 {
118                 gchar *w;
119                 gchar *r;
120
121                 w = r = text;
122
123                 while (*r != '\0')
124                         {
125                         if (*r == '%' && *(r + 1) != '\0' && *(r + 2) != '\0')
126                                 {
127                                 gchar t[3];
128                                 gint n;
129
130                                 r++;
131                                 t[0] = *r;
132                                 r++;
133                                 t[1] = *r;
134                                 t[2] = '\0';
135                                 n = (gint)strtol(t, NULL, 16);
136                                 if (n > 0 && n < 256)
137                                         {
138                                         *w = (gchar)n;
139                                         }
140                                 else
141                                         {
142                                         /* invalid number, rewind and ignore this escape */
143                                         r -= 2;
144                                         *w = *r;
145                                         }
146                                 }
147                         else if (w != r)
148                                 {
149                                 *w = *r;
150                                 }
151                         r++;
152                         w++;
153                         }
154                 if (*w != '\0') *w = '\0';
155                 }
156 }
157
158 static void uri_list_parse_encoded_chars(GList *list)
159 {
160         GList *work = list;
161
162         while (work)
163                 {
164                 gchar *text = work->data;
165
166                 uri_text_decode(text);
167
168                 work = work->next;
169                 }
170 }
171
172 GList *uri_list_from_text(gchar *data, gboolean files_only)
173 {
174         GList *list = NULL;
175         gint b, e;
176
177         b = e = 0;
178
179         while (data[b] != '\0')
180                 {
181                 while (data[e] != '\r' && data[e] != '\n' && data[e] != '\0') e++;
182                 if (strncmp(data + b, "file:", 5) == 0)
183                         {
184                         gchar *path;
185                         b += 5;
186                         while (data[b] == '/' && data[b+1] == '/') b++;
187                         path = g_strndup(data + b, e - b);
188                         list = g_list_append(list, path_to_utf8(path));
189                         g_free(path);
190                         }
191                 else if (!files_only && strncmp(data + b, "http:", 5) == 0)
192                         {
193                         list = g_list_append(list, g_strndup(data + b, e - b));
194                         }
195                 else if (!files_only && strncmp(data + b, "ftp:", 3) == 0)
196                         {
197                         list = g_list_append(list, g_strndup(data + b, e - b));
198                         }
199                 while (data[e] == '\r' || data[e] == '\n') e++;
200                 b = e;
201                 }
202
203         uri_list_parse_encoded_chars(list);
204
205         return list;
206 }
207
208 GList *uri_filelist_from_text(gchar *data, gboolean files_only)
209 {
210         GList *path_list = uri_list_from_text(data, files_only);
211         GList *filelist = filelist_from_path_list(path_list);
212         string_list_free(path_list);
213         return filelist;
214 }
215
216 gchar *uri_text_from_list(GList *list, gint *len, gboolean plain_text)
217 {
218         gchar *uri_text = NULL;
219         GString *string;
220         GList *work;
221
222         if (!list)
223                 {
224                 if (len) *len = 0;
225                 return NULL;
226                 }
227
228         string = g_string_new("");
229
230         work = list;
231         while (work)
232                 {
233                 const gchar *name8;     /* dnd filenames are in utf-8 */
234
235                 name8 = work->data;
236
237                 if (!plain_text)
238                         {
239                         gchar *escaped;
240
241                         escaped = uri_text_escape(name8);
242                         g_string_append(string, "file:");
243                         g_string_append(string, escaped);
244                         g_free(escaped);
245
246                         g_string_append(string, "\r\n");
247                         }
248                 else
249                         {
250                         g_string_append(string, name8);
251                         if (work->next) g_string_append(string, "\n");
252                         }
253
254                 work = work->next;
255                 }
256
257         uri_text = string->str;
258         if (len) *len = string->len;
259         g_string_free(string, FALSE);
260
261         return uri_text;
262 }
263
264 gchar *uri_text_from_filelist(GList *list, gint *len, gboolean plain_text)
265 {
266         GList *path_list = filelist_to_path_list(list);
267         gchar *ret = uri_text_from_list(path_list, len, plain_text);
268         string_list_free(path_list);
269         return ret;
270 }
271 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */