UriBool URI_FUNC()

in cpp/src/arrow/vendored/uriparser/UriCommon.c [133:339]


UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
		UriBool relative, UriBool pathOwned, UriMemoryManager * memory) {
	URI_TYPE(PathSegment) * walker;
	if ((uri == NULL) || (uri->pathHead == NULL)) {
		return URI_TRUE;
	}

	walker = uri->pathHead;
	walker->reserved = NULL; /* Prev pointer */
	do {
		UriBool removeSegment = URI_FALSE;
		int len = (int)(walker->text.afterLast - walker->text.first);
		switch (len) {
		case 1:
			if ((walker->text.first)[0] == _UT('.')) {
				/* "." segment -> remove if not essential */
				URI_TYPE(PathSegment) * const prev = walker->reserved;
				URI_TYPE(PathSegment) * const nextBackup = walker->next;

				/* Is this dot segment essential? */
				removeSegment = URI_TRUE;
				if (relative && (walker == uri->pathHead) && (walker->next != NULL)) {
					const URI_CHAR * ch = walker->next->text.first;
					for (; ch < walker->next->text.afterLast; ch++) {
						if (*ch == _UT(':')) {
							removeSegment = URI_FALSE;
							break;
						}
					}
				}

				if (removeSegment) {
					/* Last segment? */
					if (walker->next != NULL) {
						/* Not last segment */
						walker->next->reserved = prev;

						if (prev == NULL) {
							/* First but not last segment */
							uri->pathHead = walker->next;
						} else {
							/* Middle segment */
							prev->next = walker->next;
						}

						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
							memory->free(memory, (URI_CHAR *)walker->text.first);
						}
						memory->free(memory, walker);
					} else {
						/* Last segment */
						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
							memory->free(memory, (URI_CHAR *)walker->text.first);
						}

						if (prev == NULL) {
							/* Last and first */
							if (URI_FUNC(IsHostSet)(uri)) {
								/* Replace "." with empty segment to represent trailing slash */
								walker->text.first = URI_FUNC(SafeToPointTo);
								walker->text.afterLast = URI_FUNC(SafeToPointTo);
							} else {
								memory->free(memory, walker);

								uri->pathHead = NULL;
								uri->pathTail = NULL;
							}
						} else {
							/* Last but not first, replace "." with empty segment to represent trailing slash */
							walker->text.first = URI_FUNC(SafeToPointTo);
							walker->text.afterLast = URI_FUNC(SafeToPointTo);
						}
					}

					walker = nextBackup;
				}
			}
			break;

		case 2:
			if (((walker->text.first)[0] == _UT('.'))
					&& ((walker->text.first)[1] == _UT('.'))) {
				/* Path ".." -> remove this and the previous segment */
				URI_TYPE(PathSegment) * const prev = walker->reserved;
				URI_TYPE(PathSegment) * prevPrev;
				URI_TYPE(PathSegment) * const nextBackup = walker->next;

				removeSegment = URI_TRUE;
				if (relative) {
					if (prev == NULL) {
						removeSegment = URI_FALSE;
					} else if ((prev != NULL)
							&& ((prev->text.afterLast - prev->text.first) == 2)
							&& ((prev->text.first)[0] == _UT('.'))
							&& ((prev->text.first)[1] == _UT('.'))) {
						removeSegment = URI_FALSE;
					}
				}

				if (removeSegment) {
					if (prev != NULL) {
						/* Not first segment */
						prevPrev = prev->reserved;
						if (prevPrev != NULL) {
							/* Not even prev is the first one */
							prevPrev->next = walker->next;
							if (walker->next != NULL) {
								walker->next->reserved = prevPrev;
							} else {
								/* Last segment -> insert "" segment to represent trailing slash, update tail */
								URI_TYPE(PathSegment) * const segment = memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment)));
								if (segment == NULL) {
									if (pathOwned && (walker->text.first != walker->text.afterLast)) {
										memory->free(memory, (URI_CHAR *)walker->text.first);
									}
									memory->free(memory, walker);

									if (pathOwned && (prev->text.first != prev->text.afterLast)) {
										memory->free(memory, (URI_CHAR *)prev->text.first);
									}
									memory->free(memory, prev);

									return URI_FALSE; /* Raises malloc error */
								}
								segment->text.first = URI_FUNC(SafeToPointTo);
								segment->text.afterLast = URI_FUNC(SafeToPointTo);
								prevPrev->next = segment;
								uri->pathTail = segment;
							}

							if (pathOwned && (walker->text.first != walker->text.afterLast)) {
								memory->free(memory, (URI_CHAR *)walker->text.first);
							}
							memory->free(memory, walker);

							if (pathOwned && (prev->text.first != prev->text.afterLast)) {
								memory->free(memory, (URI_CHAR *)prev->text.first);
							}
							memory->free(memory, prev);

							walker = nextBackup;
						} else {
							/* Prev is the first segment */
							if (walker->next != NULL) {
								uri->pathHead = walker->next;
								walker->next->reserved = NULL;

								if (pathOwned && (walker->text.first != walker->text.afterLast)) {
									memory->free(memory, (URI_CHAR *)walker->text.first);
								}
								memory->free(memory, walker);
							} else {
								/* Re-use segment for "" path segment to represent trailing slash, update tail */
								URI_TYPE(PathSegment) * const segment = walker;
								if (pathOwned && (segment->text.first != segment->text.afterLast)) {
									memory->free(memory, (URI_CHAR *)segment->text.first);
								}
								segment->text.first = URI_FUNC(SafeToPointTo);
								segment->text.afterLast = URI_FUNC(SafeToPointTo);
								uri->pathHead = segment;
								uri->pathTail = segment;
							}

							if (pathOwned && (prev->text.first != prev->text.afterLast)) {
								memory->free(memory, (URI_CHAR *)prev->text.first);
							}
							memory->free(memory, prev);

							walker = nextBackup;
						}
					} else {
						URI_TYPE(PathSegment) * const anotherNextBackup = walker->next;
						/* First segment -> update head pointer */
						uri->pathHead = walker->next;
						if (walker->next != NULL) {
							walker->next->reserved = NULL;
						} else {
							/* Last segment -> update tail */
							uri->pathTail = NULL;
						}

						if (pathOwned && (walker->text.first != walker->text.afterLast)) {
							memory->free(memory, (URI_CHAR *)walker->text.first);
						}
						memory->free(memory, walker);

						walker = anotherNextBackup;
					}
				}
			}
			break;

		}

		if (!removeSegment) {
			if (walker->next != NULL) {
				walker->next->reserved = walker;
			} else {
				/* Last segment -> update tail */
				uri->pathTail = walker;
			}
			walker = walker->next;
		}
	} while (walker != NULL);

	return URI_TRUE;
}