Git init
[external/libiri.git] / libiri / parse.c
1 /*
2  * libiri: An IRI/URI/URL parsing library
3  * @(#) $Id$
4  */
5
6 /*
7  * Copyright (c) 2005, 2008 Mo McRoberts.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. The names of the author(s) of this software may not be used to endorse
18  * or promote products derived from this software without specific prior
19  * written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
22  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
23  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24  * AUTHORS OF THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34
35 The following code was added by Samsung Electronics.
36
37 --- a/libiri/parse.c
38 +++ b/libiri/parse.c
39 @@ -59,6 +59,7 @@ iri__hexnibble(char c)
40         {
41                 return c - 'a' + 10;
42         }
43 +    return 0;
44  }
45  
46  static inline const char *
47 @@ -130,6 +131,7 @@ iri__allocbuf(const char *src, size_t *len)
48                 *len = (src - c) + 1 + sc + ((sc + 1) * (sizeof(char *) + 7));
49                 *len += (7 * 11);
50         }
51 +    *len = 9999; // FIXME: DIRTY HACK THAT USUALLY WORKS... UNTIL IRI IS NOT TO
52         return (char *) calloc(1, *len);
53  }
54
55
56
57 License of the above code is Apache License
58
59
60     Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
61
62                                  Apache License
63                            Version 2.0, January 2004
64                         http://www.apache.org/licenses/
65
66    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
67
68    1. Definitions.
69
70       "License" shall mean the terms and conditions for use, reproduction,
71       and distribution as defined by Sections 1 through 9 of this document.
72
73       "Licensor" shall mean the copyright owner or entity authorized by
74       the copyright owner that is granting the License.
75
76       "Legal Entity" shall mean the union of the acting entity and all
77       other entities that control, are controlled by, or are under common
78       control with that entity. For the purposes of this definition,
79       "control" means (i) the power, direct or indirect, to cause the
80       direction or management of such entity, whether by contract or
81       otherwise, or (ii) ownership of fifty percent (50%) or more of the
82       outstanding shares, or (iii) beneficial ownership of such entity.
83
84       "You" (or "Your") shall mean an individual or Legal Entity
85       exercising permissions granted by this License.
86
87       "Source" form shall mean the preferred form for making modifications,
88       including but not limited to software source code, documentation
89       source, and configuration files.
90
91       "Object" form shall mean any form resulting from mechanical
92       transformation or translation of a Source form, including but
93       not limited to compiled object code, generated documentation,
94       and conversions to other media types.
95
96       "Work" shall mean the work of authorship, whether in Source or
97       Object form, made available under the License, as indicated by a
98       copyright notice that is included in or attached to the work
99       (an example is provided in the Appendix below).
100
101       "Derivative Works" shall mean any work, whether in Source or Object
102       form, that is based on (or derived from) the Work and for which the
103       editorial revisions, annotations, elaborations, or other modifications
104       represent, as a whole, an original work of authorship. For the purposes
105       of this License, Derivative Works shall not include works that remain
106       separable from, or merely link (or bind by name) to the interfaces of,
107       the Work and Derivative Works thereof.
108
109       "Contribution" shall mean any work of authorship, including
110       the original version of the Work and any modifications or additions
111       to that Work or Derivative Works thereof, that is intentionally
112       submitted to Licensor for inclusion in the Work by the copyright owner
113       or by an individual or Legal Entity authorized to submit on behalf of
114       the copyright owner. For the purposes of this definition, "submitted"
115       means any form of electronic, verbal, or written communication sent
116       to the Licensor or its representatives, including but not limited to
117       communication on electronic mailing lists, source code control systems,
118       and issue tracking systems that are managed by, or on behalf of, the
119       Licensor for the purpose of discussing and improving the Work, but
120       excluding communication that is conspicuously marked or otherwise
121       designated in writing by the copyright owner as "Not a Contribution."
122
123       "Contributor" shall mean Licensor and any individual or Legal Entity
124       on behalf of whom a Contribution has been received by Licensor and
125       subsequently incorporated within the Work.
126
127    2. Grant of Copyright License. Subject to the terms and conditions of
128       this License, each Contributor hereby grants to You a perpetual,
129       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
130       copyright license to reproduce, prepare Derivative Works of,
131       publicly display, publicly perform, sublicense, and distribute the
132       Work and such Derivative Works in Source or Object form.
133
134    3. Grant of Patent License. Subject to the terms and conditions of
135       this License, each Contributor hereby grants to You a perpetual,
136       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
137       (except as stated in this section) patent license to make, have made,
138       use, offer to sell, sell, import, and otherwise transfer the Work,
139       where such license applies only to those patent claims licensable
140       by such Contributor that are necessarily infringed by their
141       Contribution(s) alone or by combination of their Contribution(s)
142       with the Work to which such Contribution(s) was submitted. If You
143       institute patent litigation against any entity (including a
144       cross-claim or counterclaim in a lawsuit) alleging that the Work
145       or a Contribution incorporated within the Work constitutes direct
146       or contributory patent infringement, then any patent licenses
147       granted to You under this License for that Work shall terminate
148       as of the date such litigation is filed.
149
150    4. Redistribution. You may reproduce and distribute copies of the
151       Work or Derivative Works thereof in any medium, with or without
152       modifications, and in Source or Object form, provided that You
153       meet the following conditions:
154
155       (a) You must give any other recipients of the Work or
156           Derivative Works a copy of this License; and
157
158       (b) You must cause any modified files to carry prominent notices
159           stating that You changed the files; and
160
161       (c) You must retain, in the Source form of any Derivative Works
162           that You distribute, all copyright, patent, trademark, and
163           attribution notices from the Source form of the Work,
164           excluding those notices that do not pertain to any part of
165           the Derivative Works; and
166
167       (d) If the Work includes a "NOTICE" text file as part of its
168           distribution, then any Derivative Works that You distribute must
169           include a readable copy of the attribution notices contained
170           within such NOTICE file, excluding those notices that do not
171           pertain to any part of the Derivative Works, in at least one
172           of the following places: within a NOTICE text file distributed
173           as part of the Derivative Works; within the Source form or
174           documentation, if provided along with the Derivative Works; or,
175           within a display generated by the Derivative Works, if and
176           wherever such third-party notices normally appear. The contents
177           of the NOTICE file are for informational purposes only and
178           do not modify the License. You may add Your own attribution
179           notices within Derivative Works that You distribute, alongside
180           or as an addendum to the NOTICE text from the Work, provided
181           that such additional attribution notices cannot be construed
182           as modifying the License.
183
184       You may add Your own copyright statement to Your modifications and
185       may provide additional or different license terms and conditions
186       for use, reproduction, or distribution of Your modifications, or
187       for any such Derivative Works as a whole, provided Your use,
188       reproduction, and distribution of the Work otherwise complies with
189       the conditions stated in this License.
190
191    5. Submission of Contributions. Unless You explicitly state otherwise,
192       any Contribution intentionally submitted for inclusion in the Work
193       by You to the Licensor shall be under the terms and conditions of
194       this License, without any additional terms or conditions.
195       Notwithstanding the above, nothing herein shall supersede or modify
196       the terms of any separate license agreement you may have executed
197       with Licensor regarding such Contributions.
198
199    6. Trademarks. This License does not grant permission to use the trade
200       names, trademarks, service marks, or product names of the Licensor,
201       except as required for reasonable and customary use in describing the
202       origin of the Work and reproducing the content of the NOTICE file.
203
204    7. Disclaimer of Warranty. Unless required by applicable law or
205       agreed to in writing, Licensor provides the Work (and each
206       Contributor provides its Contributions) on an "AS IS" BASIS,
207       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
208       implied, including, without limitation, any warranties or conditions
209       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
210       PARTICULAR PURPOSE. You are solely responsible for determining the
211       appropriateness of using or redistributing the Work and assume any
212       risks associated with Your exercise of permissions under this License.
213
214    8. Limitation of Liability. In no event and under no legal theory,
215       whether in tort (including negligence), contract, or otherwise,
216       unless required by applicable law (such as deliberate and grossly
217       negligent acts) or agreed to in writing, shall any Contributor be
218       liable to You for damages, including any direct, indirect, special,
219       incidental, or consequential damages of any character arising as a
220       result of this License or out of the use or inability to use the
221       Work (including but not limited to damages for loss of goodwill,
222       work stoppage, computer failure or malfunction, or any and all
223       other commercial damages or losses), even if such Contributor
224       has been advised of the possibility of such damages.
225
226    9. Accepting Warranty or Additional Liability. While redistributing
227       the Work or Derivative Works thereof, You may choose to offer,
228       and charge a fee for, acceptance of support, warranty, indemnity,
229       or other liability obligations and/or rights consistent with this
230       License. However, in accepting such obligations, You may act only
231       on Your own behalf and on Your sole responsibility, not on behalf
232       of any other Contributor, and only if You agree to indemnify,
233       defend, and hold each Contributor harmless for any liability
234       incurred by, or claims asserted against, such Contributor by reason
235       of your accepting any such warranty or additional liability.
236
237    END OF TERMS AND CONDITIONS
238
239    APPENDIX: How to apply the Apache License to your work.
240
241       To apply the Apache License to your work, attach the following
242       boilerplate notice, with the fields enclosed by brackets "[]"
243       replaced with your own identifying information. (Don't include
244       the brackets!)  The text should be enclosed in the appropriate
245       comment syntax for the file format. We also recommend that a
246       file or class name and description of purpose be included on the
247       same "printed page" as the copyright notice for easier
248       identification within third-party archives.
249
250    Copyright [yyyy] [name of copyright owner]
251
252    Licensed under the Apache License, Version 2.0 (the "License");
253    you may not use this file except in compliance with the License.
254    You may obtain a copy of the License at
255
256        http://www.apache.org/licenses/LICENSE-2.0
257
258    Unless required by applicable law or agreed to in writing, software
259    distributed under the License is distributed on an "AS IS" BASIS,
260    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
261    See the License for the specific language governing permissions and
262    limitations under the License.
263
264
265 */
266
267 #ifdef HAVE_CONFIG_H
268 # include "config.h"
269 #endif
270
271 #include <stdio.h>
272
273 #include "p_libiri.h"
274
275 #undef ALIGNMENT
276 #define ALIGNMENT 8
277 #undef ALIGN
278 #define _ALIGN(x) ((((x)+(ALIGNMENT-1))&~(ALIGNMENT-1)))
279 #define ALIGN(x) (char *) _ALIGN((size_t) x)
280
281 static inline int
282 iri__hexnibble(char c)
283 {
284         if(c >= '0' && c <= '9')
285         {
286                 return c - '0';
287         }
288         if(c >= 'A' && c <= 'F')
289         {
290                 return c - 'A' + 10;
291         }
292         if(c >= 'a' && c <= 'f')
293         {
294                 return c - 'a' + 10;
295         }
296     return 0;
297 }
298
299 static inline const char *
300 iri__copychar(char **dest, const char *src)
301 {
302         **dest = *src;
303         (*dest)++;
304         src++;
305         return src;
306 }
307
308 /* TODO: Punycode decoding for the host part */
309 static inline const char *
310 iri__copychar_decode(char **dest, const char *src, int convert_space)
311 {
312         unsigned char *p = (unsigned char *) (*dest);
313         
314         if(1 == convert_space && '+' == *src)
315         {
316                 **dest = ' ';
317         }
318         else if('%' == *src)
319         {
320                 if(0 == isxdigit(src[1]) || 0 == isxdigit(src[2]))
321                 {
322                         /* TODO: Deal with %u<nnnn> non-standard encoding - be liberal in
323                          * what you accept, etc.
324                          */
325                         **dest = '%';
326                 }
327                 else
328                 {
329                         *p = (iri__hexnibble(src[1]) << 4) | iri__hexnibble(src[2]);
330                         src += 2;
331                 }
332         }
333         else
334         {
335                 **dest = *src;
336         }
337         src++;
338         (*dest)++;
339         return src;
340 }
341
342 static inline char *
343 iri__allocbuf(const char *src, size_t *len)
344 {
345         size_t sc;
346         const char *p, *c;
347         
348         /* Calculate the size of the buffer required to hold a decoded version of
349          * src, including enough breathing space for null bytes.
350          */
351         /* XXX: This is way too much; we need to actually count it */
352         *len = (strlen(src) * 4) + 16;
353         /* Determine how much space we need for the scheme list */
354         if(NULL != (c = strchr(src, ':')))
355         {
356                 sc = 1;
357                 for(p = src; p < c; p++)
358                 {
359                         if(*p == '+')
360                         {
361                                 sc++;
362                         }
363                 }
364                 /* Ensure we can align each element on an 8-byte boundary */
365                 *len = (src - c) + 1 + sc + ((sc + 1) * (sizeof(char *) + 7));
366                 *len += (7 * 11);
367         }
368     *len = 9999; // FIXME: DIRTY HACK THAT USUALLY WORKS... UNTIL IRI IS NOT TOO LONG
369         return (char *) calloc(1, *len);
370 }
371
372 iri_t *
373 iri_parse(const char *src)
374 {
375         iri_t *p;
376         char *bufstart, *endp, *bufp, **sl;
377         const char *at, *colon, *slash, *t;
378         size_t buflen, sc, cp;
379         
380         if(NULL == (p = (iri_t *) calloc(1, sizeof(iri_t))))
381         {
382                 return NULL;
383         }
384         if(NULL == (bufstart = iri__allocbuf(src, &buflen)))
385         {
386                 free(p);
387                 return NULL;
388         }
389         p->base = bufp = bufstart;
390         p->nbytes = buflen;
391         at = strchr(src, '@');
392         slash = strchr(src, '/');
393         colon = strchr(src, ':');
394         if(slash && colon && slash < colon)
395         {
396                 /* We can disregard the colon if a slash appears before it */
397                 colon = NULL;
398         }
399         if(colon && !at)
400         {
401                 /* Definitely a scheme */
402                 bufp = ALIGN(bufp);
403                 p->iri.scheme = bufp;
404                 while(*src && *src != ':')
405                 {
406                         src = iri__copychar_decode(&bufp, src, 0);
407                 }
408                 *bufp = 0;
409                 bufp++;
410                 src++;
411                 /* src[0-1] SHOULD == '/' */
412                 if(src[0] == '/') src++;
413                 if(src[0] == '/') src++;
414         }
415         else if(colon && at && colon < at)
416         {
417                 fprintf(stderr, "Colon occurs before at\n");
418                 /* This could be scheme://user[;auth][:password]@host or [scheme:]user[;auth][:password]@host (urgh) */
419                 if(colon[1] == '/' && colon[2] == '/' && colon[3] != '/')
420                 {
421                         bufp = ALIGN(bufp);
422                         p->iri.scheme = bufp;
423                         while(*src && *src != ':')
424                         {
425                                 src = iri__copychar_decode(&bufp, src, 0);
426                         }
427                         *bufp = 0;
428                         bufp++;
429                         src++;
430                         /* src[0-1] SHOULD == '/' */
431                         for(; *src == '/'; src++);
432                         bufp = ALIGN(bufp);
433                         p->iri.user = bufp;
434                         fprintf(stderr, "Found user\n");
435                 }
436                 else
437                 {
438                         fprintf(stderr, "Matched scheme\n");
439                         bufp = ALIGN(bufp);
440                         p->iri.scheme = bufp;
441                 }
442                 while(*src && *src != ':' && *src != '@' && *src != ';')
443                 {
444                         src = iri__copychar_decode(&bufp, src, 0);
445                 }
446                 *bufp = 0;
447                 bufp++;
448                 if(*src == ';')
449                 {
450                         /* Following authentication parameters */
451                         src++;
452                         bufp = ALIGN(bufp);
453                         p->iri.auth = bufp;
454                         while(*src && *src != ':' && *src != '@')
455                         {
456                                 /* Don't decode, so it can be extracted properly */
457                                 src = iri__copychar(&bufp, src);
458                         }
459                         *bufp = 0;
460                         bufp++;
461                 }
462                 if(*src == ':')
463                 {
464                         /* Following password data */
465                         src++;
466                         bufp = ALIGN(bufp);
467                         p->iri.password = bufp;
468                         while(*src && *src != ':' && *src != '@')
469                         {
470                                 src = iri__copychar_decode(&bufp, src, 0);
471                         }
472                         *bufp = 0;
473                         bufp++;
474                         if(*src == ':')
475                         {
476                                 src++;
477                                 /* It was actually scheme:user:auth@host */
478                                 p->iri.user = p->iri.auth;
479                                 bufp = ALIGN(bufp);
480                                 p->iri.password = bufp;
481                                 while(*src && *src != '@')
482                                 {
483                                         src = iri__copychar_decode(&bufp, src, 0);
484                                 }
485                                 *bufp = 0;
486                                 bufp++;
487                         }
488                 }
489                 if(!*src)
490                 {
491                         /* No host part */
492                         return p;
493                 }
494                 if(*src == '@')
495                 {
496                         src++;
497                 }
498         }
499         else if(at)
500         {
501                 /* user[;auth]@host[/path...] */
502                 bufp = ALIGN(bufp);
503                 p->iri.user = bufp;
504                 while(*src != '@' && *src != ';')
505                 {
506                         src = iri__copychar_decode(&bufp, src, 0);
507                 }
508                 *bufp = 0;
509                 bufp++;
510                 if(*src == ';')
511                 {
512                         src++;
513                         bufp = ALIGN(bufp);
514                         p->iri.auth = bufp;
515                         while(*src && *src != '@')
516                         {
517                                 /* Don't decode, so it can be extracted properly */
518                                 src = iri__copychar(&bufp, src);
519                         }
520                         *bufp = 0;
521                         bufp++;
522                 }
523                 else
524                 {
525                         src++;
526                 }
527         }
528         if(NULL != p->iri.scheme)
529         {
530                 sc = 1;
531                 for(t = p->iri.scheme; *t; t++)
532                 {
533                         if('+' == *t)
534                         {
535                                 sc++;
536                         }
537                 }
538                 bufp = ALIGN(bufp);
539                 sl = (char **) (void *) bufp;
540                 bufp += (sc + 1) * sizeof(char *);
541                 sc = 0;
542                 cp = 0;
543                 bufp = ALIGN(bufp);
544                 sl[0] = bufp;
545                 for(t = p->iri.scheme; *t; t++)
546                 {
547                         if('+' == *t)
548                         {
549                                 if(sl[sc][0])
550                                 {
551                                         sl[sc][cp] = 0;
552                                         bufp++;
553                                         sc++;
554                                         bufp = ALIGN(bufp);
555                                         sl[sc] = bufp;
556                                         cp = 0;
557                                 }
558                         }
559                         else
560                         {
561                                 sl[sc][cp] = *t;
562                                 bufp++;
563                                 cp++;
564                         }
565                 }
566                 if(sl[sc][0])
567                 {
568                         sl[sc][cp] = 0;
569                         sc++;
570                         bufp++;
571                 }
572                 sl[sc] = NULL;
573                 p->iri.schemelist = (const char **) sl;
574                 p->iri.nschemes = sc;
575                 bufp++;
576         }
577         bufp = ALIGN(bufp);
578         p->iri.host = bufp;
579         while(*src && *src != ':' && *src != '/' && *src != '?' && *src != '#')
580         {
581                 src = iri__copychar_decode(&bufp, src, 0);
582         }
583         *bufp = 0;
584         bufp++;
585         if(*src == ':')
586         {
587                 /* Port part */
588                 src++;
589                 endp = (char *) src;
590                 p->iri.port = strtol(src, &endp, 10);
591                 src = endp;
592         }
593         if(*src == '/')
594         {
595                 bufp = ALIGN(bufp);
596                 p->iri.path = bufp;
597                 while(*src && *src != '?' && *src != '#')
598                 {
599                         src = iri__copychar_decode(&bufp, src, 0);
600                 }
601                 *bufp = 0;
602                 bufp++;
603         }
604         if(*src == '?')
605         {
606                 bufp = ALIGN(bufp);
607                 p->iri.query = bufp;
608                 src++;
609                 while(*src && *src != '#')
610                 {
611                         /* Don't actually decode the query itself, otherwise it
612                          * can't be reliably split */
613                         src = iri__copychar(&bufp, src);
614                 }
615                 *bufp = 0;
616                 bufp++;
617         }
618         if(*src == '#')
619         {
620                 bufp = ALIGN(bufp);
621                 p->iri.anchor = bufp; 
622                 while(*src)
623                 {
624                         src = iri__copychar_decode(&bufp, src, 0);
625                 }
626                 *bufp = 0;
627                 bufp++;
628         }
629         if(*src)
630         {
631                 /* Still stuff left? It must be a path... of sorts */
632                 bufp = ALIGN(bufp);
633                 p->iri.path = bufp; 
634                 while(*src && *src != '?' && *src != '#')
635                 {
636                         src = iri__copychar_decode(&bufp, src, 0);
637                 }
638                 *bufp = 0;
639                 bufp++;
640         }
641         return p;
642 }
643
644
645
646
647