1 /*
2  Copyright (C) 2016-2017 Alexander Borisov
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 
18  Author: lex.borisov@gmail.com (Alexander Borisov)
19 */
20 
21 #include "myurl/path.h"
22 #include "myurl/url.h"
23 
myurl_path_create(myurl_t * url)24 myurl_path_t * myurl_path_create(myurl_t* url)
25 {
26     myurl_path_t *path = url->callback_malloc(sizeof(myurl_path_t), url->callback_ctx);
27 
28     if(path)
29         memset(path, 0, sizeof(myurl_path_t));
30 
31     return path;
32 }
33 
myurl_path_init(myurl_t * url,myurl_path_t * path,size_t begin_size)34 mystatus_t myurl_path_init(myurl_t* url, myurl_path_t* path, size_t begin_size)
35 {
36     if(begin_size == 0)
37         return MyURL_STATUS_ERROR;
38 
39     path->length = 0;
40     path->size   = begin_size;
41     path->list   = url->callback_malloc(sizeof(myurl_path_entry_t) * path->size, url->callback_ctx);
42 
43     if(path->list == NULL)
44         return MyURL_STATUS_ERROR_MEMORY_ALLOCATION;
45 
46     memset(path->list, 0, sizeof(myurl_path_entry_t) * path->size);
47 
48     return MyURL_STATUS_OK;
49 }
50 
myurl_path_clean(myurl_t * url,myurl_path_t * path)51 void myurl_path_clean(myurl_t* url, myurl_path_t* path)
52 {
53     for(size_t i = 0; i < path->length; i++) {
54         if(path->list[i].data) {
55             url->callback_free(path->list[i].data, url->callback_ctx);
56         }
57     }
58 
59     path->length = 0;
60 }
61 
myurl_path_entry_destroy(myurl_t * url,myurl_path_entry_t * path,bool destroy_self)62 myurl_path_entry_t * myurl_path_entry_destroy(myurl_t* url, myurl_path_entry_t* path, bool destroy_self)
63 {
64     if(path == NULL)
65         return NULL;
66 
67     if(path->data)
68         url->callback_free(path->data, url->callback_ctx);
69 
70     if(destroy_self) {
71         url->callback_free(path, url->callback_ctx);
72         return NULL;
73     }
74 
75     return path;
76 }
77 
myurl_path_destroy(myurl_t * url,myurl_path_t * path,bool destroy_self)78 myurl_path_t * myurl_path_destroy(myurl_t* url, myurl_path_t* path, bool destroy_self)
79 {
80     if(path == NULL)
81         return NULL;
82 
83     if(path->list) {
84         myurl_path_clean(url, path);
85         url->callback_free(path->list, url->callback_ctx);
86     }
87 
88     if(destroy_self && path) {
89         return url->callback_free(path, url->callback_ctx);
90     }
91 
92     return path;
93 }
94 
myurl_path_append(myurl_t * url,myurl_path_t * path,const char * data,size_t length)95 myurl_path_entry_t * myurl_path_append(myurl_t* url, myurl_path_t* path, const char* data, size_t length)
96 {
97     if(path->length >= path->size) {
98         size_t new_size = path->length + 1024;
99 
100         myurl_path_entry_t *tmp = url->callback_realloc(path->list, sizeof(myurl_path_entry_t) * new_size, url->callback_ctx);
101 
102         if(tmp) {
103             memset(&tmp[path->length], 0, sizeof(myurl_path_entry_t) * (new_size - path->length));
104 
105             path->list = tmp;
106             path->size = new_size;
107         }
108         else
109             return NULL;
110     }
111 
112     myurl_path_entry_t *entry = &path->list[ path->length ];
113     path->length++;
114 
115     if(length) {
116         entry->data = url->callback_malloc(sizeof(char) * length, url->callback_ctx);
117 
118         if(entry->data == NULL)
119             return NULL;
120 
121         memcpy(entry->data, data, sizeof(char) * length);
122     }
123     else
124         entry->data = NULL;
125 
126     entry->length = length;
127     return entry;
128 }
129 
myurl_path_push(myurl_t * url,myurl_path_t * path,char * data,size_t length)130 myurl_path_entry_t * myurl_path_push(myurl_t* url, myurl_path_t* path, char* data, size_t length)
131 {
132     if(path->length >= path->size) {
133         size_t new_size = path->length + 32;
134 
135         myurl_path_entry_t *tmp = url->callback_realloc(path->list, sizeof(myurl_path_entry_t) * new_size, url->callback_ctx);
136 
137         if(tmp) {
138             memset(&tmp[path->length], 0, sizeof(myurl_path_entry_t) * (new_size - path->length));
139 
140             path->list = tmp;
141             path->size = new_size;
142         }
143         else
144             return NULL;
145     }
146 
147     myurl_path_entry_t *entry = &path->list[ path->length ];
148     path->length++;
149 
150     entry->data = data;
151     entry->length = length;
152 
153     return entry;
154 }
155 
myurl_path_push_to_index(myurl_t * url,myurl_path_t * path,size_t index,char * data,size_t length)156 myurl_path_entry_t * myurl_path_push_to_index(myurl_t* url, myurl_path_t* path, size_t index, char* data, size_t length)
157 {
158     if(index >= path->size) {
159         myurl_path_entry_t *tmp = url->callback_realloc(path->list, sizeof(myurl_path_entry_t) * index, url->callback_ctx);
160 
161         if(tmp) {
162             memset(&tmp[path->length], 0, sizeof(myurl_path_entry_t) * (index - path->length));
163 
164             path->list = tmp;
165             path->size = index;
166         }
167         else
168             return NULL;
169     }
170 
171     if(index > path->length)
172         path->length = index;
173 
174     if(path->list[ index ].data)
175         url->callback_free(path->list[ index ].data, url->callback_ctx);
176 
177     path->list[ index ].data = data;
178     path->list[ index ].length = length;
179 
180     return &path->list[ index ];
181 }
182 
myurl_path_current(myurl_path_t * path)183 myurl_path_entry_t * myurl_path_current(myurl_path_t* path)
184 {
185     if(path->length == 0)
186         return NULL;
187 
188     return &path->list[ (path->length - 1) ];
189 }
190 
myurl_path_pop(myurl_path_t * path)191 myurl_path_entry_t * myurl_path_pop(myurl_path_t* path)
192 {
193     if(path->length == 0)
194         return NULL;
195 
196     path->length--;
197 
198     return &path->list[path->length];
199 }
200 
myurl_path_remove_by_index(myurl_t * url,myurl_path_t * path,size_t index)201 void myurl_path_remove_by_index(myurl_t* url, myurl_path_t* path, size_t index)
202 {
203     if(path->length == 0 || index >= path->length || path->list == NULL)
204         return;
205 
206     myurl_path_entry_destroy(url, &path->list[index], false);
207 
208     if((path->length - 1) > index) {
209         memmove(&path->list[index], &path->list[index + 1], sizeof(myurl_path_entry_t) * (path->length - (path->length - index)));
210     }
211 
212     path->length--;
213 }
214 
myurl_path_copy(myurl_t * url,myurl_path_t * path_from,myurl_path_t * path_to)215 mystatus_t myurl_path_copy(myurl_t* url, myurl_path_t* path_from, myurl_path_t* path_to)
216 {
217     if(path_from->length >= path_to->size) {
218         size_t new_size = path_from->length + 2;
219 
220         myurl_path_entry_t* tmp = url->callback_realloc(path_to->list, sizeof(myurl_path_entry_t) * new_size, url->callback_ctx);
221 
222         if(tmp) {
223             memset(&tmp[path_to->length], 0, sizeof(myurl_path_entry_t) * (new_size - path_to->length));
224 
225             path_to->list = tmp;
226             path_to->size = new_size;
227         }
228         else
229             return MyURL_STATUS_ERROR_MEMORY_ALLOCATION;
230     }
231 
232     myurl_path_entry_t *list_to   = path_to->list;
233     myurl_path_entry_t *list_from = path_from->list;
234 
235     if(path_to->length > path_from->length)
236     {
237         while(path_to->length > path_from->length) {
238             path_to->length--;
239 
240             if(list_to[path_to->length].data)
241                 url->callback_free( list_to[path_to->length].data, url->callback_ctx );
242         }
243     }
244 
245     path_to->length = path_from->length;
246 
247     for(size_t i = 0; i < path_from->length; i++)
248     {
249         if(list_to[i].data)
250         {
251             if(list_to[i].length < list_from[i].length)
252                 list_to[i].data = url->callback_realloc(list_to[i].data, (list_from[i].length + 1), url->callback_ctx);
253         }
254         else {
255             list_to[i].data = url->callback_malloc((list_from[i].length + 1), url->callback_ctx);
256         }
257 
258         if(list_to[i].data == NULL)
259             return MyURL_STATUS_ERROR_MEMORY_ALLOCATION;
260 
261         list_to[i].length = list_from[i].length;
262         list_to[i].data[ list_to[i].length ] = '\0';
263 
264         if(list_from[i].length) {
265             memcpy(list_to[i].data, list_from[i].data, sizeof(char) * list_from[i].length);
266         }
267     }
268 
269     return MyURL_STATUS_OK;
270 }
271 
myurl_path_shorten(myurl_path_t * path,myurl_scheme_id_t scheme_id)272 void myurl_path_shorten(myurl_path_t* path, myurl_scheme_id_t scheme_id)
273 {
274     if(path->length == 0)
275         return;
276 
277     if(scheme_id == MyURL_SCHEME_ID_FILE) {
278         if(path->length == 1 && myurl_utils_is_windows_drive_letter(path->list[0].data, 0, path->list[0].length))
279             return;
280     }
281 
282     myurl_path_pop(path);
283 }
284 
285 
286 
287