"Fossies" - the Fresh Open Source Software Archive

Member "uriparser-0.9.5/src/UriCommon.c" (18 Mar 2021, 18375 Bytes) of package /linux/www/uriparser-0.9.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "UriCommon.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.9.4_vs_0.9.5.

    1 /*
    2  * uriparser - RFC 3986 URI parsing library
    3  *
    4  * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
    5  * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source  and binary forms, with or without
    9  * modification, are permitted provided  that the following conditions
   10  * are met:
   11  *
   12  *     1. Redistributions  of  source  code   must  retain  the  above
   13  *        copyright notice, this list  of conditions and the following
   14  *        disclaimer.
   15  *
   16  *     2. Redistributions  in binary  form  must  reproduce the  above
   17  *        copyright notice, this list  of conditions and the following
   18  *        disclaimer  in  the  documentation  and/or  other  materials
   19  *        provided with the distribution.
   20  *
   21  *     3. Neither the  name of the  copyright holder nor the  names of
   22  *        its contributors may be used  to endorse or promote products
   23  *        derived from  this software  without specific  prior written
   24  *        permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   27  * "AS IS" AND  ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING, BUT NOT
   28  * LIMITED TO,  THE IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS
   29  * FOR  A  PARTICULAR  PURPOSE  ARE  DISCLAIMED.  IN  NO  EVENT  SHALL
   30  * THE  COPYRIGHT HOLDER  OR CONTRIBUTORS  BE LIABLE  FOR ANY  DIRECT,
   31  * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   32  * (INCLUDING, BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS OR
   33  * SERVICES; LOSS OF USE, DATA,  OR PROFITS; OR BUSINESS INTERRUPTION)
   34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   35  * STRICT  LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE  OR  OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   37  * OF THE POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /* What encodings are enabled? */
   41 #include <uriparser/UriDefsConfig.h>
   42 #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
   43 /* Include SELF twice */
   44 # ifdef URI_ENABLE_ANSI
   45 #  define URI_PASS_ANSI 1
   46 #  include "UriCommon.c"
   47 #  undef URI_PASS_ANSI
   48 # endif
   49 # ifdef URI_ENABLE_UNICODE
   50 #  define URI_PASS_UNICODE 1
   51 #  include "UriCommon.c"
   52 #  undef URI_PASS_UNICODE
   53 # endif
   54 #else
   55 # ifdef URI_PASS_ANSI
   56 #  include <uriparser/UriDefsAnsi.h>
   57 # else
   58 #  include <uriparser/UriDefsUnicode.h>
   59 #  include <wchar.h>
   60 # endif
   61 
   62 
   63 
   64 #ifndef URI_DOXYGEN
   65 # include <uriparser/Uri.h>
   66 # include "UriCommon.h"
   67 #endif
   68 
   69 
   70 
   71 /*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
   72 /*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
   73 /*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
   74 
   75 
   76 
   77 void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
   78     if (uri == NULL) {
   79         return;
   80     }
   81     memset(uri, 0, sizeof(URI_TYPE(Uri)));
   82 }
   83 
   84 
   85 
   86 /* Compares two text ranges for equal text content */
   87 int URI_FUNC(CompareRange)(
   88         const URI_TYPE(TextRange) * a,
   89         const URI_TYPE(TextRange) * b) {
   90     int diff;
   91 
   92     /* NOTE: Both NULL means equal! */
   93     if ((a == NULL) || (b == NULL)) {
   94         return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
   95     }
   96 
   97     /* NOTE: Both NULL means equal! */
   98     if ((a->first == NULL) || (b->first == NULL)) {
   99         return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
  100     }
  101 
  102     diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first));
  103     if (diff > 0) {
  104         return 1;
  105     } else if (diff < 0) {
  106         return -1;
  107     }
  108 
  109     diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first));
  110 
  111     if (diff > 0) {
  112         return 1;
  113     } else if (diff < 0) {
  114         return -1;
  115     }
  116 
  117     return diff;
  118 }
  119 
  120 
  121 
  122 UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
  123         UriBool relative, UriBool pathOwned, UriMemoryManager * memory) {
  124     URI_TYPE(PathSegment) * walker;
  125     if ((uri == NULL) || (uri->pathHead == NULL)) {
  126         return URI_TRUE;
  127     }
  128 
  129     walker = uri->pathHead;
  130     walker->reserved = NULL; /* Prev pointer */
  131     do {
  132         UriBool removeSegment = URI_FALSE;
  133         int len = (int)(walker->text.afterLast - walker->text.first);
  134         switch (len) {
  135         case 1:
  136             if ((walker->text.first)[0] == _UT('.')) {
  137                 /* "." segment -> remove if not essential */
  138                 URI_TYPE(PathSegment) * const prev = walker->reserved;
  139                 URI_TYPE(PathSegment) * const nextBackup = walker->next;
  140 
  141                 /*
  142                  * Is this dot segment essential,
  143                  * i.e. is there a chance of changing semantics by dropping this dot segment?
  144                  *
  145                  * For example, changing "./http://foo" into "http://foo" would change semantics
  146                  * and hence the dot segment is essential to that case and cannot be removed.
  147                  */
  148                 removeSegment = URI_TRUE;
  149                 if (relative && (walker == uri->pathHead) && (walker->next != NULL)) {
  150                     const URI_CHAR * ch = walker->next->text.first;
  151                     for (; ch < walker->next->text.afterLast; ch++) {
  152                         if (*ch == _UT(':')) {
  153                             removeSegment = URI_FALSE;
  154                             break;
  155                         }
  156                     }
  157                 }
  158 
  159                 if (removeSegment) {
  160                     /* .. then let's go remove that segment. */
  161                     /* Last segment? */
  162                     if (walker->next != NULL) {
  163                         /* Not last segment, i.e. first or middle segment
  164                          * OLD: (prev|NULL) <- walker <- next
  165                          * NEW: (prev|NULL) <----------- next */
  166                         walker->next->reserved = prev;
  167 
  168                         if (prev == NULL) {
  169                             /* First but not last segment
  170                              * OLD: head -> walker -> next
  171                              * NEW: head -----------> next */
  172                             uri->pathHead = walker->next;
  173                         } else {
  174                             /* Middle segment
  175                              * OLD: prev -> walker -> next
  176                              * NEW: prev -----------> next */
  177                             prev->next = walker->next;
  178                         }
  179 
  180                         if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  181                             memory->free(memory, (URI_CHAR *)walker->text.first);
  182                         }
  183                         memory->free(memory, walker);
  184                     } else {
  185                         /* Last segment */
  186                         if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  187                             memory->free(memory, (URI_CHAR *)walker->text.first);
  188                         }
  189 
  190                         if (prev == NULL) {
  191                             /* Last and first */
  192                             if (URI_FUNC(IsHostSet)(uri)) {
  193                                 /* Replace "." with empty segment to represent trailing slash */
  194                                 walker->text.first = URI_FUNC(SafeToPointTo);
  195                                 walker->text.afterLast = URI_FUNC(SafeToPointTo);
  196                             } else {
  197                                 memory->free(memory, walker);
  198 
  199                                 uri->pathHead = NULL;
  200                                 uri->pathTail = NULL;
  201                             }
  202                         } else {
  203                             /* Last but not first, replace "." with empty segment to represent trailing slash */
  204                             walker->text.first = URI_FUNC(SafeToPointTo);
  205                             walker->text.afterLast = URI_FUNC(SafeToPointTo);
  206                         }
  207                     }
  208 
  209                     walker = nextBackup;
  210                 }
  211             }
  212             break;
  213 
  214         case 2:
  215             if (((walker->text.first)[0] == _UT('.'))
  216                     && ((walker->text.first)[1] == _UT('.'))) {
  217                 /* Path ".." -> remove this and the previous segment */
  218                 URI_TYPE(PathSegment) * const prev = walker->reserved;
  219                 URI_TYPE(PathSegment) * prevPrev;
  220                 URI_TYPE(PathSegment) * const nextBackup = walker->next;
  221 
  222                 removeSegment = URI_TRUE;
  223                 if (relative) {
  224                     if (prev == NULL) {
  225                         /* We cannot remove traversal beyond because the
  226                          * URI is relative and may be resolved later.
  227                          * So we can simplify "a/../b/d" to "b/d" but
  228                          * we cannot simplify "../b/d" (outside of reference resolution). */
  229                         removeSegment = URI_FALSE;
  230                     } else if ((prev != NULL)
  231                             && ((prev->text.afterLast - prev->text.first) == 2)
  232                             && ((prev->text.first)[0] == _UT('.'))
  233                             && ((prev->text.first)[1] == _UT('.'))) {
  234                         /* We need to protect against mis-simplifying "a/../../b" to "a/b". */
  235                         removeSegment = URI_FALSE;
  236                     }
  237                 }
  238 
  239                 if (removeSegment) {
  240                     if (prev != NULL) {
  241                         /* Not first segment */
  242                         prevPrev = prev->reserved;
  243                         if (prevPrev != NULL) {
  244                             /* Not even prev is the first one
  245                              * OLD: prevPrev -> prev -> walker -> (next|NULL)
  246                              * NEW: prevPrev -------------------> (next|NULL) */
  247                             prevPrev->next = walker->next;
  248                             if (walker->next != NULL) {
  249                                 /* Update parent relationship as well
  250                                  * OLD: prevPrev <- prev <- walker <- next
  251                                  * NEW: prevPrev <------------------- next */
  252                                 walker->next->reserved = prevPrev;
  253                             } else {
  254                                 /* Last segment -> insert "" segment to represent trailing slash, update tail */
  255                                 URI_TYPE(PathSegment) * const segment = memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment)));
  256                                 if (segment == NULL) {
  257                                     if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  258                                         memory->free(memory, (URI_CHAR *)walker->text.first);
  259                                     }
  260                                     memory->free(memory, walker);
  261 
  262                                     if (pathOwned && (prev->text.first != prev->text.afterLast)) {
  263                                         memory->free(memory, (URI_CHAR *)prev->text.first);
  264                                     }
  265                                     memory->free(memory, prev);
  266 
  267                                     return URI_FALSE; /* Raises malloc error */
  268                                 }
  269                                 segment->text.first = URI_FUNC(SafeToPointTo);
  270                                 segment->text.afterLast = URI_FUNC(SafeToPointTo);
  271                                 prevPrev->next = segment;
  272                                 uri->pathTail = segment;
  273                             }
  274 
  275                             if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  276                                 memory->free(memory, (URI_CHAR *)walker->text.first);
  277                             }
  278                             memory->free(memory, walker);
  279 
  280                             if (pathOwned && (prev->text.first != prev->text.afterLast)) {
  281                                 memory->free(memory, (URI_CHAR *)prev->text.first);
  282                             }
  283                             memory->free(memory, prev);
  284 
  285                             walker = nextBackup;
  286                         } else {
  287                             /* Prev is the first segment */
  288                             if (walker->next != NULL) {
  289                                 uri->pathHead = walker->next;
  290                                 walker->next->reserved = NULL;
  291 
  292                                 if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  293                                     memory->free(memory, (URI_CHAR *)walker->text.first);
  294                                 }
  295                                 memory->free(memory, walker);
  296                             } else {
  297                                 /* Re-use segment for "" path segment to represent trailing slash, update tail */
  298                                 URI_TYPE(PathSegment) * const segment = walker;
  299                                 if (pathOwned && (segment->text.first != segment->text.afterLast)) {
  300                                     memory->free(memory, (URI_CHAR *)segment->text.first);
  301                                 }
  302                                 segment->text.first = URI_FUNC(SafeToPointTo);
  303                                 segment->text.afterLast = URI_FUNC(SafeToPointTo);
  304                                 uri->pathHead = segment;
  305                                 uri->pathTail = segment;
  306                             }
  307 
  308                             if (pathOwned && (prev->text.first != prev->text.afterLast)) {
  309                                 memory->free(memory, (URI_CHAR *)prev->text.first);
  310                             }
  311                             memory->free(memory, prev);
  312 
  313                             walker = nextBackup;
  314                         }
  315                     } else {
  316                         URI_TYPE(PathSegment) * const anotherNextBackup = walker->next;
  317                         int freeWalker = URI_TRUE;
  318 
  319                         /* First segment */
  320                         if (walker->next != NULL) {
  321                             /* First segment of multiple -> update head
  322                              * OLD: head -> walker -> next
  323                              * NEW: head -----------> next */
  324                             uri->pathHead = walker->next;
  325 
  326                             /* Update parent link as well
  327                              * OLD: head <- walker <- next
  328                              * NEW: head <----------- next */
  329                             walker->next->reserved = NULL;
  330                         } else {
  331                             if (uri->absolutePath) {
  332                                 /* First and only segment -> update head
  333                                  * OLD: head -> walker -> NULL
  334                                  * NEW: head -----------> NULL */
  335                                 uri->pathHead = NULL;
  336 
  337                                 /* Last segment -> update tail
  338                                  * OLD: tail -> walker
  339                                  * NEW: tail -> NULL */
  340                                 uri->pathTail = NULL;
  341                             } else {
  342                                 /* Re-use segment for "" path segment to represent trailing slash,
  343                                  * then update head and tail */
  344                                 if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  345                                     memory->free(memory, (URI_CHAR *)walker->text.first);
  346                                 }
  347                                 walker->text.first = URI_FUNC(SafeToPointTo);
  348                                 walker->text.afterLast = URI_FUNC(SafeToPointTo);
  349                                 freeWalker = URI_FALSE;
  350                             }
  351                         }
  352 
  353                         if (freeWalker) {
  354                             if (pathOwned && (walker->text.first != walker->text.afterLast)) {
  355                                 memory->free(memory, (URI_CHAR *)walker->text.first);
  356                             }
  357                             memory->free(memory, walker);
  358                         }
  359 
  360                         walker = anotherNextBackup;
  361                     }
  362                 }
  363             }
  364             break;
  365         } /* end of switch */
  366 
  367         if (!removeSegment) {
  368             /* .. then let's move to the next element, and start again. */
  369             if (walker->next != NULL) {
  370                 walker->next->reserved = walker;
  371             } else {
  372                 /* Last segment -> update tail */
  373                 uri->pathTail = walker;
  374             }
  375             walker = walker->next;
  376         }
  377     } while (walker != NULL);
  378 
  379     return URI_TRUE;
  380 }
  381 
  382 
  383 
  384 /* Properly removes "." and ".." path segments */
  385 UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
  386         UriMemoryManager * memory) {
  387     const UriBool ABSOLUTE = URI_FALSE;
  388     if (uri == NULL) {
  389         return URI_TRUE;
  390     }
  391     return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory);
  392 }
  393 
  394 
  395 
  396 unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
  397     switch (hexdig) {
  398     case _UT('0'):
  399     case _UT('1'):
  400     case _UT('2'):
  401     case _UT('3'):
  402     case _UT('4'):
  403     case _UT('5'):
  404     case _UT('6'):
  405     case _UT('7'):
  406     case _UT('8'):
  407     case _UT('9'):
  408         return (unsigned char)(9 + hexdig - _UT('9'));
  409 
  410     case _UT('a'):
  411     case _UT('b'):
  412     case _UT('c'):
  413     case _UT('d'):
  414     case _UT('e'):
  415     case _UT('f'):
  416         return (unsigned char)(15 + hexdig - _UT('f'));
  417 
  418     case _UT('A'):
  419     case _UT('B'):
  420     case _UT('C'):
  421     case _UT('D'):
  422     case _UT('E'):
  423     case _UT('F'):
  424         return (unsigned char)(15 + hexdig - _UT('F'));
  425 
  426     default:
  427         return 0;
  428     }
  429 }
  430 
  431 
  432 
  433 URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) {
  434     /* Uppercase recommended in section 2.1. of RFC 3986 *
  435      * http://tools.ietf.org/html/rfc3986#section-2.1    */
  436     return URI_FUNC(HexToLetterEx)(value, URI_TRUE);
  437 }
  438 
  439 
  440 
  441 URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
  442     switch (value) {
  443     case  0: return _UT('0');
  444     case  1: return _UT('1');
  445     case  2: return _UT('2');
  446     case  3: return _UT('3');
  447     case  4: return _UT('4');
  448     case  5: return _UT('5');
  449     case  6: return _UT('6');
  450     case  7: return _UT('7');
  451     case  8: return _UT('8');
  452     case  9: return _UT('9');
  453 
  454     case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
  455     case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
  456     case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
  457     case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
  458     case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
  459     default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
  460     }
  461 }
  462 
  463 
  464 
  465 /* Checks if a URI has the host component set. */
  466 UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri) {
  467     return (uri != NULL)
  468             && ((uri->hostText.first != NULL)
  469                 || (uri->hostData.ip4 != NULL)
  470                 || (uri->hostData.ip6 != NULL)
  471                 || (uri->hostData.ipFuture.first != NULL)
  472             );
  473 }
  474 
  475 
  476 
  477 /* Copies the path segment list from one URI to another. */
  478 UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest,
  479         const URI_TYPE(Uri) * source, UriMemoryManager * memory) {
  480     if (source->pathHead == NULL) {
  481         /* No path component */
  482         dest->pathHead = NULL;
  483         dest->pathTail = NULL;
  484     } else {
  485         /* Copy list but not the text contained */
  486         URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
  487         URI_TYPE(PathSegment) * destPrev = NULL;
  488         do {
  489             URI_TYPE(PathSegment) * cur = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
  490             if (cur == NULL) {
  491                 /* Fix broken list */
  492                 if (destPrev != NULL) {
  493                     destPrev->next = NULL;
  494                 }
  495                 return URI_FALSE; /* Raises malloc error */
  496             }
  497 
  498             /* From this functions usage we know that *
  499              * the dest URI cannot be uri->owner      */
  500             cur->text = sourceWalker->text;
  501             if (destPrev == NULL) {
  502                 /* First segment ever */
  503                 dest->pathHead = cur;
  504             } else {
  505                 destPrev->next = cur;
  506             }
  507             destPrev = cur;
  508             sourceWalker = sourceWalker->next;
  509         } while (sourceWalker != NULL);
  510         dest->pathTail = destPrev;
  511         dest->pathTail->next = NULL;
  512     }
  513 
  514     dest->absolutePath = source->absolutePath;
  515     return URI_TRUE;
  516 }
  517 
  518 
  519 
  520 /* Copies the authority part of an URI over to another. */
  521 UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest,
  522         const URI_TYPE(Uri) * source, UriMemoryManager * memory) {
  523     /* From this functions usage we know that *
  524      * the dest URI cannot be uri->owner      */
  525     
  526     /* Copy userInfo */
  527     dest->userInfo = source->userInfo;
  528 
  529     /* Copy hostText */
  530     dest->hostText = source->hostText;
  531 
  532     /* Copy hostData */
  533     if (source->hostData.ip4 != NULL) {
  534         dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
  535         if (dest->hostData.ip4 == NULL) {
  536             return URI_FALSE; /* Raises malloc error */
  537         }
  538         *(dest->hostData.ip4) = *(source->hostData.ip4);
  539         dest->hostData.ip6 = NULL;
  540         dest->hostData.ipFuture.first = NULL;
  541         dest->hostData.ipFuture.afterLast = NULL;
  542     } else if (source->hostData.ip6 != NULL) {
  543         dest->hostData.ip4 = NULL;
  544         dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
  545         if (dest->hostData.ip6 == NULL) {
  546             return URI_FALSE; /* Raises malloc error */
  547         }
  548         *(dest->hostData.ip6) = *(source->hostData.ip6);
  549         dest->hostData.ipFuture.first = NULL;
  550         dest->hostData.ipFuture.afterLast = NULL;
  551     } else {
  552         dest->hostData.ip4 = NULL;
  553         dest->hostData.ip6 = NULL;
  554         dest->hostData.ipFuture = source->hostData.ipFuture;
  555     }
  556 
  557     /* Copy portText */
  558     dest->portText = source->portText;
  559 
  560     return URI_TRUE;
  561 }
  562 
  563 
  564 
  565 UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri,
  566         UriMemoryManager * memory) {
  567     URI_TYPE(PathSegment) * segment;
  568 
  569     if (    /* Case 1: absolute path, empty first segment */
  570             (uri->absolutePath
  571             && (uri->pathHead != NULL)
  572             && (uri->pathHead->text.afterLast == uri->pathHead->text.first))
  573 
  574             /* Case 2: relative path, empty first and second segment */
  575             || (!uri->absolutePath
  576             && (uri->pathHead != NULL)
  577             && (uri->pathHead->next != NULL)
  578             && (uri->pathHead->text.afterLast == uri->pathHead->text.first)
  579             && (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) {
  580         /* NOOP */
  581     } else {
  582         return URI_TRUE;
  583     }
  584 
  585     segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
  586     if (segment == NULL) {
  587         return URI_FALSE; /* Raises malloc error */
  588     }
  589 
  590     /* Insert "." segment in front */
  591     segment->next = uri->pathHead;
  592     segment->text.first = URI_FUNC(ConstPwd);
  593     segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
  594     uri->pathHead = segment;
  595     return URI_TRUE;
  596 }
  597 
  598 
  599 
  600 void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri,
  601         UriMemoryManager * memory) {
  602     /* Fix path if only one empty segment */
  603     if (!uri->absolutePath
  604             && !URI_FUNC(IsHostSet)(uri)
  605             && (uri->pathHead != NULL)
  606             && (uri->pathHead->next == NULL)
  607             && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
  608         memory->free(memory, uri->pathHead);
  609         uri->pathHead = NULL;
  610         uri->pathTail = NULL;
  611     }
  612 }
  613 
  614 
  615 
  616 #endif