summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhsoting.net>2026-05-08 11:54:15 +0200
committerJörg Frings-Fürst <debian@jff-webhsoting.net>2026-05-08 11:54:15 +0200
commit9d62028a6e8eced2ae6fabedd2b6317e9519b00d (patch)
tree1d8458cb6627ccfc673f791c5f0db45f9c06f7e0
parenta1dac799b819ba356a2faff3a98d7f5f076c24b6 (diff)
parent5177d88bf591522d1b934e24221e16e02cd1592b (diff)
Merge branch 'feature/upstream' into develop
-rw-r--r--.clang-format297
-rw-r--r--.github/workflows/build-and-test.yml53
-rw-r--r--.github/workflows/clang_format.yml39
-rw-r--r--.github/workflows/codespell.yml28
-rw-r--r--.github/workflows/coverage.yml77
-rw-r--r--.github/workflows/fuzzing.yml105
-rw-r--r--.github/workflows/windows.yml117
-rw-r--r--CMakeLists.txt153
-rw-r--r--COPYING.Apache-2.0202
-rw-r--r--COPYING.BSD-3-Clause (renamed from COPYING)0
-rw-r--r--COPYING.LGPL-2.1504
-rw-r--r--ChangeLog193
-rw-r--r--GOALS.txt92
-rw-r--r--README.md28
-rw-r--r--THANKS10
-rw-r--r--appveyor.yml101
-rw-r--r--cmake/test_find_package/CMakeLists.txt2
-rw-r--r--doc/.gitignore2
-rw-r--r--doc/Doxyfile.in1836
-rw-r--r--doc/Mainpage.txt242
-rwxr-xr-xdoc/preprocess.sh13
-rwxr-xr-xdoc/release.sh.in14
-rw-r--r--doc/rule_dependencies.dot128
-rw-r--r--fuzz/COPYING202
-rw-r--r--fuzz/DissectQueryMallocFuzzer.cpp62
-rw-r--r--fuzz/FreeFuzzer.cpp30
-rw-r--r--fuzz/FuzzingUtils.h44
-rw-r--r--fuzz/ParseFuzzer.cpp125
-rw-r--r--include/uriparser/COPYING36
-rw-r--r--include/uriparser/Uri.h1685
-rw-r--r--include/uriparser/UriBase.h339
-rw-r--r--include/uriparser/UriDefsAnsi.h10
-rw-r--r--include/uriparser/UriDefsConfig.h64
-rw-r--r--include/uriparser/UriDefsUnicode.h10
-rw-r--r--include/uriparser/UriIp4.h87
-rwxr-xr-xmake-distcheck.sh4
-rw-r--r--mull.yml2
-rwxr-xr-xscripts/edit_version.sh10
-rw-r--r--src/COPYING36
-rw-r--r--src/UriCommon.c1211
-rw-r--r--src/UriCommon.h88
-rw-r--r--src/UriCompare.c234
-rw-r--r--src/UriConfig.h.in10
-rw-r--r--src/UriCopy.c242
-rw-r--r--src/UriCopy.h76
-rw-r--r--src/UriEscape.c678
-rw-r--r--src/UriFile.c335
-rw-r--r--src/UriIp4.c404
-rw-r--r--src/UriIp4Base.c67
-rw-r--r--src/UriIp4Base.h16
-rw-r--r--src/UriMemory.c706
-rw-r--r--src/UriMemory.h52
-rw-r--r--src/UriNormalize.c1423
-rw-r--r--src/UriNormalize.h75
-rw-r--r--src/UriNormalizeBase.c146
-rw-r--r--src/UriNormalizeBase.h10
-rw-r--r--src/UriParse.c3785
-rw-r--r--src/UriParseBase.c73
-rw-r--r--src/UriParseBase.h12
-rw-r--r--src/UriQuery.c792
-rw-r--r--src/UriRecompose.c1073
-rw-r--r--src/UriResolve.c597
-rw-r--r--src/UriSetFragment.c174
-rw-r--r--src/UriSetHostAuto.c124
-rw-r--r--src/UriSetHostBase.h49
-rw-r--r--src/UriSetHostCommon.c248
-rw-r--r--src/UriSetHostCommon.h74
-rw-r--r--src/UriSetHostIp4.c91
-rw-r--r--src/UriSetHostIp6.c158
-rw-r--r--src/UriSetHostIpFuture.c157
-rw-r--r--src/UriSetHostRegName.c124
-rw-r--r--src/UriSetPath.c343
-rw-r--r--src/UriSetPort.c149
-rw-r--r--src/UriSetQuery.c172
-rw-r--r--src/UriSetScheme.c168
-rw-r--r--src/UriSetUserInfo.c180
-rw-r--r--src/UriSets.h174
-rw-r--r--src/UriShorten.c628
-rw-r--r--src/UriVersion.c81
-rw-r--r--test/CompareRangeLengthWrap.cpp97
-rw-r--r--test/FourSuite.cpp1196
-rw-r--r--test/MemoryManagerSuite.cpp554
-rw-r--r--test/SetFragment.cpp230
-rw-r--r--test/SetHostAuto.cpp223
-rw-r--r--test/SetHostIp4.cpp316
-rw-r--r--test/SetHostIp6.cpp387
-rw-r--r--test/SetHostIpFuture.cpp300
-rw-r--r--test/SetHostRegName.cpp336
-rw-r--r--test/SetPath.cpp450
-rw-r--r--test/SetPort.cpp191
-rw-r--r--test/SetQuery.cpp231
-rw-r--r--test/SetScheme.cpp230
-rw-r--r--test/SetUserInfo.cpp238
-rw-r--r--test/VersionSuite.cpp26
-rw-r--r--test/copy.cpp202
-rw-r--r--test/test.cpp4071
-rw-r--r--tool/COPYING36
-rw-r--r--tool/uriparse.c170
98 files changed, 20673 insertions, 10992 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..e511508
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,297 @@
+---
+Language: Cpp
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: true
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveMacros:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCaseArrows: false
+ AlignCaseColons: false
+AlignConsecutiveTableGenBreakingDAGArgColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveTableGenCondOperatorColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveTableGenDefinitionColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionDeclarations: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignEscapedNewlines: DontAlign
+AlignOperands: Align
+AlignTrailingComments:
+ Kind: Never
+ OverEmptyLines: 0
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseExpressionOnASingleLine: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
+AllowShortNamespacesOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AttributeMacros:
+ - __capability
+BinPackArguments: true
+BinPackLongBracedList: true
+BinPackParameters: BinPack
+BitFieldColonSpacing: Both
+BracedInitializerIndentWidth: -1
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: Never
+ AfterEnum: false
+ AfterExternBlock: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakAdjacentStringLiterals: true
+BreakAfterAttributes: Leave
+BreakAfterJavaFieldAnnotations: false
+BreakAfterReturnType: None
+BreakArrays: true
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeConceptDeclarations: Always
+BreakBeforeBraces: Attach
+BreakBeforeInlineASMColon: OnlyMultiline
+BreakBeforeTemplateCloser: false
+BreakBeforeTernaryOperators: true
+BreakBinaryOperations: Never
+BreakConstructorInitializers: BeforeColon
+BreakFunctionDefinitionParameters: false
+BreakInheritanceList: BeforeColon
+BreakStringLiterals: true
+BreakTemplateDeclarations: MultiLine
+ColumnLimit: 90
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+EnumTrailingComma: Leave
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentExportBlock: true
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: AfterHash
+IndentRequiresClause: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+InsertBraces: false
+InsertNewlineAtEOF: false
+InsertTrailingCommas: None
+IntegerLiteralSeparator:
+ Binary: 0
+ BinaryMinDigits: 0
+ Decimal: 0
+ DecimalMinDigits: 0
+ Hex: 0
+ HexMinDigits: 0
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLines:
+ AtEndOfFile: false
+ AtStartOfBlock: true
+ AtStartOfFile: true
+KeepFormFeed: false
+LambdaBodyIndentation: Signature
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MainIncludeChar: Quote
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+OneLineFormatOffRegex: ''
+PackConstructorInitializers: BinPack
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakBeforeMemberAccess: 150
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Middle
+PPIndentWidth: 2
+QualifierAlignment: Leave
+ReferenceAlignment: Pointer
+ReflowComments: Always
+RemoveBracesLLVM: false
+RemoveEmptyLinesInUnwrappedLines: false
+RemoveParentheses: Leave
+RemoveSemicolon: false
+RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
+SortIncludes:
+ Enabled: false
+ IgnoreCase: false
+SortJavaStaticImport: Before
+SortUsingDeclarations: LexicographicNumeric
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterOperatorKeyword: false
+SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterNot: false
+ AfterOverloadedOperator: false
+ AfterPlacementOperator: true
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: Never
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParens: Never
+SpacesInParensOptions:
+ ExceptDoubleParentheses: false
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
+SpacesInSquareBrackets: false
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TableGenBreakInsideDAGArg: DontBreak
+TabWidth: 8
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
+WhitespaceSensitiveMacros:
+ - BOOST_PP_STRINGIZE
+ - CF_SWIFT_NAME
+ - NS_SWIFT_NAME
+ - PP_STRINGIZE
+ - STRINGIZE
+WrapNamespaceBodyWithEmptyLines: Leave
+...
+
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index f330d27..8653739 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -1,7 +1,7 @@
# Copyright (C) 2021 Sebastian Pipping <sebastian@pipping.org>
# Licensed under the MIT license
-name: Build and test
+name: Build and test (Linux)
on:
pull_request:
@@ -11,30 +11,30 @@ on:
jobs:
build_and_test:
- name: Build and test
+ name: Build and test (Linux)
strategy:
matrix:
include:
- name: Native Linux
cmake_args: >-
- -DCMAKE_C_COMPILER=clang-18
- -DCMAKE_CXX_COMPILER=clang++-18
+ -DCMAKE_C_COMPILER=clang-21
+ -DCMAKE_CXX_COMPILER=clang++-21
cflags: >-
-fsanitize=address,undefined,leak
-fno-sanitize-recover=all
-fno-omit-frame-pointer
ldflags: >-
-fsanitize=address,undefined,leak
- - name: MingGW on Linux
+ - name: MinGW on Linux
cmake_args: >-
-DCMAKE_C_COMPILER=i686-w64-mingw32-gcc
-DCMAKE_CXX_COMPILER=i686-w64-mingw32-g++
-DCMAKE_SYSTEM_NAME=Windows
-DWIN32=ON
-DMINGW=ON
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Add Clang/LLVM repositories (Non-MinGW)
if: "${{ ! contains(matrix.cmake_args, 'mingw') }}"
@@ -42,7 +42,7 @@ jobs:
set -x
source /etc/os-release
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
- sudo add-apt-repository "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-18 main"
+ sudo add-apt-repository "deb http://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-21 main"
- name: Install build dependencies
run: |-
@@ -59,20 +59,7 @@ jobs:
- name: Install build dependencies (MinGW)
if: "${{ contains(matrix.cmake_args, 'mingw') }}"
run: |-
- set -x -u -o pipefail
- source /etc/os-release
-
- # Get rid of packages installed from ppa:ondrej/php so that we will be able to install wine32:i386 without conflicts
- # (see issue https://github.com/actions/virtual-environments/issues/4589)
- # In detail we:
- # 1. Remove all packages that ppa:ondrej/php has but plain Ubuntu doesn't, e.g. everything PHP
- # 2. Revert (remaining) packages that ppa:ondrej/php and plain Ubuntu share, back to the plain Ubuntu version
- # 3. Assert that no packages from ppa:ondrej/php are left installed
- dpkg -l | grep '^ii' | fgrep deb.sury.org | awk '{print $2}' | grep '^php' \
- | xargs -r -t sudo apt-get remove --yes libpcre2-posix3 libzip4
- dpkg -l | grep '^ii' | fgrep deb.sury.org | awk '{print $2}' | sed "s,\$,/${UBUNTU_CODENAME}," \
- | xargs -r -t sudo apt-get install --yes --no-install-recommends --allow-downgrades -V
- ! dpkg -l | grep '^ii' | fgrep deb.sury.org
+ set -x
# Install 32bit Wine
sudo dpkg --add-architecture i386 # for wine32
@@ -86,8 +73,8 @@ jobs:
if: "${{ ! contains(matrix.cmake_args, 'mingw') }}"
run: |-
sudo apt-get install --yes --no-install-recommends -V \
- clang-18 \
- libclang-rt-18-dev
+ clang-21 \
+ libclang-rt-21-dev
- name: Build, test and install
run: |-
@@ -103,8 +90,8 @@ jobs:
(
cd googletest-release-${GTEST_VERSION}/
- # Silence warning "Compatibility with CMake < 2.8.12 will be removed"
- find -name CMakeLists.txt -print -exec sed 's/cmake_minimum_required.*/cmake_minimum_required(VERSION 3.5.0)/' -i {} \;
+ # Silence warning "Compatibility with CMake < 3.10 will be removed"
+ find -name CMakeLists.txt -print -exec sed 's/cmake_minimum_required.*/cmake_minimum_required(VERSION 3.10.0)/' -i {} \;
cmake \
-DBUILD_SHARED_LIBS=ON \
@@ -129,8 +116,8 @@ jobs:
-Wextra
-pedantic
)
- CFLAGS="${compile_flags[*]} -std=c89"
- CXXFLAGS="${compile_flags[*]} -std=c++98"
+ CFLAGS="${compile_flags[*]} -std=c99"
+ CXXFLAGS="${compile_flags[*]} -std=c++11"
LDFLAGS='-g ${{ matrix.ldflags }}'
cmake_args=(
-DCMAKE_INSTALL_PREFIX:PATH=${GTEST_PREFIX}
@@ -148,6 +135,7 @@ jobs:
${{ matrix.cmake_args }}
+ -DURIPARSER_BUILD_TESTS=ON
-DURIPARSER_WARNINGS_AS_ERRORS=ON
)
cmake "${cmake_args[@]}" -DCMAKE_INSTALL_INCLUDEDIR=include123 ..
@@ -157,12 +145,19 @@ jobs:
# NOTE: We need to copy some .dll files next to the
# Windows binaries so that they are ready to be executed
if [[ "${{ matrix.cmake_args }}" == *mingw* ]]; then
- cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libgcc_s_sjlj-1.dll ./
+ cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libgcc_s_dw2-1.dll ./
cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libstdc++-6.dll ./
cp /usr/i686-w64-mingw32/lib/libwinpthread-1.dll ./
cp "${GTEST_PREFIX}"/bin/libgtest.dll ./
fi
+ # Configure UBSan to show (non-default) stack traces for runtime errors
+ # NOTE: "halt_on_error=1" we don't need to add because of the
+ # -fno-sanitize-recover=all for CFLAGS further up.
+ # NOTE: "abort_on_error=1" we don't need here because to CI,
+ # a non-zero exit code is all that matters.
+ export UBSAN_OPTIONS='print_stacktrace=1'
+
make VERBOSE=1 test ARGS=--verbose
cat Testing/Temporary/LastTest.log
diff --git a/.github/workflows/clang_format.yml b/.github/workflows/clang_format.yml
new file mode 100644
index 0000000..7ac9268
--- /dev/null
+++ b/.github/workflows/clang_format.yml
@@ -0,0 +1,39 @@
+# Copyright (C) 2025 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license
+
+name: Enforce clang-format clean code
+
+on:
+ pull_request:
+ push:
+ schedule:
+ - cron: '0 2 * * 5' # Every Friday at 2am
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ clang_format:
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Install Clang 21
+ run: |-
+ set -x
+ source /etc/os-release
+ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
+ sudo add-apt-repository "deb https://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-21 main"
+ sudo apt-get update # due to new repository
+ sudo apt-get install --yes --no-install-recommends -V \
+ clang-format-21
+ echo /usr/lib/llvm-21/bin >>"${GITHUB_PATH}"
+
+ - name: Enforce clang-format clean code
+ run: |
+ set -x -o pipefail
+ clang-format --version
+ git ls-files \*.cpp \*.c \*.h \*.h.in | xargs clang-format -i
+ sed 's,#\( \+\)cmakedefine,#cmakedefine,' -i.bak src/UriConfig.h.in # this helps Meson
+ git -c color.ui=always diff --exit-code # i.e. fail CI for non-empty diff
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
new file mode 100644
index 0000000..61af9fb
--- /dev/null
+++ b/.github/workflows/codespell.yml
@@ -0,0 +1,28 @@
+# Copyright (C) 2025 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license
+
+name: Enforce codespell-clean spelling
+
+on:
+ pull_request:
+ push:
+ schedule:
+ - cron: '0 4 * * 5' # Every Friday at 4am
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ checks:
+ name: Enforce codespell-clean spelling
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ - uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 # v2.2
+ with:
+ # "inout" is from "<b>INOUT</b>" markers
+ # "puls" is for last name "Puls" in files THANKS and ChangeLog
+ # "worstcase" is from variable name "worstCase" in file src/UriQuery.c
+ ignore_words_list: inout,puls,worstcase
+ skip: ./doc/rfc1866.htm,./doc/rfc3513.htm,./doc/rfc3986.htm
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..39e4bb1
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,77 @@
+# Copyright (C) 2025 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license
+
+name: Run tests under coverage
+
+on:
+ pull_request:
+ push:
+ schedule:
+ - cron: '0 2 * * 5' # Every Friday at 2am
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ test_coverage:
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Install Clang 21
+ run: |-
+ set -x
+ source /etc/os-release
+ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
+ sudo add-apt-repository "deb https://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-21 main"
+ sudo apt-get update # due to new repository
+ sudo apt-get install --yes --no-install-recommends -V \
+ clang-21 \
+ libclang-rt-21-dev \
+ llvm-21
+ echo /usr/lib/llvm-21/bin >>"${GITHUB_PATH}"
+
+ - name: Install other build dependencies
+ run: |-
+ set -x
+ sudo apt-get install --yes --no-install-recommends -V \
+ libgtest-dev
+
+ - name: Build uriparser fuzzers
+ run: |
+ args=(
+ # Build nothing but the test suite
+ -DURIPARSER_BUILD_DOCS=OFF
+ -DURIPARSER_BUILD_TESTS=ON
+ -DURIPARSER_BUILD_TOOLS=OFF
+ -DURIPARSER_ENABLE_INSTALL=OFF
+
+ # Tune compilation to use Clang with code coverage
+ -DCMAKE_C_COMPILER=clang-21
+ -DCMAKE_CXX_COMPILER=clang++-21
+ -DCMAKE_{C,CXX}_FLAGS='-Wall -Wextra -pedantic -O2 -g -fprofile-instr-generate -fcoverage-mapping'
+ -DURIPARSER_WARNINGS_AS_ERRORS=ON
+ )
+ set -x -o pipefail
+ cmake "${args[@]}" -S . -B build
+ make -C build VERBOSE=1 -j$(nproc)
+
+ - name: Run tests under coverage
+ run: |
+ CTEST_OUTPUT_ON_FAILURE=1 make -C build all test
+
+ - name: Generate reports
+ run: |
+ set -x -o pipefail
+ mkdir coverage/
+ llvm-profdata merge -sparse build/default.profraw -o coverage/indexed.profraw
+ llvm-cov show -instr-profile=coverage/indexed.profraw -format=html -output-dir=coverage/html/ build/testrunner
+ llvm-cov report -instr-profile=coverage/indexed.profraw build/testrunner |& tee coverage/report.txt
+
+ - name: Store coverage report
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: uriparser_coverage_${{ github.sha }}
+ path: coverage/
+ if-no-files-found: error
diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml
new file mode 100644
index 0000000..5b83389
--- /dev/null
+++ b/.github/workflows/fuzzing.yml
@@ -0,0 +1,105 @@
+# Copyright (C) 2025 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license
+
+name: Run fuzzing regression tests
+
+on:
+ pull_request:
+ push:
+ schedule:
+ - cron: '0 2 * * 5' # Every Friday at 2am
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ run_fuzzers:
+ name: ${{ matrix.fuzzer_name }}
+ strategy:
+ fail-fast: false
+ matrix:
+ fuzzer_name:
+ - uri_dissect_query_malloc_fuzzer
+ - uri_dissect_query_mallocw_fuzzer
+ - uri_free_fuzzer
+ - uri_freew_fuzzer
+ - uri_parse_fuzzer
+ - uri_parsew_fuzzer
+ runs-on: ubuntu-24.04
+ env:
+ fuzzer_name: ${{ matrix.fuzzer_name }}
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - name: Install Clang 21
+ run: |-
+ set -x
+ source /etc/os-release
+ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
+ sudo add-apt-repository "deb https://apt.llvm.org/${UBUNTU_CODENAME}/ llvm-toolchain-${UBUNTU_CODENAME}-21 main"
+ sudo apt-get update # due to new repository
+ sudo apt-get install --yes --no-install-recommends -V \
+ clang-21 \
+ libclang-rt-21-dev \
+ llvm-21
+ echo /usr/lib/llvm-21/bin >>"${GITHUB_PATH}"
+
+ - name: Build uriparser fuzzers
+ run: |
+ args=(
+ # Build nothing but fuzzers
+ -DURIPARSER_BUILD_DOCS=OFF
+ -DURIPARSER_BUILD_FUZZERS=ON
+ -DURIPARSER_BUILD_TOOLS=OFF
+ -DURIPARSER_ENABLE_INSTALL=OFF
+ -DURIPARSER_OSSFUZZ_BUILD=OFF
+
+ # Tune compilation of fuzzers to use Clang with ASan and UBSan
+ -DCMAKE_C_COMPILER=clang-21
+ -DCMAKE_CXX_COMPILER=clang++-21
+ -DCMAKE_{C,CXX}_FLAGS='-Wall -Wextra -pedantic -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -fno-common'
+ -DCMAKE_{EXE,MODULE,SHARED}_LINKER_FLAGS='-g -fsanitize=address,undefined'
+ -DURIPARSER_WARNINGS_AS_ERRORS=ON
+ )
+ set -x -o pipefail
+ cmake "${args[@]}" -S . -B build
+ make -C build VERBOSE=1 -j$(nproc)
+
+ - name: Download and extract uriparser fuzzing corpora
+ run: |-
+ set -x -o pipefail
+ cd build/
+ wget -q "https://storage.googleapis.com/uriparser-backup.clusterfuzz-external.appspot.com/corpus/libFuzzer/uriparser_${fuzzer_name}/public.zip"
+ unzip -q -d "corpus_${fuzzer_name}" public.zip
+ rm public.zip
+
+ - name: Run fuzzing regression tests
+ run: |
+ fuzz_args=(
+ -jobs=$(nproc)
+ -print_final_stats=1
+ -rss_limit_mb=2560 # from OSS-Fuzz
+ -timeout=25 # from OSS-Fuzz
+ )
+
+ set -x -o pipefail
+ cd "build/corpus_${fuzzer_name}/"
+
+ # Configure UBSan to show (non-default) stack traces for runtime errors
+ # NOTE: "halt_on_error=1" we don't need to add because of the
+ # -fno-sanitize-recover=all for CFLAGS further up.
+ # NOTE: "abort_on_error=1" we don't need here because to CI,
+ # a non-zero exit code is all that matters.
+ export UBSAN_OPTIONS='print_stacktrace=1'
+
+ find . -type f | sort | xargs -n 1000 "../fuzz/${fuzzer_name}" "${fuzz_args[@]}"
+ find . -type f | wc -l
+
+ - name: Store fuzzing logs of last batch
+ if: always()
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: uriparser_fuzzing_logs_last_${{ github.sha }}_${{ matrix.fuzzer_name }}
+ path: build/*/fuzz-*.log
+ if-no-files-found: error
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 0000000..ec8cee4
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,117 @@
+# Copyright (C) 2025 Sebastian Pipping <sebastian@pipping.org>
+# Licensed under the MIT license
+
+name: Build and test (Windows)
+
+on:
+ pull_request:
+ push:
+ schedule:
+ - cron: '0 2 * * 5' # Every Friday at 2am
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ windows:
+ name: Build and test (Windows)
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # Visual Studio 2022, 32 bit
+ - runs-on: windows-2022
+ cmake_generator: Visual Studio 17 2022
+ common_cmake_args: -A Win32
+ uriparser_sln: uriparser.sln
+
+ # Visual Studio 2022, 64 bit
+ - runs-on: windows-2022
+ cmake_generator: Visual Studio 17 2022
+ common_cmake_args: -A x64
+ uriparser_sln: uriparser.sln
+
+ # Visual Studio 2026, 32 bit
+ - runs-on: windows-2025-vs2026
+ cmake_generator: Visual Studio 18 2026
+ common_cmake_args: -A Win32
+ uriparser_sln: uriparser.slnx
+
+ # Visual Studio 2026, 64 bit
+ - runs-on: windows-2025-vs2026
+ cmake_generator: Visual Studio 18 2026
+ common_cmake_args: -A x64
+ uriparser_sln: uriparser.slnx
+
+ runs-on: ${{ matrix.runs-on }}
+ defaults:
+ run:
+ shell: bash
+ env:
+ CMAKE_GENERATOR: ${{ matrix.cmake_generator }}
+ COMMON_CMAKE_ARGS: ${{ matrix.common_cmake_args }}
+ GTEST_VERSION: 1.12.0
+ steps:
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+
+ - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0
+
+ - name: Build dependency googletest
+ run: |-
+ set -x
+ curl -fsSL -o "release-${GTEST_VERSION}.zip" "https://github.com/google/googletest/archive/release-${GTEST_VERSION}.zip"
+ unzip -q "release-${GTEST_VERSION}.zip"
+
+ cd "googletest-release-${GTEST_VERSION}"
+ cmake \
+ -G "${CMAKE_GENERATOR}" \
+ -DCVF_VERSION="${GTEST_VERSION}" \
+ ${COMMON_CMAKE_ARGS}
+ cmake --build . --config Release -- -m
+
+ # Enrich folder to make FindGTest.cmake happy
+ mkdir -p googletest/lib
+ cp -v lib/Release/{gtest,gtest_main}.lib googletest/lib/
+
+ - name: Configure
+ run: |-
+ cmake_args=(
+ -G "${CMAKE_GENERATOR}"
+ # NOTE: GTEST_ROOT is relative to source CMakeLists.txt, not the build directory
+ -DGTEST_ROOT="googletest-release-${GTEST_VERSION}/googletest"
+ -DURIPARSER_BUILD_DOCS=OFF
+ -DURIPARSER_BUILD_TESTS=ON
+ -DURIPARSER_MSVC_STATIC_CRT=ON
+ -DURIPARSER_WARNINGS_AS_ERRORS=ON
+ -S .
+ -B build/
+ ${COMMON_CMAKE_ARGS}
+ )
+ set -x
+ cmake "${cmake_args[@]}"
+
+ - name: Build
+ env:
+ uriparser_sln: ${{ matrix.uriparser_sln }}
+ run: |-
+ msbuild_args=(
+ -m
+ -property:Configuration=Release
+ )
+ set -x
+ cd build
+ MSBuild.exe "${msbuild_args[@]}" "${uriparser_sln}"
+
+ - name: Run tests
+ run: |-
+ ctest_args=(
+ --build-config Release
+ --no-tests=error
+ --output-on-failure
+ --parallel 2
+ )
+ set -x
+ cd build
+ ctest "${ctest_args[@]}"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 77f8ada..a8cdaf1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,19 +34,22 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
#
-cmake_minimum_required(VERSION 3.5.0)
+cmake_minimum_required(VERSION 3.15.0)
project(uriparser
VERSION
- 0.9.8
+ 1.0.1
LANGUAGES
C
)
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS OFF) # i.e. -std=c99 rather than default -std=gnu99
# See https://verbump.de/ for what these numbers do
-set(URIPARSER_SO_CURRENT 1)
-set(URIPARSER_SO_REVISION 31)
-set(URIPARSER_SO_AGE 0)
+set(URIPARSER_SO_CURRENT 3)
+set(URIPARSER_SO_REVISION 1)
+set(URIPARSER_SO_AGE 2)
include(CheckCCompilerFlag)
include(CheckFunctionExists)
@@ -65,13 +68,15 @@ else()
endif()
option(URIPARSER_SHARED_LIBS "Build shared libraries (rather than static ones)" ${_URIPARSER_SHARED_LIBS_DEFAULT})
option(URIPARSER_BUILD_DOCS "Build API documentation (requires Doxygen, Graphviz, and (optional) Qt's qhelpgenerator)" ON)
-option(URIPARSER_BUILD_TESTS "Build test suite (requires GTest >=1.8.0)" ON)
+option(URIPARSER_BUILD_TESTS "Build test suite (requires GTest >=1.8.0)" OFF)
+option(URIPARSER_BUILD_FUZZERS "Build fuzzers (requires Clang)" OFF)
+option(URIPARSER_OSSFUZZ_BUILD "Build fuzzers via OSS-Fuzz" OFF)
option(URIPARSER_BUILD_TOOLS "Build tools (e.g. CLI \"uriparse\")" ON)
option(URIPARSER_BUILD_CHAR "Build code supporting data type 'char'" ON)
option(URIPARSER_BUILD_WCHAR_T "Build code supporting data type 'wchar_t'" ON)
option(URIPARSER_ENABLE_INSTALL "Enable installation of uriparser" ON)
option(URIPARSER_WARNINGS_AS_ERRORS "Treat all compiler warnings as errors" OFF)
-set(URIPARSER_MSVC_RUNTIME "" CACHE STRING "Use of specific runtime library (/MT /MTd /MD /MDd) with MSVC")
+option(URIPARSER_MSVC_STATIC_CRT "Use /MT flag (static CRT) when compiling in MSVC" OFF)
if(NOT URIPARSER_BUILD_CHAR AND NOT URIPARSER_BUILD_WCHAR_T)
message(SEND_ERROR "One or more of URIPARSER_BUILD_CHAR and URIPARSER_BUILD_WCHAR_T needs to be enabled.")
@@ -83,9 +88,17 @@ if(URIPARSER_BUILD_TOOLS AND NOT URIPARSER_BUILD_CHAR)
message(SEND_ERROR "URIPARSER_BUILD_TOOLS=ON requires URIPARSER_BUILD_CHAR=ON.")
endif()
-if(URIPARSER_BUILD_TESTS)
+if(URIPARSER_BUILD_TESTS OR URIPARSER_BUILD_FUZZERS)
# We have to call enable_language() before modifying any CMAKE_CXX_* variables
enable_language(CXX)
+
+ if(URIPARSER_BUILD_FUZZERS)
+ set(CMAKE_CXX_STANDARD 17)
+ else()
+ set(CMAKE_CXX_STANDARD 11)
+ endif()
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_EXTENSIONS OFF) # i.e. -std=c++11 rather than default -std=gnu++11
endif()
if(URIPARSER_SHARED_LIBS)
@@ -94,14 +107,18 @@ else()
set(_URIPARSER_STATIC_OR_SHARED STATIC)
endif()
-macro(uriparser_apply_msvc_runtime_to ref)
- string(REGEX REPLACE "/M[DT]d?" ${URIPARSER_MSVC_RUNTIME} ${ref} "${${ref}}")
-endmacro()
+if (MSVC)
+ cmake_policy(GET CMP0091 _policy_cmp0091_behavior)
+ if (NOT _policy_cmp0091_behavior STREQUAL NEW)
+ message(SEND_ERROR "Policy CMP0091 behavior is '${_policy_cmp0091_behavior}' rather than 'NEW', mis-compilation detected.")
+ endif()
-if(MSVC AND URIPARSER_MSVC_RUNTIME)
- uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS)
- uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS_DEBUG)
- uriparser_apply_msvc_runtime_to(CMAKE_C_FLAGS_RELEASE)
+ message(STATUS "-- Using static CRT ${URIPARSER_MSVC_STATIC_CRT}")
+ if (URIPARSER_MSVC_STATIC_CRT)
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") # .. without suffix "DLL": static
+ else()
+ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL") # i.e. CMake default behavior: shared
+ endif()
endif()
macro(uriparser_install)
@@ -142,6 +159,8 @@ set(LIBRARY_CODE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/UriCommon.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriCommon.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UriCompare.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriCopy.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriCopy.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UriEscape.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriFile.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriIp4Base.c
@@ -152,13 +171,30 @@ set(LIBRARY_CODE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalizeBase.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalizeBase.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalize.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriNormalize.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UriParseBase.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriParseBase.h
${CMAKE_CURRENT_SOURCE_DIR}/src/UriParse.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriQuery.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriRecompose.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriResolve.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetFragment.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostAuto.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostBase.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostCommon.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostCommon.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostIp4.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostIp6.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostIpFuture.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetHostRegName.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetPath.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetPort.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetQuery.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSets.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetScheme.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriSetUserInfo.c
${CMAKE_CURRENT_SOURCE_DIR}/src/UriShorten.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/UriVersion.c
)
add_library(uriparser
@@ -167,6 +203,8 @@ add_library(uriparser
${LIBRARY_CODE_FILES}
)
+add_library(uriparser::uriparser ALIAS uriparser)
+
if(NOT MSVC)
math(EXPR URIPARSER_SO_CURRENT_MINUS_AGE "${URIPARSER_SO_CURRENT} - ${URIPARSER_SO_AGE}")
set_property(TARGET uriparser PROPERTY VERSION ${URIPARSER_SO_CURRENT_MINUS_AGE}.${URIPARSER_SO_AGE}.${URIPARSER_SO_REVISION})
@@ -276,9 +314,22 @@ if(URIPARSER_BUILD_TESTS)
find_package(GTest 1.8.0 REQUIRED)
add_executable(testrunner
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/CompareRangeLengthWrap.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/copy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/FourSuite.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/MemoryManagerSuite.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/test.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetFragment.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetHostAuto.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetHostIp4.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetHostIp6.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetHostIpFuture.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetHostRegName.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetPath.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetPort.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetQuery.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetScheme.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/SetUserInfo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/VersionSuite.cpp
# These library code files have non-public symbols that the test suite
@@ -333,6 +384,73 @@ if(URIPARSER_BUILD_TESTS)
endif()
#
+# Fuzzers
+#
+if(URIPARSER_BUILD_FUZZERS)
+ if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ message(FATAL_ERROR
+ "Building fuzz targets without Clang (but ${CMAKE_C_COMPILER_ID}) is not "
+ "supported. Please set -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++.")
+ endif()
+
+ if(URIPARSER_OSSFUZZ_BUILD AND NOT DEFINED ENV{LIB_FUZZING_ENGINE})
+ message(FATAL_ERROR
+ "OSS-Fuzz builds require the environment variable "
+ "LIB_FUZZING_ENGINE to be set. If you are seeing this "
+ "warning, it points to a deeper problem in the OSS-Fuzz "
+ "build setup.")
+ endif()
+
+ add_library(fuzzparser STATIC ${API_HEADER_FILES} ${LIBRARY_CODE_FILES})
+ target_compile_definitions(fuzzparser PUBLIC URI_STATIC_BUILD)
+ target_include_directories(fuzzparser
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR} # for UriConfig.h
+ )
+
+ if(NOT URIPARSER_OSSFUZZ_BUILD)
+ target_compile_options(fuzzparser PRIVATE -fsanitize=fuzzer-no-link)
+ endif()
+
+ function(add_fuzzer target_name source compile_definitions)
+ add_executable(${target_name} ${source})
+ target_link_libraries(${target_name} PRIVATE fuzzparser)
+ target_compile_definitions(${target_name} PRIVATE ${compile_definitions})
+ if(URIPARSER_OSSFUZZ_BUILD)
+ set_target_properties(${target_name} PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
+ set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE "CXX")
+ else()
+ target_compile_options(${target_name} PRIVATE -fsanitize=fuzzer)
+ set_target_properties(${target_name} PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
+ endif()
+ set_property(TARGET ${target_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz)
+ endfunction()
+
+ function(add_ansi_and_unicode_fuzzer name source)
+ if(URIPARSER_BUILD_CHAR)
+ add_fuzzer(${name}_fuzzer ${source} URI_NO_UNICODE)
+ endif()
+
+ if(URIPARSER_BUILD_WCHAR_T)
+ add_fuzzer(${name}w_fuzzer ${source} URI_NO_ANSI)
+ endif()
+ endfunction()
+
+ add_ansi_and_unicode_fuzzer(uri_dissect_query_malloc fuzz/DissectQueryMallocFuzzer.cpp)
+ add_ansi_and_unicode_fuzzer(uri_free fuzz/FreeFuzzer.cpp)
+ add_ansi_and_unicode_fuzzer(uri_parse fuzz/ParseFuzzer.cpp)
+else()
+ if(URIPARSER_OSSFUZZ_BUILD)
+ message(SEND_ERROR
+ "Attempting to perform an OSS-Fuzz build without turning on the fuzzer build. "
+ "This is likely in error - consider adding "
+ "-DURIPARSER_BUILD_FUZZERS=ON to your CMake execution.")
+ endif()
+endif()
+
+#
# Compiler flags
#
if(URIPARSER_WARNINGS_AS_ERRORS)
@@ -402,7 +520,7 @@ if(URIPARSER_BUILD_DOCS)
if(QHG_LOCATION)
uriparser_install(
FILES
- ${CMAKE_CURRENT_BINARY_DIR}/doc/uriparser-${PROJECT_VERSION}.qch
+ ${CMAKE_CURRENT_BINARY_DIR}/doc/uriparser-${PROJECT_VERSION}-doc.qch
DESTINATION
${CMAKE_INSTALL_DOCDIR}
)
@@ -420,7 +538,7 @@ configure_package_config_file(
)
write_basic_package_version_file(
cmake/uriparser-config-version.cmake
- COMPATIBILITY SameMajorVersion # i.e. semver
+ COMPATIBILITY AnyNewerVersion # i.e. declare 0.x.x and 1.x.x compatible
)
export(
TARGETS
@@ -493,6 +611,7 @@ message(STATUS " Code for char * ...... ${URIPARSER_BUILD_CHAR}")
message(STATUS " Code for wchar_t * ... ${URIPARSER_BUILD_WCHAR_T}")
message(STATUS " Tools ................ ${URIPARSER_BUILD_TOOLS}")
message(STATUS " Test suite ........... ${URIPARSER_BUILD_TESTS}")
+message(STATUS " Fuzzers .............. ${URIPARSER_BUILD_FUZZERS}")
message(STATUS " Documentation ........ ${URIPARSER_BUILD_DOCS}")
message(STATUS "")
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
diff --git a/COPYING.Apache-2.0 b/COPYING.Apache-2.0
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/COPYING.Apache-2.0
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/COPYING b/COPYING.BSD-3-Clause
index 261c741..261c741 100644
--- a/COPYING
+++ b/COPYING.BSD-3-Clause
diff --git a/COPYING.LGPL-2.1 b/COPYING.LGPL-2.1
new file mode 100644
index 0000000..c176226
--- /dev/null
+++ b/COPYING.LGPL-2.1
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ChangeLog b/ChangeLog
index 8f19bbf..5b1ed29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,196 @@ NOTE: uriparser is looking for help with a few things:
https://github.com/uriparser/uriparser/labels/help%20wanted
If you can help, please get in touch. Thanks!
+2026-04-27 -- 1.0.1
+
+>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ * Fixed: [CVE-2026-42371]
+ Protect from integer overflow in text range comparison.
+ Thanks for the report and pull request to Joshua W. Windle! (GitHub #298)
+>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ * Fixed: Fix `reallocarray` preprocessor handling for Illumos (GitHub #289)
+ * Improved: Fix an in-code comment typo in src/UriCommon.c;
+ Thanks for the report and pull request to Tim Düsterhus! (GitHub #290)
+ * Improved: CMake: Start enforcing supported C++ standard (GitHub #295)
+ * Improved: Allow use of C++11 to future unit tests (GitHub #296)
+ * Infrastructure: Cover compilation with Visual Studio 18 2026 (GitHub #301)
+ * Infrastructure: Address warning on CMake <3.10 in CI (GitHub #297)
+ * Soname: 3:1:2 — see https://verbump.de/ for what these numbers do
+ (liburiparser.so.1.2.1)
+
+2025-12-15 -- 1.0.0
+
+>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ * Fixed: [CVE-2025-67899]
+ Protect from stack overflow during parsing by dissolving all 13 cases
+ of recursion, both direct and indirect. The attack vector was long
+ (or crafted) URI input. The known impact is denial of service or more.
+ Thanks for the report to Sergey Svistunov!
+ Thanks for in-depth review to Tim Düsterhus! (sponsored by Tideways GmbH)
+ Thanks for C callgraph tool "egypt" (https://www.gson.org/egypt/)
+ to Andreas Gustafsson and for "dot_find_cycles.py" to Jason Antman!
+ (GitHub #282, GitHub #284)
+>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ * Changed: Start requiring a C99 compiler (GitHub #264, GitHub #273)
+ * Changed: Require CMake >=3.15.0 (GitHub #270)
+ * Changed: Stop building tests by default (GitHub #283)
+ * Fixed: Normalization of URIs with leading dot segments
+ produced ambiguous results in the sense that a reparse
+ after normalization would have misinterpreted path parts
+ as a host (GitHub #262, GitHub #263, GitHub #265)
+ Examples of affected URIs:
+ - "scheme:/.//path1/path2"
+ - "/.//path1/path2"
+ - ".//path1/path2"
+ The fix is to not remove that dot segment.
+ Thanks to Ignace Nyamagana Butera and to Tim Düsterhus for the report!
+ * Fixed: Insufficient pointer alignment from allocation wrappers
+ used in the implementation of function uriCompleteMemoryManager.
+ (GitHub #261)
+ Thanks to Matthew Fernandez and Rolf Eike Beer for the report and review!
+ * Fixed: Do not set `absolutePath` for empty paths when removing host
+ Thanks for the report and pull request to Tim Düsterhus!
+ (GitHub #275, GitHub #276)
+ * Fixed: Documentation of functions uriCompleteMemoryManager,
+ uriEmulateCalloc, uriEmulateReallocarray and uriTestMemoryManager
+ (GitHub #261)
+ * Fixed: CMake: Remake approach to static CRT with MSVC compilers
+ Old: -DURIPARSER_MSVC_RUNTIME=/MT
+ New: -DURIPARSER_MSVC_STATIC_CRT=ON
+ (GitHub #270)
+ * Fixed: Documentation: Get CMake variables list back in sync and sorted
+ in the readme (GitHub #270)
+ * Fixed: Various typos found by Codespell
+ (https://github.com/codespell-project/codespell) (GitHub #259)
+ * Added: Add a new (and recommended to use) version of uriTestMemoryManager
+ that can challenge pointer alignment (GitHub #261)
+ New functions:
+ uriTestMemoryManagerEx
+ * Improved: Increase test coverage by mutation testing
+ Thanks for the pull request to Tim Düsterhus! (GitHub #266)
+ * Improved: Address compiler warning -Wunused-but-set-variable (GitHub #268)
+ * Improved: Deduplicate internal char set macros (GitHub #280)
+ * Infrastructure: Enable stack traces from UndefinedBehaviorSanitizer in CI
+ via environment variable UBSAN_OPTIONS (GitHub #261)
+ * Infrastructure: Bump GoogleTest to 1.12.0 in AppVeyor CI to fix the build
+ with CMake >=3.5 (GitHub #261)
+ * Infrastructure: Migrate Windows CI from AppVeyor to GitHub Actions
+ (GitHub #270)
+ * Infrastructure: Make GitHub Actions detect and reject known typos using
+ Codespell (https://github.com/codespell-project/codespell) (GitHub #259)
+ * Infrastructure: Update Clang from 20 to 21 (GitHub #267)
+ * Infrastructure: Start specifying CXX and CXXFLAGS for fuzzing CI
+ (GitHub #268)
+ * Infrastructure: Make CI report on test coverage using LLVM, and offer
+ these reports for download (GitHub #32, GitHub #269)
+ * Infrastructure: Make CI enforce clang-format clean code (GitHub #272)
+ * Soname: 3:0:2 — see https://verbump.de/ for what these numbers do
+ (liburiparser.so.1.2.0)
+
+2025-09-03 -- 0.9.9
+
+ * Changed: Require CMake >=3.10.0 (GitHub #204)
+ * Fixed: Dissolve undefined behavior in parsing of URIs (GitHub #252)
+ Thanks to Tim Düsterhus for the report!
+ * Fixed: Normalized percent-encoded octets should have uppercase letters
+ in the host (GitHub #221, GitHub #222)
+ Thanks to Máté Kocsis for the pull request!
+ * Fixed: Fix documentation of uriEscape (GitHub #206, GitHub #207)
+ * Fixed: Docstring typo in ParseIpFourAddress (GitHub #254)
+ * Fixed: Documentation: Make Mainpage.txt bypass the C preprocessor
+ (GitHub #226, GitHub #227)
+ * Fixed: Documentation: Migrate Doxygen from ${CPP} to ${CC} -E (GitHub #192)
+ * Fixed: Fix macros URI_VER_SUFFIX_UNICODE and URI_VER_UNICODE (GitHub #258)
+ Thanks to Tim Düsterhus for the report and patch!
+ * Added: Support for copying Uri structures (GitHub #200, GitHub #230,
+ GitHub #237, GitHub #240, GitHub #250, GitHub #251)
+ Thanks to Máté Kocsis and to Tim Düsterhus!
+ New functions:
+ uriCopyUri[AW]
+ uriCopyUriMm[AW]
+ * Added: Add port normalization to NormalizeSyntax function (GitHub #231)
+ * Added: Add function HasHost to the public API (GitHub #234)
+ Thanks to Máté Kocsis for the pull request!
+ New functions:
+ uriHasHost[AW]
+ * Added: Support obtaining base runtime version (GitHub #219, GitHub #258)
+ New functions:
+ uriBaseRuntimeVersion[AW]
+ * Added: CMake: Add alias "uriparser::uriparser" (GitHub #197)
+ * Added: Integrate fuzzers from google/oss-fuzz repository and
+ improve those fuzzers on top (GitHub #209, GitHub #211, GitHub #212,
+ GitHub #214)
+ Thanks to @tyler92 for two of the related pull requests!
+ * Added: Support setting individual components of a UriUri[AW] structure
+ (GitHub #196, GitHub #249)
+ Part of this work was commissioned by the PHP Foundation.
+ Thanks to Máté Kocsis and Tim Düsterhus for the detailed review!
+ New functions:
+ uriIsWellFormedFragment[AW]
+ uriIsWellFormedHostIp4[AW]
+ uriIsWellFormedHostIp6[AW]
+ uriIsWellFormedHostIp6Mm[AW]
+ uriIsWellFormedHostIpFuture[AW]
+ uriIsWellFormedHostIpFutureMm[AW]
+ uriIsWellFormedHostRegName[AW]
+ uriIsWellFormedPath[AW]
+ uriIsWellFormedPort[AW]
+ uriIsWellFormedQuery[AW]
+ uriIsWellFormedScheme[AW]
+ uriIsWellFormedUserInfo[AW]
+ uriParseIpSixAddress[AW]
+ uriParseIpSixAddressMm[AW]
+ uriSetFragment[AW]
+ uriSetFragmentMm[AW]
+ uriSetHostAuto[AW]
+ uriSetHostAutoMm[AW]
+ uriSetHostIp4[AW]
+ uriSetHostIp4Mm[AW]
+ uriSetHostIp6[AW]
+ uriSetHostIp6Mm[AW]
+ uriSetHostIpFuture[AW]
+ uriSetHostIpFutureMm[AW]
+ uriSetHostRegName[AW]
+ uriSetHostRegNameMm[AW]
+ uriSetPath[AW]
+ uriSetPathMm[AW]
+ uriSetPortText[AW]
+ uriSetPortTextMm[AW]
+ uriSetQuery[AW]
+ uriSetQueryMm[AW]
+ uriSetScheme[AW]
+ uriSetSchemeMm[AW]
+ uriSetUserInfo[AW]
+ uriSetUserInfoMm[AW]
+ * Improved: CMake: Compile with -std=c90 by default (GitHub #232)
+ * Improved: Be consequent about and document .hostData.ipFuture .hostText
+ relation (GitHub #243)
+ * Improved: Document and cover FreeUriMembers after memset with zeros
+ (GitHub #238, GitHub #239)
+ * Improved: CLI tool "uriparse": Add missing hostData.ipFuture output
+ (GitHub #253)
+ * Improved: tests: Mass-replace ASSERT_TRUE([..] == [..]) by ASSERT_EQ
+ (GitHub #235)
+ * Improved: tests: Leverage assertion EXPECT_STREQ (GitHub #257)
+ * Improved: Percent encoding related code cleanup (GitHub #242)
+ * Improved: Documentation: Update some URLs to new HTTPS locations
+ Thanks to Hanno Böck for the pull request!
+ (GitHub #224)
+ * Improved: Documentation: Hide URI_PUBLIC (GitHub #236)
+ * Improved: Convert remaining DOS (CR/LF) newlines to Unix newlines
+ Thanks to Hanno Böck for the pull request!
+ (GitHub #225)
+ * Improved: Rename misleading variable doneMask to revertMask
+ (GitHub #233, GitHub #244)
+ * Improved: Make licensing easier to discover (GitHub #246)
+ * Changed: Documentation: For the Qt Compressed Help file, migrate from
+ naming ".qch" to "-doc.qch" (GitHub #191)
+ * Infrastructure: Update Clang from 18 to 20 (GitHub #217, GitHub #228)
+ * Infrastructure: Bump CI to Ubuntu 24.04 (GitHub #216)
+ * Infrastructure: Adapt to breaking changes in CI (GitHub #199, GitHub #204)
+ * Soname: 2:0:1 — see https://verbump.de/ for what these numbers do
+ (liburiparser.so.1.1.0)
+
2024-05-05 -- 0.9.8
>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -28,6 +218,7 @@ NOTE: uriparser is looking for help with a few things:
* Infrastructure: Pin GitHub Actions to specific commits for security
(GitHub #165)
* Soname: 1:31:0 — see https://verbump.de/ for what these numbers do
+ (liburiparser.so.1.0.31)
2022-10-05 -- 0.9.7
@@ -223,7 +414,7 @@ NOTE: uriparser is looking for help with a few things:
Protect uriResetUri* against acting on NULL input
Commit f58c25069cf4a986fe17a80c5b38687e31feb539
>>>>>>>>>>>>> SECURITY >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
- * Fixed: Be fully compliant to C89 (Gitub #28) and C++98 in test code
+ * Fixed: Be fully compliant to C89 (GitHub #28) and C++98 in test code
* Fixed: Fix off-by-one in uriComposeQueryCharsRequired* and ...Ex*
Reported space requirements were 1 byte bigger than necessary
* Changed: Marked as deprecated:
diff --git a/GOALS.txt b/GOALS.txt
index a906a2a..1e0baf6 100644
--- a/GOALS.txt
+++ b/GOALS.txt
@@ -1,46 +1,46 @@
-== Requirements ==
- (1) URI parser fully conforming to the
- latest URI RFC. Currently this is RFC 3986:
- http://tools.ietf.org/html/rfc3986
-
- (2) Based on an LL(1) grammar, at least mainly.
- Not using a jump table but one function per
- rule instead.
-
- (3) Library licensed under "New BSD license".
- http://www.opensource.org/licenses/bsd-license.php
- Test suite code licensed under LGPL.
- http://www.opensource.org/licenses/lgpl-license.php
-
- (4) Written in ANSI/ISO C.
-
- (5) Portable. Must compile with GCC, MinGW,
- Visual Studio 200[35].
-
- (6) "OOP-C" -> thread safe, no shared globals
- between two parser "instances"
-
- (7) Support for <char> and <wchar_t> without internal
- conversion. Two versions of all functions
- from the public interface.
-
- (8) Doxygen Code documentation at least for all
- interface functions and structures.
- http://www.stack.nl/~dimitri/doxygen/index.html
-
- (9) Sun Java code conventions for all C/C++ code.
- http://java.sun.com/docs/codeconv/
-
-(10) #include "xxx" for files in same folder.
- #include <xxx> for files from include folders.
-
-(11) Use GoogleTest for unit testing.
- https://github.com/google/googletest
-
-(12) Implement algorithm for reference resolution
-
-(13) Implement algorithm for normalization and
- comparison
-
-== Optional goals ==
- (A) C++ Wrapper classes (uriparser++?)
+== Requirements ==
+ (1) URI parser fully conforming to the
+ latest URI RFC. Currently this is RFC 3986:
+ https://datatracker.ietf.org/doc/html/rfc3986
+
+ (2) Based on an LL(1) grammar, at least mainly.
+ Not using a jump table but one function per
+ rule instead.
+
+ (3) Library licensed under "New BSD license".
+ https://opensource.org/license/BSD-2-Clause
+ Test suite code licensed under LGPL.
+ https://opensource.org/license/lgpl-3-0
+
+ (4) Written in ANSI/ISO C.
+
+ (5) Portable. Must compile with GCC, MinGW,
+ Visual Studio 200[35].
+
+ (6) "OOP-C" -> thread safe, no shared globals
+ between two parser "instances"
+
+ (7) Support for <char> and <wchar_t> without internal
+ conversion. Two versions of all functions
+ from the public interface.
+
+ (8) Doxygen Code documentation at least for all
+ interface functions and structures.
+ https://www.doxygen.nl/
+
+ (9) Sun Java code conventions for all C/C++ code.
+ http://java.sun.com/docs/codeconv/
+
+(10) #include "xxx" for files in same folder.
+ #include <xxx> for files from include folders.
+
+(11) Use GoogleTest for unit testing.
+ https://github.com/google/googletest
+
+(12) Implement algorithm for reference resolution
+
+(13) Implement algorithm for normalization and
+ comparison
+
+== Optional goals ==
+ (A) C++ Wrapper classes (uriparser++?)
diff --git a/README.md b/README.md
index d399ca2..10e6855 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,23 @@
-[![Build and test](https://github.com/uriparser/uriparser/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/uriparser/uriparser/actions/workflows/build-and-test.yml)
-[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/uriparseradmin/uriparser?svg=true)](https://ci.appveyor.com/project/uriparseradmin/uriparser)
+[![Build and test (Linux)](https://github.com/uriparser/uriparser/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/uriparser/uriparser/actions/workflows/build-and-test.yml)
+[![Build and test (Windows)](https://github.com/uriparser/uriparser/actions/workflows/windows.yml/badge.svg)](https://github.com/uriparser/uriparser/actions/workflows/windows.yml)
# uriparser
uriparser is a
-strictly [RFC 3986](http://tools.ietf.org/html/rfc3986) compliant
+strictly [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) compliant
URI parsing and handling library
-written in C89 ("ANSI C").
+written in C99.
uriparser is cross-platform,
fast,
supports both `char` and `wchar_t`, and
-is licensed under the [New BSD license](https://github.com/uriparser/uriparser/blob/master/COPYING).
+is licensed under the [BSD-3-Clause license](https://spdx.org/licenses/BSD-3-Clause.html)
+(except for the test suite
+that is licensed under the
+[LGPL-2.1-or-later license](https://spdx.org/licenses/LGPL-2.1-or-later.html)
+and for the fuzzing code
+that is licensed under the
+[Apache-2.0 license](https://spdx.org/licenses/Apache-2.0.html)).
To learn more about uriparser,
please check out [https://uriparser.github.io/](https://uriparser.github.io/).
@@ -64,8 +70,11 @@ URIPARSER_BUILD_CHAR:BOOL=ON
// Build API documentation (requires Doxygen, Graphviz, and (optional) Qt's qhelpgenerator)
URIPARSER_BUILD_DOCS:BOOL=ON
+// Build fuzzers (requires Clang)
+URIPARSER_BUILD_FUZZERS:BOOL=OFF
+
// Build test suite (requires GTest >=1.8.0)
-URIPARSER_BUILD_TESTS:BOOL=ON
+URIPARSER_BUILD_TESTS:BOOL=OFF
// Build tools (e.g. CLI "uriparse")
URIPARSER_BUILD_TOOLS:BOOL=ON
@@ -76,8 +85,11 @@ URIPARSER_BUILD_WCHAR_T:BOOL=ON
// Enable installation of uriparser
URIPARSER_ENABLE_INSTALL:BOOL=ON
-// Use of specific runtime library (/MT /MTd /MD /MDd) with MSVC
-URIPARSER_MSVC_RUNTIME:STRING=
+// Use /MT flag (static CRT) when compiling in MSVC
+URIPARSER_MSVC_STATIC_CRT:BOOL=OFF
+
+// Build fuzzers via OSS-Fuzz
+URIPARSER_OSSFUZZ_BUILD:BOOL=OFF
// Build shared libraries (rather than static ones)
URIPARSER_SHARED_LIBS:BOOL=ON
diff --git a/THANKS b/THANKS
index a394948..f6666c8 100644
--- a/THANKS
+++ b/THANKS
@@ -5,6 +5,7 @@ Adrian Manrique
Alexander Klink
Alexander Richardson
Arkadiusz Miskiewicz
+Andreas Gustafsson
Andreas Sturmlechner
Blair Sadewitz
Brecht Sanders
@@ -27,7 +28,10 @@ Friedrich Delgado Friedrichs
Gaspard Petit
Gary Mazzaferro
Graham Percival
+Hanno Böck
Harvey Vrsalovic
+Ignace Nyamagana Butera
+Jason Antman
jensenrichardson
Jerome Custodio
Joel Cunningham
@@ -41,6 +45,8 @@ Marc Novakowski
Marcin Juszkiewicz
Mariusz Zaborski
Martin Michlmayr
+Máté Kocsis
+Matthew Fernandez
Michael Anthony Puls II
Michelino Chionchio
Michel Zou
@@ -57,14 +63,18 @@ René Rebe
Richard Hodges
Robert Buchholz
Robert Kausch
+Rolf Eike Beer
Ryan Schmidt
Sandro Mani
Scallop Ye
Schrijvers Luc
Scott Donelan
+Sergey Svistunov
Sezai Tekin
Shehzan Mohammed
SpaceIm
+Tim Düsterhus
+tyler92
Valentin Haenel
Vitaly Lipatov
Wouter Beek
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 2f6f632..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-# uriparser - RFC 3986 URI parsing library
-#
-# Copyright (C) 2018, Sebastian Pipping <sebastian@pipping.org>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above
-# copyright notice, this list of conditions and the following
-# disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials
-# provided with the distribution.
-#
-# 3. Neither the name of the copyright holder nor the names of
-# its contributors may be used to endorse or promote products
-# derived from this software without specific prior written
-# permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-version: '{build}-{branch}'
-
-configuration:
- - Debug
-# - Release
-
-environment:
- GTEST_VERSION: 1.10.0
-
- # https://www.appveyor.com/docs/windows-images-software/
- matrix:
- # Visual Studio 2017, 32 bit
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- CMAKE_GENERATOR: Visual Studio 15 2017
- PLATFORM: Win32
-
- # Visual Studio 2017, 64 bit
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- CMAKE_GENERATOR: Visual Studio 15 2017 Win64
- PLATFORM: x64
-
- # Visual Studio 2022, 32 bit
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
- CMAKE_GENERATOR: Visual Studio 17 2022
- COMMON_CMAKE_ARGS: -A Win32
-
- # Visual Studio 2022, 64 bit
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
- CMAKE_GENERATOR: Visual Studio 17 2022
- COMMON_CMAKE_ARGS: -A x64
-
-before_build:
- - curl -fsSL -o release-%GTEST_VERSION%.zip https://github.com/google/googletest/archive/release-%GTEST_VERSION%.zip
- - unzip -q release-%GTEST_VERSION%.zip
- - cd googletest-release-%GTEST_VERSION%
- - cmake
- -G "%CMAKE_GENERATOR%"
- -DCVF_VERSION=%GTEST_VERSION%
- %COMMON_CMAKE_ARGS%
- .
- - cmake --build . --config Release -- /m
-# BEGIN Enrich folder to make FindGTest.cmake happy
- - md googletest\lib
- - copy lib\Release\gtest.lib googletest\lib
- - copy lib\Release\gtest_main.lib googletest\lib
-# END
- - cd ..
- - mkdir build
- - cd build
-# NOTE: GTEST_ROOT is relative to source CMakeLists.txt, not the build directory
- - cmake
- -G "%CMAKE_GENERATOR%"
- -DGTEST_ROOT=googletest-release-%GTEST_VERSION%/googletest
- -DURIPARSER_BUILD_DOCS=OFF
- -DURIPARSER_MSVC_RUNTIME=/MT
- -DURIPARSER_WARNINGS_AS_ERRORS=ON
- %COMMON_CMAKE_ARGS%
- ..
-
-build:
- parallel: true
- project: $(APPVEYOR_BUILD_FOLDER)\build\$(APPVEYOR_PROJECT_NAME).sln
-
-test_script:
- - '%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\testrunner.exe'
diff --git a/cmake/test_find_package/CMakeLists.txt b/cmake/test_find_package/CMakeLists.txt
index 77527cd..58851c5 100644
--- a/cmake/test_find_package/CMakeLists.txt
+++ b/cmake/test_find_package/CMakeLists.txt
@@ -34,7 +34,7 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
#
-cmake_minimum_required(VERSION 3.5.0)
+cmake_minimum_required(VERSION 3.15.0)
project(test-find-package VERSION 1.0)
diff --git a/doc/.gitignore b/doc/.gitignore
index ba9a3b7..9323408 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1,5 +1,5 @@
/Doxyfile
/html
/release.sh
-/uriparser-*.qch
+/uriparser-*-doc.qch
/uriparser-*-doc.zip
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index da4132f..64ab45f 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -1,918 +1,918 @@
-# Doxyfile for Doxygen 1.5.7
-
-# .qhp output
-GENERATE_QHP = @GENERATE_QHP@
-QHP_NAMESPACE = "io.github.uriparser"
-QHP_VIRTUAL_FOLDER = "uriparser-@PROJECT_VERSION@"
-
-# .qch output
-QCH_FILE = "../@PROJECT_NAME@-@PROJECT_VERSION@.qch"
-QHG_LOCATION = "@QHG_LOCATION@"
-
-
-###############################################################
-# Project related options
-###############################################################
-
-
-PROJECT_NAME = "uriparser"
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by double-quotes) that should identify the project for which the documentation is generated. This name is used in the title of most generated pages and in a few other places.
-
-
-PROJECT_NUMBER = "@PROJECT_VERSION@"
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This could be handy for archiving the generated documentation or if some version control system is used.
-
-
-CHM_FILE = "..\@PROJECT_NAME@-@PROJECT_VERSION@.chm"
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can be used to specify the file name of the resulting .chm file. You can add a path in front of the file if the result should not be written to the html output directory.
-
-
-OUTPUT_DIRECTORY = .
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path into which the generated documentation will be written. If a relative path is entered, it will be relative to the location where doxygen was started. If left blank the current directory will be used.
-
-
-# CREATE_SUBDIRS =
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-directories (in 2 levels) under the output directory of each output format and will distribute the generated files over these directories. Enabling this option can be useful when feeding doxygen a huge amount of source files, where putting all generated files in the same directory would otherwise causes performance problems for the file system.
-
-
-# OUTPUT_LANGUAGE =
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all documentation generated by doxygen is written. Doxygen will use this information to generate all constant output in the proper language. The default language is English, other supported languages are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean, Lithuanian, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
-
-
-# USE_WINDOWS_ENCODING =
-# This tag can be used to specify the encoding used in the generated output. The encoding is not always determined by the language that is chosen, but also whether or not the output is meant for Windows or non-Windows users. In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES forces the Windows encoding, (this is the default for the Windows binary), whereas setting the tag to NO uses a Unix-style encoding (the default for all platforms other than Windows).
-
-
-# BRIEF_MEMBER_DESC =
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) doxygen will include brief member descriptions after the members that are listed in the file and class documentation (similar to JavaDoc). Set to NO to disable this.
-
-
-# REPEAT_BRIEF =
-# If the REPEAT_BRIEF tag is set to YES (the default) doxygen will prepend the brief description of a member or function before the detailed description
-#
-# Note:
-# If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the brief descriptions will be completely suppressed.
-
-
-# ABBREVIATE_BRIEF =
-# This tag implements a quasi-intelligent brief description abbreviator that is used to form the text in various listings. Each string in this list, if found as the leading text of the brief description, will be stripped from the text and the result after processing the whole list, is used as the annotated text. Otherwise, the brief description is used as-is. If left blank, the following values are used ("\$name" is automatically replaced with the name of the entity): "The $name class" "The $name widget" "The $name file" "is" "provides" "specifies" "contains" "represents" "a" "an" "the".
-
-
-# ALWAYS_DETAILED_SEC =
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then doxygen will generate a detailed section even if there is only a brief description.
-
-
-# INLINE_INHERITED_MEMB =
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited members of a class in the documentation of that class as if those members were ordinary class members. Constructors, destructors and assignment operators of the base classes will not be shown.
-
-
-FULL_PATH_NAMES = NO
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path before files name in the file list and in the header files. If set to NO the shortest path that makes the file name unique will be used
-
-
-# STRIP_FROM_PATH =
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. Stripping is only done if one of the specified strings matches the left-hand part of the path. The tag can be used to show relative paths in the file list. If left blank the directory from which doxygen is run is used as the path to strip.
-
-
-# STRIP_FROM_INC_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the path mentioned in the documentation of a class, which tells the reader which header file to include in order to use a class. If left blank only the name of the header file containing the class definition is used. Otherwise one should specify the include paths that are normally passed to the compiler using the -I flag.
-
-
-# CASE_SENSE_NAMES =
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file names in lower-case letters. If set to YES upper-case letters are also allowed. This is useful if you have classes or files whose names only differ in case and if your file system supports case sensitive file names. Windows users are advised to set this option to NO.
-
-
-# SHORT_NAMES =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but less readable) file names. This can be useful is your file systems doesn't support long names like on DOS, Mac, or CD-ROM.
-
-
-# JAVADOC_AUTOBRIEF =
-# If the JAVADOC_AUTOBRIEF is set to YES then doxygen will interpret the first line (until the first dot) of a JavaDoc-style comment as the brief description. If set to NO (the default), the Javadoc-style will behave just like the Qt-style comments.
-
-
-BUILTIN_STL_SUPPORT = NO
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to include (a tag file for) the STL sources as input, then you should set this tag to YES in order to let doxygen match functions declarations and definitions whose arguments contain STL classes (e.g. func(std::string); v.s. func(std::string) {}). This also make the inheritance and collaboration diagrams that involve STL classes more complete and accurate.
-
-
-# DISTRIBUTE_GROUP_DOC =
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC tag is set to YES, then doxygen will reuse the documentation of the first member in the group (if any) for the other members of the group. By default all members of a group must be documented explicitly.
-
-
-# MULTILINE_CPP_IS_BRIEF =
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a multi-line C++ special comment block (i.e. a block of //! or /// comments) as a brief description. This used to be the default behaviour. The new default is to treat a multi-line C++ comment block as a detailed description. Set this tag to YES if you prefer the old behaviour instead. Note that setting this tag to YES also means that rational rose comments are not recognized any more.
-
-
-# INHERIT_DOCS =
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented member inherits the documentation from any documented member that it re-implements.
-
-
-# SEPARATE_MEMBER_PAGES =
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a new page for each member. If set to NO, the documentation of a member will be part of the file/class/namespace that contains it.
-
-
-# TAB_SIZE =
-# the TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen uses this value to replace tabs by spaces in code fragments.
-
-
-# ALIASES =
-# This tag can be used to specify a number of aliases that acts as commands in the documentation. An alias has the form
-#
-# name=value
-#
-# For example adding
-#
-# "sideeffect=\par Side Effects:\n"
-#
-# will allow you to put the command \sideeffect (or @sideeffect) in the documentation, which will result in a user-defined paragraph with heading "Side Effects:". You can put \n's in the value part of an alias to insert newlines.
-
-
-OPTIMIZE_OUTPUT_FOR_C = YES
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources only. Doxygen will then generate output that is more tailored for C. For instance, some of the names that are used will be different. The list of all members will be omitted, etc.
-
-
-# OPTIMIZE_OUTPUT_JAVA =
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or Python sources only. Doxygen will then generate output that is more tailored for that language. For instance, namespaces will be presented as packages, qualified scopes will look different, etc.
-
-
-# SUBGROUPING =
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of the same type (for instance a group of public functions) to be put as a subgroup of that type (e.g. under the Public Functions section). Set it to NO to prevent subgrouping. Alternatively, this can be done per class using the \nosubgrouping command.
-
-
-
-
-###############################################################
-# Build related options
-###############################################################
-
-
-EXTRACT_ALL = NO
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in documentation are documented, even if no documentation was available. Private class members and static file members will be hidden unless the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-#
-# Note:
-# This will also disable the warnings about undocumented members that are normally produced when WARNINGS is set to YES
-
-
-EXTRACT_PRIVATE = YES
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will be included in the documentation.
-
-
-EXTRACT_STATIC = YES
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be included in the documentation.
-
-
-# EXTRACT_LOCAL_CLASSES =
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined locally in source files will be included in the documentation. If set to NO only classes defined in header files are included. Does not have any effect for Java sources.
-
-
-# EXTRACT_LOCAL_METHODS =
-# This flag is only useful for Objective-C code. When set to YES local methods, which are defined in the implementation section but not in the interface are included in the documentation. If set to NO (the default) only methods in the interface are included.
-
-
-HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all undocumented members inside documented classes or files. If set to NO (the default) these members will be included in the various overviews, but no documentation section is generated. This option has no effect if EXTRACT_ALL is enabled.
-
-
-HIDE_UNDOC_CLASSES = NO
-# If the HIDE_UNDOC_CLASSESS tag is set to YES, doxygen will hide all undocumented classes. If set to NO (the default) these classes will be included in the various overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-
-HIDE_FRIEND_COMPOUNDS = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend (class|struct|union) declarations. If set to NO (the default) these declarations will be included in the documentation.
-
-
-# HIDE_IN_BODY_DOCS =
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any documentation blocks found inside the body of a function. If set to NO (the default) these blocks will be appended to the function's detailed documentation block.
-
-
-# INTERNAL_DOCS =
-# The INTERNAL_DOCS tag determines if documentation that is typed after a \internal command is included. If the tag is set to NO (the default) then the documentation will be excluded. Set it to YES to include the internal documentation.
-
-
-HIDE_SCOPE_NAMES = YES
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then doxygen will show members with their full class and namespace scopes in the documentation. If set to YES the scope will be hidden.
-
-
-SHOW_INCLUDE_FILES = YES
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then doxygen will put a list of the files that are included by a file in the documentation of that file.
-
-
-# INLINE_INFO =
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] is inserted in the documentation for inline members.
-
-
-# SORT_MEMBER_DOCS =
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen will sort the (detailed) documentation of file and class members alphabetically by member name. If set to NO the members will appear in declaration order.
-
-
-# SORT_BRIEF_DOCS =
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief descriptions of file, namespace and class members alphabetically by member name. If set to NO (the default) the members will appear in declaration order.
-
-
-# GENERATE_DEPRECATEDLIST =
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
-
-
-# GENERATE_TODOLIST =
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo list. This list is created by putting \todo commands in the documentation.
-
-
-# GENERATE_TESTLIST =
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test list. This list is created by putting \test commands in the documentation.
-
-
-# GENERATE_BUGLIST =
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug list. This list is created by putting \bug commands in the documentation.
-
-
-# ENABLED_SECTIONS =
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation sections, marked by \if <section-label> ... \endif and \cond <section-label> ... \endcond blocks.
-
-
-# MAX_INITIALIZER_LINES =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the initial value of a variable or define can be. If the initializer consists of more lines than specified here it will be hidden. Use a value of 0 to hide initializers completely. The appearance of the value of individual variables and defines can be controlled using \showinitializer or \hideinitializer command in the documentation.
-
-
-SHOW_USED_FILES = YES
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at the bottom of the documentation of classes and structs. If set to YES the list will mention the files that were used to generate the documentation.
-
-
-
-
-###############################################################
-# Options related to warning and progress messages
-###############################################################
-
-
-QUIET = YES
-# The QUIET tag can be used to turn on/off the messages that are generated to standard output by doxygen. Possible values are YES and NO, where YES implies that the messages are off. If left blank NO is used.
-
-
-# WARNINGS =
-# The WARNINGS tag can be used to turn on/off the warning messages that are generated to standard error by doxygen. Possible values are YES and NO, where YES implies that the warnings are on. If left blank NO is used.
-#
-# Tip: Turn warnings on while writing the documentation.
-
-
-WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag will automatically be disabled.
-
-
-WARN_IF_DOC_ERROR = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for potential errors in the documentation, such as not documenting some parameters in a documented function, or documenting parameters that don't exist or using markup commands wrongly.
-
-
-WARN_NO_PARAMDOC = YES
-# This WARN_NO_PARAMDOC option can be abled to get warnings for functions that are documented, but have no documentation for their parameters or return value. If set to NO (the default) doxygen will only warn about wrong or incomplete parameter documentation, but not about the absence of documentation.
-
-
-WARN_FORMAT = "WARNING: $text ($line, $file)"
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen can produce. The string should contain the $file, $line, and $text tags, which will be replaced by the file and line number from which the warning originated and the warning text.
-
-
-# WARN_LOGFILE =
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error messages should be written. If left blank the output is written to stderr.
-
-
-
-
-###############################################################
-# Input related options
-###############################################################
-
-
-INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@/doc/Mainpage.txt
-# The INPUT tag is used to specify the files and/or directories that contain documented source files. You may enter file names like myfile.cpp or directories like /usr/src/myproject. Separate the files or directories with spaces.
-#
-# Note: If this tag is empty the current directory is searched.
-
-
-# FILE_PATTERNS =
-# If the value of the INPUT tag contains directories, you can use the FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and *.h ) to filter out the source-files in the directories. If left blank the following patterns are tested: .c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp .h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
-
-
-# FILE_VERSION_FILTER =
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that doxygen should invoke to get the current version for each file (typically from the version control system). Doxygen will invoke the program by executing (via popen()) the command command input-file, where command is the value of the FILE_VERSION_FILTER tag, and input-file is the name of an input file provided by doxygen. Whatever the program writes to standard output is used as the file version.
-#
-# Example of using a shell script as a filter for Unix:
-#
-# FILE_VERSION_FILTER = "/bin/sh versionfilter.sh"
-#
-# Example shell script for CVS:
-#
-# #!/bin/sh
-# cvs status $1 | sed -n 's/^[ \]*Working revision:[ \t]*\([0-9][0-9\.]*\).*/\1/p'
-#
-# Example shell script for Subversion:
-#
-# #!/bin/sh
-# svn stat -v $1 | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p'
-#
-# Example filter for ClearCase:
-#
-# FILE_VERSION_INFO = "cleartool desc -fmt \%Vn"
-
-
-RECURSIVE = YES
-# The RECURSIVE tag can be used to specify whether or not subdirectories should be searched for input files as well. Possible values are YES and NO. If left blank NO is used.
-
-
-# EXCLUDE =
-# The EXCLUDE tag can be used to specify files and/or directories that should excluded from the INPUT source files. This way you can easily exclude a subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-
-# EXCLUDE_SYMLINKS =
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories that are symbolic links (a Unix filesystem feature) are excluded from the input.
-
-
-# EXCLUDE_PATTERNS =
-# If the value of the INPUT tag contains directories, you can use the EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude certain files from those directories.
-
-# Note that the wildcards are matched against the file with absolute path, so to exclude all test directories use the pattern */test/*
-
-
-# EXAMPLE_PATH =
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories that contain example code fragments that are included (see the \include command in section \include).
-
-
-# EXAMPLE_RECURSIVE =
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be searched for input files to be used with the \include or \dontinclude commands irrespective of the value of the RECURSIVE tag. Possible values are YES and NO. If left blank NO is used.
-
-
-# EXAMPLE_PATTERNS =
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and *.h) to filter out the source-files in the directories. If left blank all files are included.
-
-
-# IMAGE_PATH =
-# The IMAGE_PATH tag can be used to specify one or more files or directories that contain images that are to be included in the documentation (see the \image command).
-
-
-INPUT_FILTER = "bash @CMAKE_CURRENT_SOURCE_DIR@/doc/preprocess.sh"
-# The INPUT_FILTER tag can be used to specify a program that doxygen should invoke to filter for each input file. Doxygen will invoke the filter program by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the name of an input file. Doxygen will then use the output that the filter program writes to standard output.
-
-
-# FILTER_PATTERNS =
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern basis. Doxygen will compare the file name with each pattern and apply the filter if there is a match. The filters are a list of the form: pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER is applied to all files.
-
-
-# FILTER_SOURCE_FILES =
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using INPUT_FILTER ) will also be used to filter the input files that are used for producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-
-
-
-###############################################################
-# Source browsing related options
-###############################################################
-
-
-# SOURCE_BROWSER =
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be generated. Documented entities will be cross-referenced with these sources.
-
-
-# INLINE_SOURCES =
-# Setting the INLINE_SOURCES tag to YES will include the body of functions, classes and enums directly into the documentation.
-
-
-STRIP_CODE_COMMENTS = YES
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct doxygen to hide any special comment blocks from generated source code fragments. Normal C and C++ comments will always remain visible.
-
-
-# REFERENCED_BY_RELATION =
-# If the REFERENCED_BY_RELATION tag is set to YES (the default) then for each documented function all documented functions referencing it will be listed.
-
-
-# REFERENCES_RELATION =
-# If the REFERENCES_RELATION tag is set to YES (the default) then for each documented function all documented entities called/used by that function will be listed.
-
-
-# REFERENCES_LINK_SOURCE =
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) and SOURCE_BROWSER tag is set to YES, then the hyperlinks from functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will link to the documentstion.
-
-
-VERBATIM_HEADERS = NO
-# If the VERBATIM_HEADERS tag is set the YES (the default) then doxygen will generate a verbatim copy of the header file for each class for which an include is specified. Set to NO to disable this.
-#
-# See also:
-# Section \class.
-
-
-# USE_HTAGS =
-# If the USE_HTAGS tag is set to YES then the references to source code will point to the HTML generated by the htags(1) tool instead of doxygen built-in source browser. The htags tool is part of GNU's global source tagging system (see http://www.gnu.org/software/global/global.html). The use it do the following:
-#
-# 1. Install the latest version of global (i.e. 4.8.6 or better)
-# 2. Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# 3. Make sure the INPUT points to the root of the source tree
-# 4. Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to source code will now point to the output of htags.
-
-
-
-
-###############################################################
-# Alphabetical index options
-###############################################################
-
-
-# COLS_IN_ALPHA_INDEX =
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in which this list will be split (can be a number in the range [1..20])
-
-
-# IGNORE_PREFIX =
-# In case all classes in a project start with a common prefix, all classes will be put under the same header in the alphabetical index. The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) that should be ignored while generating the index headers.
-
-
-
-
-###############################################################
-# HTML related options
-###############################################################
-
-
-GENERATE_HTML = YES
-# If the GENERATE_HTML tag is set to YES (the default) doxygen will generate HTML output
-
-
-# HTML_OUTPUT = TODO
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `html' will be used as the default path.
-
-
-# HTML_FILE_EXTENSION =
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each generated HTML page (for example: .htm, .php, .asp). If it is left blank doxygen will generate files with .html extension.
-
-
-# HTML_HEADER = TODO
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for each generated HTML page. To get valid HTML the header file should contain at least a <HTML> and a <BODY> tag, but it is good idea to include the style sheet that is generated by doxygen as well. Minimal example:
-#
-# <HTML>
-# <HEAD>
-# <TITLE>My title</TITLE>
-# <LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
-# </HEAD>
-# <BODY BGCOLOR="#FFFFFF">
-#
-# If the tag is left blank doxygen will generate a standard header.
-#
-# The following commands have a special meaning inside the header: $title, $datetime, $date, $doxygenversion, $projectname, and $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-#
-# If CREATE_SUBDIRS is enabled, the command $relpath$ can be used to produce a relative path to the root of the HTML output directory, e.g. use $relpath$doxygen.css, to refer to the standard style sheet.
-#
-# See also section Doxygen usage for information on how to generate the default header that doxygen normally uses.
-
-
-# HTML_FOOTER =
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each generated HTML page. To get valid HTML the footer file should contain at least a </BODY> and a </HTML> tag. A minimal example:
-#
-# </BODY>
-# </HTML>
-#
-# If the tag is left blank doxygen will generate a standard footer.
-#
-# The following commands have a special meaning inside the footer: $title, $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-#
-# See also section Doxygen usage for information on how to generate the default footer that doxygen normally uses.
-
-
-# HTML_STYLESHEET =
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style sheet that is used by each HTML page. It can be used to fine-tune the look of the HTML output. If the tag is left blank doxygen will generate a default style sheet.
-#
-# See also section Doxygen usage for information on how to generate the style sheet that doxygen normally uses.
-
-
-# HTML_ALIGN_MEMBERS =
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, files or namespaces will be aligned in HTML using tables. If set to NO a bullet list will be used.
-#
-# Note: Setting this tag to NO will become obsolete in the future, since I only intent to support and test the aligned representation.
-
-
-GENERATE_HTMLHELP = @GENERATE_HTMLHELP@
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three additional HTML index files: index.hhp, index.hhc, and index.hhk. The index.hhp is a project file that can be read by Microsoft's HTML Help Workshop on Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output generated by doxygen into a single compressed HTML file (.chm). Compressed HTML files are now used as the Windows 98 help format, and will replace the old Windows help format (.hlp) on all Windows platforms in the future. Compressed HTML files also contain an index, a table of contents, and you can search for words in the documentation. The HTML workshop also contains a viewer for compressed HTML files.
-
-
-HHC_LOCATION = "@HTML_HELP_COMPILER@"
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can be used to specify the location (absolute path including file name) of the HTML help compiler (hhc.exe). If non empty doxygen will try to run the HTML help compiler on the generated index.hhp.
-
-
-# GENERATE_CHI =
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag controls if a separate .chi index file is generated (YES) or that it should be included in the master .chm file (NO).
-
-
-# BINARY_TOC =
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag controls whether a binary table of contents is generated (YES) or a normal table of contents (NO) in the .chm file.
-
-
-# TOC_EXPAND =
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to the table of contents of the HTML help documentation and to the tree view.
-
-
-# DISABLE_INDEX =
-# If you want full control over the layout of the generated HTML pages it might be necessary to disable the index and replace it with your own. The DISABLE_INDEX tag can be used to turn on/off the condensed index at top of each page. A value of NO (the default) enables the index and the value YES disables it.
-
-
-# ENUM_VALUES_PER_LINE =
-# This tag can be used to set the number of enum values (range [1..20]) that doxygen will group on one line in the generated HTML documentation.
-
-
-# GENERATE_TREEVIEW =
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be generated containing a tree-like index structure (just like the one that is generated for HTML Help). For this to work a browser that supports JavaScript and frames is required (for instance Mozilla 1.0+, Netscape 6.0+ or Internet explorer 5.0+ or Konqueror).
-
-
-# TREEVIEW_WIDTH =
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used to set the initial width (in pixels) of the frame in which the tree is shown.
-
-
-
-
-###############################################################
-# LaTeX related options
-###############################################################
-
-
-GENERATE_LATEX = NO
-# If the GENERATE_LATEX tag is set to YES (the default) doxygen will generate $\mbox{\LaTeX}$ output.
-
-
-# LATEX_OUTPUT =
-# The LATEX_OUTPUT tag is used to specify where the $\mbox{\LaTeX}$ docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `latex' will be used as the default path.
-
-
-# LATEX_CMD_NAME =
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
-
-
-# MAKEINDEX_CMD_NAME =
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate index for LaTeX. If left blank `makeindex' will be used as the default command name.
-
-
-# COMPACT_LATEX =
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact $\mbox{\LaTeX}$ documents. This may be useful for small projects and may help to save some trees in general.
-
-
-# PAPER_TYPE =
-# The PAPER_TYPE tag can be used to set the paper type that is used by the printer. Possible values are:
-#
-# * a4 (210 x 297 mm).
-# * a4wide (same as a4, but including the a4wide package).
-# * letter (8.5 x 11 inches).
-# * legal (8.5 x 14 inches).
-# * executive (7.25 x 10.5 inches)
-#
-# If left blank a4wide will be used.
-
-
-# EXTRA_PACKAGES =
-# The EXTRA_PACKAGES tag can be used to specify one or more $\mbox{\LaTeX}$ package names that should be included in the $\mbox{\LaTeX}$ output. To get the times font for instance you can specify
-#
-# EXTRA_PACKAGES = times
-#
-# If left blank no extra packages will be included.
-
-
-# LATEX_HEADER =
-# The LATEX_HEADER tag can be used to specify a personal $\mbox{\LaTeX}$ header for the generated $\mbox{\LaTeX}$ document. The header should contain everything until the first chapter.
-#
-# If it is left blank doxygen will generate a standard header. See section Doxygen usage for information on how to let doxygen write the default header to a separate file.
-#
-# Note:
-# Only use a user-defined header if you know what you are doing!
-#
-# The following commands have a special meaning inside the header: $title, $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
-
-
-# PDF_HYPERLINKS =
-# If the PDF_HYPERLINKS tag is set to YES, the $\mbox{\LaTeX}$ that is generated is prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will contain links (just like the HTML output) instead of page references. This makes the output suitable for online browsing using a PDF viewer.
-
-
-# USE_PDFLATEX =
-# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate the PDF file directly from the $\mbox{\LaTeX}$ files.
-
-
-# LATEX_BATCHMODE =
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode. command to the generated $\mbox{\LaTeX}$ files. This will instruct $\mbox{\LaTeX}$ to keep running if errors occur, instead of asking the user for help. This option is also used when generating formulas in HTML.
-
-
-# LATEX_HIDE_INDICES =
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not include the index chapters (such as File Index, Compound Index, etc.) in the output.
-
-
-
-
-###############################################################
-# RTF related options
-###############################################################
-
-
-# GENERATE_RTF =
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The RTF output is optimized for Word 97 and may not look too pretty with other readers/editors.
-
-
-# RTF_OUTPUT =
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank rtf will be used as the default path.
-
-
-# COMPACT_RTF =
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF documents. This may be useful for small projects and may help to save some trees in general.
-
-
-# RTF_HYPERLINKS =
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will contain hyperlink fields. The RTF file will contain links (just like the HTML output) instead of page references. This makes the output suitable for online browsing using Word or some other Word compatible reader that support those fields.
-#
-# note:
-# WordPad (write) and others do not support links.
-
-
-# RTF_STYLESHEET_FILE =
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config file, i.e. a series of assignments. You only have to provide replacements, missing definitions are set to their default value.
-#
-# See also section Doxygen usage for information on how to generate the default style sheet that doxygen normally uses.
-
-
-# RTF_EXTENSIONS_FILE =
-# Set optional variables used in the generation of an RTF document. Syntax is similar to doxygen's config file. A template extensions file can be generated using doxygen -e rtf extensionFile.
-
-
-
-
-###############################################################
-# Man page related options
-###############################################################
-
-
-# GENERATE_MAN =
-# If the GENERATE_MAN tag is set to YES (the default) doxygen will generate man pages for classes and files.
-
-
-# MAN_OUTPUT =
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `man' will be used as the default path. A directory man3 will be created inside the directory specified by MAN_OUTPUT.
-
-
-# MAN_EXTENSION =
-# The MAN_EXTENSION tag determines the extension that is added to the generated man pages (default is the subroutine's section .3)
-
-
-# MAN_LINKS =
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it will generate one additional man file for each entity documented in the real man page(s). These additional files only source the real man page, but without them the man command would be unable to find the correct page. The default is NO.
-
-
-
-
-###############################################################
-# XML related options
-###############################################################
-
-
-# GENERATE_XML =
-# If the GENERATE_XML tag is set to YES Doxygen will generate an XML file that captures the structure of the code including all documentation.
-
-
-# XML_OUTPUT =
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank xml will be used as the default path.
-
-
-# XML_SCHEMA =
-# The XML_SCHEMA tag can be used to specify an XML schema, which can be used by a validating XML parser to check the syntax of the XML files.
-
-
-# XML_DTD =
-# The XML_DTD tag can be used to specify an XML DTD, which can be used by a validating XML parser to check the syntax of the XML files.
-
-
-# XML_PROGRAMLISTING =
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will dump the program listings (including syntax highlighting and cross-referencing information) to the XML output. Note that enabling this will significantly increase the size of the XML output.
-
-
-
-
-###############################################################
-# AUTOGEN_DEF related options
-###############################################################
-
-
-# GENERATE_AUTOGEN_DEF =
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will generate an AutoGen Definitions (see http://autogen.sf.net) file that captures the structure of the code including all documentation. Note that this feature is still experimental and incomplete at the moment.
-
-
-
-
-###############################################################
-# PERLMOD related options
-###############################################################
-
-
-# GENERATE_PERLMOD =
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will generate a Perl module file that captures the structure of the code including all documentation. Note that this feature is still experimental and incomplete at the moment.
-
-
-# PERLMOD_LATEX =
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate the necessary Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI output from the Perl module output.
-
-
-# PERLMOD_PRETTY =
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely formatted so it can be parsed by a human reader. This is useful if you want to understand what is going on. On the other hand, if this tag is set to NO the size of the Perl module output will be much smaller and Perl will parse it just the same.
-
-
-# PERLMOD_MAKEVAR_PREFIX =
-# The names of the make variables in the generated doxyrules.make file are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful so different doxyrules.make files included by the same Makefile don't overwrite each other's variables.
-
-
-
-
-###############################################################
-# Preprocessor related options
-###############################################################
-
-
-ENABLE_PREPROCESSING = YES
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) doxygen will evaluate all C-preprocessor directives found in the sources and include files.
-
-
-MACRO_EXPANSION = NO
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names in the source code. If set to NO (the default) only conditional compilation will be performed. Macro expansion can be done in a controlled way by setting EXPAND_ONLY_PREDEF to YES.
-
-
-EXPAND_ONLY_PREDEF = NO
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then the macro expansion is limited to the macros specified with the PREDEFINED and EXPAND_AS_DEFINED tags.
-
-
-SEARCH_INCLUDES = YES
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files in the INCLUDE_PATH (see below) will be searched if a #include is found.
-
-
-INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/include
-# The INCLUDE_PATH tag can be used to specify one or more directories that contain include files that are not input files but should be processed by the preprocessor.
-
-
-# PREDEFINED =
-# The PREDEFINED tag can be used to specify one or more macro names that are defined before the preprocessor is started (similar to the -D option of gcc). The argument of the tag is a list of macros of the form: name or name=definition (no spaces). If the definition and the "=" are omitted, "=1" is assumed. To prevent a macro definition from being undefined via #undef or recursively expanded use the := operator instead of the = operator.
-
-
-# EXPAND_AS_DEFINED =
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this tag can be used to specify a list of macro names that should be expanded. The macro definition that is found in the sources will be used. Use the PREDEFINED tag if you want to use a different macro definition.
-
-
-# SKIP_FUNCTION_MACROS =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then doxygen's preprocessor will remove all function-like macros that are alone on a line, have an all uppercase name, and do not end with a semicolon. Such function macros are typically used for boiler-plate code, and will confuse the parser if not removed.
-
-
-
-
-###############################################################
-# External reference options
-###############################################################
-
-
-# TAGFILES =
-# The TAGFILES tag can be used to specify one or more tagfiles.
-#
-# See section Doxytag usage for more information about the usage of tag files.
-#
-# Optionally an initial location of the external documentation can be added for each tagfile. The format of a tag file without this location is as follows:
-#
-# TAGFILES = file1 file2 ...
-#
-# Adding location for the tag files is done as follows:
-#
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-#
-# where loc1 and loc2 can be relative or absolute paths or URLs, If a location is present for each tag, the installdox tool (see section Installdox usage for more information) does not have to be run to correct the links.
-#
-# Note:
-# Each tag file must have a unique name (where the name does not include the path) If a tag file is not located in the directory in which doxygen is run, you must also specify the path to the tagfile here.
-
-
-# GENERATE_TAGFILE =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a tag file that is based on the input files it reads. See section Doxytag usage for more information about the usage of tag files.
-
-
-# ALLEXTERNALS =
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the class index. If set to NO only the inherited external classes will be listed.
-
-
-# EXTERNAL_GROUPS =
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in the modules index. If set to NO, only the current project's groups will be listed.
-
-
-# PERL_PATH =
-# The PERL_PATH should be the absolute path and name of the perl script interpreter (i.e. the result of `which perl').
-
-
-
-
-###############################################################
-# Dot options
-###############################################################
-
-
-# CLASS_DIAGRAMS =
-# If the CLASS_DIAGRAMS tag is set to YES (the default) doxygen will generate a class diagram (in HTML and $\mbox{\LaTeX}$) for classes with base or super classes. Setting the tag to NO turns the diagrams off. Note that this option is superseded by the HAVE_DOT option below. This is only a fallback. It is recommended to install and use dot, since it yields more powerful graphs.
-
-
-HAVE_DOT = YES
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is available from the path. This tool is part of Graphviz, a graph visualization toolkit from AT&T and Lucent Bell Labs. The other options in this section have no effect if this option is set to NO (the default)
-
-
-CLASS_GRAPH = NO
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented class showing the direct and indirect inheritance relations. Setting this tag to YES will force the the CLASS_DIAGRAMS tag to NO.
-
-
-COLLABORATION_GRAPH = NO
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented class showing the direct and indirect implementation dependencies (inheritance, containment, and class references variables) of the class with other documented classes.
-
-
-# GROUP_GRAPHS
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen will generate a graph for groups, showing the direct groups dependencies.
-
-
-UML_LOOK = NO
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and collaboration diagrams in a style similar to the OMG's Unified Modeling Language.
-
-
-# TEMPLATE_RELATIONS =
-# If the TEMPLATE_RELATIONS and HAVE_DOT tags are set to YES then doxygen will show the relations between templates and their instances.
-
-
-HIDE_UNDOC_RELATIONS = NO
-# If set to YES, the inheritance and collaboration graphs will hide inheritance and usage relations if the target is undocumented or is not a class.
-
-
-INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented file showing the direct and indirect include dependencies of the file with other documented files.
-
-
-INCLUDED_BY_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented header file showing the documented files that directly or indirectly include this file.
-
-
-CALL_GRAPH = NO
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a call dependency graph for every global function or class method. Note that enabling this option will significantly increase the time of a run. So in most cases it will be better to enable call graphs for selected functions only using the \callgraph command.
-
-
-CALLER_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a caller dependency graph for every global function or class method. Note that enabling this option will significantly increase the time of a run. So in most cases it will be better to enable caller graphs for selected functions only using the \callergraph command.
-
-
-GRAPHICAL_HIERARCHY = YES
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen will graphical hierarchy of all classes instead of a textual one.
-
-
-# DIRECTORY_GRAPH
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT options are set to YES then doxygen will show the dependencies a directory has on other directories in a graphical way. The dependency relations are determined by the #include relations between the files in the directories.
-
-
-# DOT_IMAGE_FORMAT =
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images generated by dot. Possible values are gif, jpg, and png. If left blank png will be used.
-
-
-# DOT_PATH =
-# This tag can be used to specify the path where the dot tool can be found. If left blank, it is assumed the dot tool can be found on the path.
-
-
-# DOTFILE_DIRS =
-# This tag can be used to specify one or more directories that contain dot files that are included in the documentation (see the \dotfile command).
-
-
-# MAX_DOT_GRAPH_HEIGHT =
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height (in pixels) of the graphs generated by dot. If a graph becomes larger than this value, doxygen will try to truncate the graph, so that it fits within the specified constraint. Beware that most browsers cannot cope with very large images.
-
-
-# MAX_DOT_GRAPH_DEPTH =
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs generated by dot. A depth value of 3 means that only nodes reachable from the root by following a path via at most 3 edges will be shown. Nodes that lay further from the root node will be omitted. Note that setting this option to 1 or 2 may greatly reduce the computation time needed for large code bases. Also note that a graph may be further truncated if the graph's image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), the graph is not depth-constraint.
-
-
-# MAX_DOT_GRAPH_WIDTH =
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width (in pixels) of the graphs generated by dot. If a graph becomes larger than this value, doxygen will try to truncate the graph, so that it fits within the specified constraint. Beware that most browsers cannot cope with very large images.
-
-
-# DOT_TRANSPARENT =
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent background. This is disabled by default, which results in a white background. Warning: Depending on the platform used, enabling this option may lead to badly anti-aliased labels on the edges of a graph (i.e. they become hard to read).
-
-
-DOT_MULTI_TARGETS = YES
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output files in one run (i.e. multiple -o and -T options on the command line). This makes dot run faster, but since only newer versions of dot (>1.8.10) support this, this feature is disabled by default.
-
-
-GENERATE_LEGEND = YES
-# If the GENERATE_LEGEND tag is set to YES (the default) doxygen will generate a legend page explaining the meaning of the various boxes and arrows in the dot generated graphs.
-
-
-# DOT_CLEANUP =
-# If the DOT_CLEANUP tag is set to YES (the default) doxygen will remove the intermediate dot files that are used to generate the various graphs.
-
-
-
-
-###############################################################
-# Search engine options
-###############################################################
-
-
-# SEARCHENGINE =
-# The SEARCHENGINE tag specifies whether or not the HTML output should contain a search facility. Possible values are YES and NO. If set to YES, doxygen will produce a search index and a PHP script to search through the index. For this to work the documentation should be viewed via a web-server running PHP version 4.1.0 or higher. (See http://www.php.net/manual/en/installation.php for installation instructions).
+# Doxyfile for Doxygen 1.5.7
+
+# .qhp output
+GENERATE_QHP = @GENERATE_QHP@
+QHP_NAMESPACE = "io.github.uriparser"
+QHP_VIRTUAL_FOLDER = "uriparser-@PROJECT_VERSION@"
+
+# .qch output
+QCH_FILE = "../@PROJECT_NAME@-@PROJECT_VERSION@-doc.qch"
+QHG_LOCATION = "@QHG_LOCATION@"
+
+
+###############################################################
+# Project related options
+###############################################################
+
+
+PROJECT_NAME = "uriparser"
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by double-quotes) that should identify the project for which the documentation is generated. This name is used in the title of most generated pages and in a few other places.
+
+
+PROJECT_NUMBER = "@PROJECT_VERSION@"
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This could be handy for archiving the generated documentation or if some version control system is used.
+
+
+CHM_FILE = "..\@PROJECT_NAME@-@PROJECT_VERSION@.chm"
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can be used to specify the file name of the resulting .chm file. You can add a path in front of the file if the result should not be written to the html output directory.
+
+
+OUTPUT_DIRECTORY = .
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path into which the generated documentation will be written. If a relative path is entered, it will be relative to the location where doxygen was started. If left blank the current directory will be used.
+
+
+# CREATE_SUBDIRS =
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-directories (in 2 levels) under the output directory of each output format and will distribute the generated files over these directories. Enabling this option can be useful when feeding doxygen a huge amount of source files, where putting all generated files in the same directory would otherwise causes performance problems for the file system.
+
+
+# OUTPUT_LANGUAGE =
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all documentation generated by doxygen is written. Doxygen will use this information to generate all constant output in the proper language. The default language is English, other supported languages are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean, Lithuanian, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+
+# USE_WINDOWS_ENCODING =
+# This tag can be used to specify the encoding used in the generated output. The encoding is not always determined by the language that is chosen, but also whether or not the output is meant for Windows or non-Windows users. In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES forces the Windows encoding, (this is the default for the Windows binary), whereas setting the tag to NO uses a Unix-style encoding (the default for all platforms other than Windows).
+
+
+# BRIEF_MEMBER_DESC =
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) doxygen will include brief member descriptions after the members that are listed in the file and class documentation (similar to JavaDoc). Set to NO to disable this.
+
+
+# REPEAT_BRIEF =
+# If the REPEAT_BRIEF tag is set to YES (the default) doxygen will prepend the brief description of a member or function before the detailed description
+#
+# Note:
+# If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the brief descriptions will be completely suppressed.
+
+
+# ABBREVIATE_BRIEF =
+# This tag implements a quasi-intelligent brief description abbreviator that is used to form the text in various listings. Each string in this list, if found as the leading text of the brief description, will be stripped from the text and the result after processing the whole list, is used as the annotated text. Otherwise, the brief description is used as-is. If left blank, the following values are used ("\$name" is automatically replaced with the name of the entity): "The $name class" "The $name widget" "The $name file" "is" "provides" "specifies" "contains" "represents" "a" "an" "the".
+
+
+# ALWAYS_DETAILED_SEC =
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then doxygen will generate a detailed section even if there is only a brief description.
+
+
+# INLINE_INHERITED_MEMB =
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited members of a class in the documentation of that class as if those members were ordinary class members. Constructors, destructors and assignment operators of the base classes will not be shown.
+
+
+FULL_PATH_NAMES = NO
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path before files name in the file list and in the header files. If set to NO the shortest path that makes the file name unique will be used
+
+
+# STRIP_FROM_PATH =
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. Stripping is only done if one of the specified strings matches the left-hand part of the path. The tag can be used to show relative paths in the file list. If left blank the directory from which doxygen is run is used as the path to strip.
+
+
+# STRIP_FROM_INC_PATH =
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the path mentioned in the documentation of a class, which tells the reader which header file to include in order to use a class. If left blank only the name of the header file containing the class definition is used. Otherwise one should specify the include paths that are normally passed to the compiler using the -I flag.
+
+
+# CASE_SENSE_NAMES =
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file names in lower-case letters. If set to YES upper-case letters are also allowed. This is useful if you have classes or files whose names only differ in case and if your file system supports case sensitive file names. Windows users are advised to set this option to NO.
+
+
+# SHORT_NAMES =
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but less readable) file names. This can be useful is your file systems doesn't support long names like on DOS, Mac, or CD-ROM.
+
+
+# JAVADOC_AUTOBRIEF =
+# If the JAVADOC_AUTOBRIEF is set to YES then doxygen will interpret the first line (until the first dot) of a JavaDoc-style comment as the brief description. If set to NO (the default), the Javadoc-style will behave just like the Qt-style comments.
+
+
+BUILTIN_STL_SUPPORT = NO
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to include (a tag file for) the STL sources as input, then you should set this tag to YES in order to let doxygen match functions declarations and definitions whose arguments contain STL classes (e.g. func(std::string); v.s. func(std::string) {}). This also make the inheritance and collaboration diagrams that involve STL classes more complete and accurate.
+
+
+# DISTRIBUTE_GROUP_DOC =
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC tag is set to YES, then doxygen will reuse the documentation of the first member in the group (if any) for the other members of the group. By default all members of a group must be documented explicitly.
+
+
+# MULTILINE_CPP_IS_BRIEF =
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a multi-line C++ special comment block (i.e. a block of //! or /// comments) as a brief description. This used to be the default behaviour. The new default is to treat a multi-line C++ comment block as a detailed description. Set this tag to YES if you prefer the old behaviour instead. Note that setting this tag to YES also means that rational rose comments are not recognized any more.
+
+
+# INHERIT_DOCS =
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented member inherits the documentation from any documented member that it re-implements.
+
+
+# SEPARATE_MEMBER_PAGES =
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a new page for each member. If set to NO, the documentation of a member will be part of the file/class/namespace that contains it.
+
+
+# TAB_SIZE =
+# the TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen uses this value to replace tabs by spaces in code fragments.
+
+
+# ALIASES =
+# This tag can be used to specify a number of aliases that acts as commands in the documentation. An alias has the form
+#
+# name=value
+#
+# For example adding
+#
+# "sideeffect=\par Side Effects:\n"
+#
+# will allow you to put the command \sideeffect (or @sideeffect) in the documentation, which will result in a user-defined paragraph with heading "Side Effects:". You can put \n's in the value part of an alias to insert newlines.
+
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources only. Doxygen will then generate output that is more tailored for C. For instance, some of the names that are used will be different. The list of all members will be omitted, etc.
+
+
+# OPTIMIZE_OUTPUT_JAVA =
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or Python sources only. Doxygen will then generate output that is more tailored for that language. For instance, namespaces will be presented as packages, qualified scopes will look different, etc.
+
+
+# SUBGROUPING =
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of the same type (for instance a group of public functions) to be put as a subgroup of that type (e.g. under the Public Functions section). Set it to NO to prevent subgrouping. Alternatively, this can be done per class using the \nosubgrouping command.
+
+
+
+
+###############################################################
+# Build related options
+###############################################################
+
+
+EXTRACT_ALL = NO
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in documentation are documented, even if no documentation was available. Private class members and static file members will be hidden unless the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+#
+# Note:
+# This will also disable the warnings about undocumented members that are normally produced when WARNINGS is set to YES
+
+
+EXTRACT_PRIVATE = YES
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will be included in the documentation.
+
+
+EXTRACT_STATIC = YES
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be included in the documentation.
+
+
+# EXTRACT_LOCAL_CLASSES =
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined locally in source files will be included in the documentation. If set to NO only classes defined in header files are included. Does not have any effect for Java sources.
+
+
+# EXTRACT_LOCAL_METHODS =
+# This flag is only useful for Objective-C code. When set to YES local methods, which are defined in the implementation section but not in the interface are included in the documentation. If set to NO (the default) only methods in the interface are included.
+
+
+HIDE_UNDOC_MEMBERS = NO
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all undocumented members inside documented classes or files. If set to NO (the default) these members will be included in the various overviews, but no documentation section is generated. This option has no effect if EXTRACT_ALL is enabled.
+
+
+HIDE_UNDOC_CLASSES = NO
+# If the HIDE_UNDOC_CLASSESS tag is set to YES, doxygen will hide all undocumented classes. If set to NO (the default) these classes will be included in the various overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+
+HIDE_FRIEND_COMPOUNDS = NO
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend (class|struct|union) declarations. If set to NO (the default) these declarations will be included in the documentation.
+
+
+# HIDE_IN_BODY_DOCS =
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any documentation blocks found inside the body of a function. If set to NO (the default) these blocks will be appended to the function's detailed documentation block.
+
+
+# INTERNAL_DOCS =
+# The INTERNAL_DOCS tag determines if documentation that is typed after a \internal command is included. If the tag is set to NO (the default) then the documentation will be excluded. Set it to YES to include the internal documentation.
+
+
+HIDE_SCOPE_NAMES = YES
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then doxygen will show members with their full class and namespace scopes in the documentation. If set to YES the scope will be hidden.
+
+
+SHOW_INCLUDE_FILES = YES
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then doxygen will put a list of the files that are included by a file in the documentation of that file.
+
+
+# INLINE_INFO =
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] is inserted in the documentation for inline members.
+
+
+# SORT_MEMBER_DOCS =
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen will sort the (detailed) documentation of file and class members alphabetically by member name. If set to NO the members will appear in declaration order.
+
+
+# SORT_BRIEF_DOCS =
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief descriptions of file, namespace and class members alphabetically by member name. If set to NO (the default) the members will appear in declaration order.
+
+
+# GENERATE_DEPRECATEDLIST =
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+
+# GENERATE_TODOLIST =
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo list. This list is created by putting \todo commands in the documentation.
+
+
+# GENERATE_TESTLIST =
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test list. This list is created by putting \test commands in the documentation.
+
+
+# GENERATE_BUGLIST =
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug list. This list is created by putting \bug commands in the documentation.
+
+
+# ENABLED_SECTIONS =
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation sections, marked by \if <section-label> ... \endif and \cond <section-label> ... \endcond blocks.
+
+
+# MAX_INITIALIZER_LINES =
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the initial value of a variable or define can be. If the initializer consists of more lines than specified here it will be hidden. Use a value of 0 to hide initializers completely. The appearance of the value of individual variables and defines can be controlled using \showinitializer or \hideinitializer command in the documentation.
+
+
+SHOW_USED_FILES = YES
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at the bottom of the documentation of classes and structs. If set to YES the list will mention the files that were used to generate the documentation.
+
+
+
+
+###############################################################
+# Options related to warning and progress messages
+###############################################################
+
+
+QUIET = YES
+# The QUIET tag can be used to turn on/off the messages that are generated to standard output by doxygen. Possible values are YES and NO, where YES implies that the messages are off. If left blank NO is used.
+
+
+# WARNINGS =
+# The WARNINGS tag can be used to turn on/off the warning messages that are generated to standard error by doxygen. Possible values are YES and NO, where YES implies that the warnings are on. If left blank NO is used.
+#
+# Tip: Turn warnings on while writing the documentation.
+
+
+WARN_IF_UNDOCUMENTED = YES
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+
+
+WARN_IF_DOC_ERROR = YES
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for potential errors in the documentation, such as not documenting some parameters in a documented function, or documenting parameters that don't exist or using markup commands wrongly.
+
+
+WARN_NO_PARAMDOC = YES
+# This WARN_NO_PARAMDOC option can be abled to get warnings for functions that are documented, but have no documentation for their parameters or return value. If set to NO (the default) doxygen will only warn about wrong or incomplete parameter documentation, but not about the absence of documentation.
+
+
+WARN_FORMAT = "WARNING: $text ($line, $file)"
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen can produce. The string should contain the $file, $line, and $text tags, which will be replaced by the file and line number from which the warning originated and the warning text.
+
+
+# WARN_LOGFILE =
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error messages should be written. If left blank the output is written to stderr.
+
+
+
+
+###############################################################
+# Input related options
+###############################################################
+
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@/doc/Mainpage.txt
+# The INPUT tag is used to specify the files and/or directories that contain documented source files. You may enter file names like myfile.cpp or directories like /usr/src/myproject. Separate the files or directories with spaces.
+#
+# Note: If this tag is empty the current directory is searched.
+
+
+# FILE_PATTERNS =
+# If the value of the INPUT tag contains directories, you can use the FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and *.h ) to filter out the source-files in the directories. If left blank the following patterns are tested: .c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp .h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+
+# FILE_VERSION_FILTER =
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that doxygen should invoke to get the current version for each file (typically from the version control system). Doxygen will invoke the program by executing (via popen()) the command command input-file, where command is the value of the FILE_VERSION_FILTER tag, and input-file is the name of an input file provided by doxygen. Whatever the program writes to standard output is used as the file version.
+#
+# Example of using a shell script as a filter for Unix:
+#
+# FILE_VERSION_FILTER = "/bin/sh versionfilter.sh"
+#
+# Example shell script for CVS:
+#
+# #!/bin/sh
+# cvs status $1 | sed -n 's/^[ \]*Working revision:[ \t]*\([0-9][0-9\.]*\).*/\1/p'
+#
+# Example shell script for Subversion:
+#
+# #!/bin/sh
+# svn stat -v $1 | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p'
+#
+# Example filter for ClearCase:
+#
+# FILE_VERSION_INFO = "cleartool desc -fmt \%Vn"
+
+
+RECURSIVE = YES
+# The RECURSIVE tag can be used to specify whether or not subdirectories should be searched for input files as well. Possible values are YES and NO. If left blank NO is used.
+
+
+# EXCLUDE =
+# The EXCLUDE tag can be used to specify files and/or directories that should excluded from the INPUT source files. This way you can easily exclude a subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+
+# EXCLUDE_SYMLINKS =
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+
+# EXCLUDE_PATTERNS =
+# If the value of the INPUT tag contains directories, you can use the EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude certain files from those directories.
+
+# Note that the wildcards are matched against the file with absolute path, so to exclude all test directories use the pattern */test/*
+
+
+# EXAMPLE_PATH =
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories that contain example code fragments that are included (see the \include command in section \include).
+
+
+# EXAMPLE_RECURSIVE =
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be searched for input files to be used with the \include or \dontinclude commands irrespective of the value of the RECURSIVE tag. Possible values are YES and NO. If left blank NO is used.
+
+
+# EXAMPLE_PATTERNS =
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and *.h) to filter out the source-files in the directories. If left blank all files are included.
+
+
+# IMAGE_PATH =
+# The IMAGE_PATH tag can be used to specify one or more files or directories that contain images that are to be included in the documentation (see the \image command).
+
+
+INPUT_FILTER = "bash @CMAKE_CURRENT_SOURCE_DIR@/doc/preprocess.sh"
+# The INPUT_FILTER tag can be used to specify a program that doxygen should invoke to filter for each input file. Doxygen will invoke the filter program by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the name of an input file. Doxygen will then use the output that the filter program writes to standard output.
+
+
+# FILTER_PATTERNS =
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern basis. Doxygen will compare the file name with each pattern and apply the filter if there is a match. The filters are a list of the form: pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER is applied to all files.
+
+
+# FILTER_SOURCE_FILES =
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using INPUT_FILTER ) will also be used to filter the input files that are used for producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+
+
+
+###############################################################
+# Source browsing related options
+###############################################################
+
+
+# SOURCE_BROWSER =
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be generated. Documented entities will be cross-referenced with these sources.
+
+
+# INLINE_SOURCES =
+# Setting the INLINE_SOURCES tag to YES will include the body of functions, classes and enums directly into the documentation.
+
+
+STRIP_CODE_COMMENTS = YES
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct doxygen to hide any special comment blocks from generated source code fragments. Normal C and C++ comments will always remain visible.
+
+
+# REFERENCED_BY_RELATION =
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) then for each documented function all documented functions referencing it will be listed.
+
+
+# REFERENCES_RELATION =
+# If the REFERENCES_RELATION tag is set to YES (the default) then for each documented function all documented entities called/used by that function will be listed.
+
+
+# REFERENCES_LINK_SOURCE =
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) and SOURCE_BROWSER tag is set to YES, then the hyperlinks from functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will link to the documentation.
+
+
+VERBATIM_HEADERS = NO
+# If the VERBATIM_HEADERS tag is set the YES (the default) then doxygen will generate a verbatim copy of the header file for each class for which an include is specified. Set to NO to disable this.
+#
+# See also:
+# Section \class.
+
+
+# USE_HTAGS =
+# If the USE_HTAGS tag is set to YES then the references to source code will point to the HTML generated by the htags(1) tool instead of doxygen built-in source browser. The htags tool is part of GNU's global source tagging system (see http://www.gnu.org/software/global/global.html). The use it do the following:
+#
+# 1. Install the latest version of global (i.e. 4.8.6 or better)
+# 2. Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# 3. Make sure the INPUT points to the root of the source tree
+# 4. Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to source code will now point to the output of htags.
+
+
+
+
+###############################################################
+# Alphabetical index options
+###############################################################
+
+
+# COLS_IN_ALPHA_INDEX =
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in which this list will be split (can be a number in the range [1..20])
+
+
+# IGNORE_PREFIX =
+# In case all classes in a project start with a common prefix, all classes will be put under the same header in the alphabetical index. The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) that should be ignored while generating the index headers.
+
+
+
+
+###############################################################
+# HTML related options
+###############################################################
+
+
+GENERATE_HTML = YES
+# If the GENERATE_HTML tag is set to YES (the default) doxygen will generate HTML output
+
+
+# HTML_OUTPUT = TODO
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `html' will be used as the default path.
+
+
+# HTML_FILE_EXTENSION =
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each generated HTML page (for example: .htm, .php, .asp). If it is left blank doxygen will generate files with .html extension.
+
+
+# HTML_HEADER = TODO
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for each generated HTML page. To get valid HTML the header file should contain at least a <HTML> and a <BODY> tag, but it is good idea to include the style sheet that is generated by doxygen as well. Minimal example:
+#
+# <HTML>
+# <HEAD>
+# <TITLE>My title</TITLE>
+# <LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
+# </HEAD>
+# <BODY BGCOLOR="#FFFFFF">
+#
+# If the tag is left blank doxygen will generate a standard header.
+#
+# The following commands have a special meaning inside the header: $title, $datetime, $date, $doxygenversion, $projectname, and $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+#
+# If CREATE_SUBDIRS is enabled, the command $relpath$ can be used to produce a relative path to the root of the HTML output directory, e.g. use $relpath$doxygen.css, to refer to the standard style sheet.
+#
+# See also section Doxygen usage for information on how to generate the default header that doxygen normally uses.
+
+
+# HTML_FOOTER =
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each generated HTML page. To get valid HTML the footer file should contain at least a </BODY> and a </HTML> tag. A minimal example:
+#
+# </BODY>
+# </HTML>
+#
+# If the tag is left blank doxygen will generate a standard footer.
+#
+# The following commands have a special meaning inside the footer: $title, $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+#
+# See also section Doxygen usage for information on how to generate the default footer that doxygen normally uses.
+
+
+# HTML_STYLESHEET =
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style sheet that is used by each HTML page. It can be used to fine-tune the look of the HTML output. If the tag is left blank doxygen will generate a default style sheet.
+#
+# See also section Doxygen usage for information on how to generate the style sheet that doxygen normally uses.
+
+
+# HTML_ALIGN_MEMBERS =
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, files or namespaces will be aligned in HTML using tables. If set to NO a bullet list will be used.
+#
+# Note: Setting this tag to NO will become obsolete in the future, since I only intent to support and test the aligned representation.
+
+
+GENERATE_HTMLHELP = @GENERATE_HTMLHELP@
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three additional HTML index files: index.hhp, index.hhc, and index.hhk. The index.hhp is a project file that can be read by Microsoft's HTML Help Workshop on Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output generated by doxygen into a single compressed HTML file (.chm). Compressed HTML files are now used as the Windows 98 help format, and will replace the old Windows help format (.hlp) on all Windows platforms in the future. Compressed HTML files also contain an index, a table of contents, and you can search for words in the documentation. The HTML workshop also contains a viewer for compressed HTML files.
+
+
+HHC_LOCATION = "@HTML_HELP_COMPILER@"
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can be used to specify the location (absolute path including file name) of the HTML help compiler (hhc.exe). If non empty doxygen will try to run the HTML help compiler on the generated index.hhp.
+
+
+# GENERATE_CHI =
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag controls if a separate .chi index file is generated (YES) or that it should be included in the master .chm file (NO).
+
+
+# BINARY_TOC =
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag controls whether a binary table of contents is generated (YES) or a normal table of contents (NO) in the .chm file.
+
+
+# TOC_EXPAND =
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to the table of contents of the HTML help documentation and to the tree view.
+
+
+# DISABLE_INDEX =
+# If you want full control over the layout of the generated HTML pages it might be necessary to disable the index and replace it with your own. The DISABLE_INDEX tag can be used to turn on/off the condensed index at top of each page. A value of NO (the default) enables the index and the value YES disables it.
+
+
+# ENUM_VALUES_PER_LINE =
+# This tag can be used to set the number of enum values (range [1..20]) that doxygen will group on one line in the generated HTML documentation.
+
+
+# GENERATE_TREEVIEW =
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be generated containing a tree-like index structure (just like the one that is generated for HTML Help). For this to work a browser that supports JavaScript and frames is required (for instance Mozilla 1.0+, Netscape 6.0+ or Internet explorer 5.0+ or Konqueror).
+
+
+# TREEVIEW_WIDTH =
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used to set the initial width (in pixels) of the frame in which the tree is shown.
+
+
+
+
+###############################################################
+# LaTeX related options
+###############################################################
+
+
+GENERATE_LATEX = NO
+# If the GENERATE_LATEX tag is set to YES (the default) doxygen will generate $\mbox{\LaTeX}$ output.
+
+
+# LATEX_OUTPUT =
+# The LATEX_OUTPUT tag is used to specify where the $\mbox{\LaTeX}$ docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `latex' will be used as the default path.
+
+
+# LATEX_CMD_NAME =
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+
+# MAKEINDEX_CMD_NAME =
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate index for LaTeX. If left blank `makeindex' will be used as the default command name.
+
+
+# COMPACT_LATEX =
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact $\mbox{\LaTeX}$ documents. This may be useful for small projects and may help to save some trees in general.
+
+
+# PAPER_TYPE =
+# The PAPER_TYPE tag can be used to set the paper type that is used by the printer. Possible values are:
+#
+# * a4 (210 x 297 mm).
+# * a4wide (same as a4, but including the a4wide package).
+# * letter (8.5 x 11 inches).
+# * legal (8.5 x 14 inches).
+# * executive (7.25 x 10.5 inches)
+#
+# If left blank a4wide will be used.
+
+
+# EXTRA_PACKAGES =
+# The EXTRA_PACKAGES tag can be used to specify one or more $\mbox{\LaTeX}$ package names that should be included in the $\mbox{\LaTeX}$ output. To get the times font for instance you can specify
+#
+# EXTRA_PACKAGES = times
+#
+# If left blank no extra packages will be included.
+
+
+# LATEX_HEADER =
+# The LATEX_HEADER tag can be used to specify a personal $\mbox{\LaTeX}$ header for the generated $\mbox{\LaTeX}$ document. The header should contain everything until the first chapter.
+#
+# If it is left blank doxygen will generate a standard header. See section Doxygen usage for information on how to let doxygen write the default header to a separate file.
+#
+# Note:
+# Only use a user-defined header if you know what you are doing!
+#
+# The following commands have a special meaning inside the header: $title, $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will replace them by respectively the title of the page, the current date and time, only the current date, the version number of doxygen, the project name (see PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+
+
+# PDF_HYPERLINKS =
+# If the PDF_HYPERLINKS tag is set to YES, the $\mbox{\LaTeX}$ that is generated is prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will contain links (just like the HTML output) instead of page references. This makes the output suitable for online browsing using a PDF viewer.
+
+
+# USE_PDFLATEX =
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate the PDF file directly from the $\mbox{\LaTeX}$ files.
+
+
+# LATEX_BATCHMODE =
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode. command to the generated $\mbox{\LaTeX}$ files. This will instruct $\mbox{\LaTeX}$ to keep running if errors occur, instead of asking the user for help. This option is also used when generating formulas in HTML.
+
+
+# LATEX_HIDE_INDICES =
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not include the index chapters (such as File Index, Compound Index, etc.) in the output.
+
+
+
+
+###############################################################
+# RTF related options
+###############################################################
+
+
+# GENERATE_RTF =
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The RTF output is optimized for Word 97 and may not look too pretty with other readers/editors.
+
+
+# RTF_OUTPUT =
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank rtf will be used as the default path.
+
+
+# COMPACT_RTF =
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF documents. This may be useful for small projects and may help to save some trees in general.
+
+
+# RTF_HYPERLINKS =
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will contain hyperlink fields. The RTF file will contain links (just like the HTML output) instead of page references. This makes the output suitable for online browsing using Word or some other Word compatible reader that support those fields.
+#
+# note:
+# WordPad (write) and others do not support links.
+
+
+# RTF_STYLESHEET_FILE =
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config file, i.e. a series of assignments. You only have to provide replacements, missing definitions are set to their default value.
+#
+# See also section Doxygen usage for information on how to generate the default style sheet that doxygen normally uses.
+
+
+# RTF_EXTENSIONS_FILE =
+# Set optional variables used in the generation of an RTF document. Syntax is similar to doxygen's config file. A template extensions file can be generated using doxygen -e rtf extensionFile.
+
+
+
+
+###############################################################
+# Man page related options
+###############################################################
+
+
+# GENERATE_MAN =
+# If the GENERATE_MAN tag is set to YES (the default) doxygen will generate man pages for classes and files.
+
+
+# MAN_OUTPUT =
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank `man' will be used as the default path. A directory man3 will be created inside the directory specified by MAN_OUTPUT.
+
+
+# MAN_EXTENSION =
+# The MAN_EXTENSION tag determines the extension that is added to the generated man pages (default is the subroutine's section .3)
+
+
+# MAN_LINKS =
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it will generate one additional man file for each entity documented in the real man page(s). These additional files only source the real man page, but without them the man command would be unable to find the correct page. The default is NO.
+
+
+
+
+###############################################################
+# XML related options
+###############################################################
+
+
+# GENERATE_XML =
+# If the GENERATE_XML tag is set to YES Doxygen will generate an XML file that captures the structure of the code including all documentation.
+
+
+# XML_OUTPUT =
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put in front of it. If left blank xml will be used as the default path.
+
+
+# XML_SCHEMA =
+# The XML_SCHEMA tag can be used to specify an XML schema, which can be used by a validating XML parser to check the syntax of the XML files.
+
+
+# XML_DTD =
+# The XML_DTD tag can be used to specify an XML DTD, which can be used by a validating XML parser to check the syntax of the XML files.
+
+
+# XML_PROGRAMLISTING =
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will dump the program listings (including syntax highlighting and cross-referencing information) to the XML output. Note that enabling this will significantly increase the size of the XML output.
+
+
+
+
+###############################################################
+# AUTOGEN_DEF related options
+###############################################################
+
+
+# GENERATE_AUTOGEN_DEF =
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will generate an AutoGen Definitions (see http://autogen.sf.net) file that captures the structure of the code including all documentation. Note that this feature is still experimental and incomplete at the moment.
+
+
+
+
+###############################################################
+# PERLMOD related options
+###############################################################
+
+
+# GENERATE_PERLMOD =
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will generate a Perl module file that captures the structure of the code including all documentation. Note that this feature is still experimental and incomplete at the moment.
+
+
+# PERLMOD_LATEX =
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate the necessary Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI output from the Perl module output.
+
+
+# PERLMOD_PRETTY =
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely formatted so it can be parsed by a human reader. This is useful if you want to understand what is going on. On the other hand, if this tag is set to NO the size of the Perl module output will be much smaller and Perl will parse it just the same.
+
+
+# PERLMOD_MAKEVAR_PREFIX =
+# The names of the make variables in the generated doxyrules.make file are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful so different doxyrules.make files included by the same Makefile don't overwrite each other's variables.
+
+
+
+
+###############################################################
+# Preprocessor related options
+###############################################################
+
+
+ENABLE_PREPROCESSING = YES
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) doxygen will evaluate all C-preprocessor directives found in the sources and include files.
+
+
+MACRO_EXPANSION = NO
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names in the source code. If set to NO (the default) only conditional compilation will be performed. Macro expansion can be done in a controlled way by setting EXPAND_ONLY_PREDEF to YES.
+
+
+EXPAND_ONLY_PREDEF = NO
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then the macro expansion is limited to the macros specified with the PREDEFINED and EXPAND_AS_DEFINED tags.
+
+
+SEARCH_INCLUDES = YES
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files in the INCLUDE_PATH (see below) will be searched if a #include is found.
+
+
+INCLUDE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/include
+# The INCLUDE_PATH tag can be used to specify one or more directories that contain include files that are not input files but should be processed by the preprocessor.
+
+
+# PREDEFINED =
+# The PREDEFINED tag can be used to specify one or more macro names that are defined before the preprocessor is started (similar to the -D option of gcc). The argument of the tag is a list of macros of the form: name or name=definition (no spaces). If the definition and the "=" are omitted, "=1" is assumed. To prevent a macro definition from being undefined via #undef or recursively expanded use the := operator instead of the = operator.
+
+
+# EXPAND_AS_DEFINED =
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this tag can be used to specify a list of macro names that should be expanded. The macro definition that is found in the sources will be used. Use the PREDEFINED tag if you want to use a different macro definition.
+
+
+# SKIP_FUNCTION_MACROS =
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then doxygen's preprocessor will remove all function-like macros that are alone on a line, have an all uppercase name, and do not end with a semicolon. Such function macros are typically used for boiler-plate code, and will confuse the parser if not removed.
+
+
+
+
+###############################################################
+# External reference options
+###############################################################
+
+
+# TAGFILES =
+# The TAGFILES tag can be used to specify one or more tagfiles.
+#
+# See section Doxytag usage for more information about the usage of tag files.
+#
+# Optionally an initial location of the external documentation can be added for each tagfile. The format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+#
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+#
+# where loc1 and loc2 can be relative or absolute paths or URLs, If a location is present for each tag, the installdox tool (see section Installdox usage for more information) does not have to be run to correct the links.
+#
+# Note:
+# Each tag file must have a unique name (where the name does not include the path) If a tag file is not located in the directory in which doxygen is run, you must also specify the path to the tagfile here.
+
+
+# GENERATE_TAGFILE =
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a tag file that is based on the input files it reads. See section Doxytag usage for more information about the usage of tag files.
+
+
+# ALLEXTERNALS =
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the class index. If set to NO only the inherited external classes will be listed.
+
+
+# EXTERNAL_GROUPS =
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in the modules index. If set to NO, only the current project's groups will be listed.
+
+
+# PERL_PATH =
+# The PERL_PATH should be the absolute path and name of the perl script interpreter (i.e. the result of `which perl').
+
+
+
+
+###############################################################
+# Dot options
+###############################################################
+
+
+# CLASS_DIAGRAMS =
+# If the CLASS_DIAGRAMS tag is set to YES (the default) doxygen will generate a class diagram (in HTML and $\mbox{\LaTeX}$) for classes with base or super classes. Setting the tag to NO turns the diagrams off. Note that this option is superseded by the HAVE_DOT option below. This is only a fallback. It is recommended to install and use dot, since it yields more powerful graphs.
+
+
+HAVE_DOT = YES
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is available from the path. This tool is part of Graphviz, a graph visualization toolkit from AT&T and Lucent Bell Labs. The other options in this section have no effect if this option is set to NO (the default)
+
+
+CLASS_GRAPH = NO
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented class showing the direct and indirect inheritance relations. Setting this tag to YES will force the the CLASS_DIAGRAMS tag to NO.
+
+
+COLLABORATION_GRAPH = NO
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented class showing the direct and indirect implementation dependencies (inheritance, containment, and class references variables) of the class with other documented classes.
+
+
+# GROUP_GRAPHS
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen will generate a graph for groups, showing the direct groups dependencies.
+
+
+UML_LOOK = NO
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and collaboration diagrams in a style similar to the OMG's Unified Modeling Language.
+
+
+# TEMPLATE_RELATIONS =
+# If the TEMPLATE_RELATIONS and HAVE_DOT tags are set to YES then doxygen will show the relations between templates and their instances.
+
+
+HIDE_UNDOC_RELATIONS = NO
+# If set to YES, the inheritance and collaboration graphs will hide inheritance and usage relations if the target is undocumented or is not a class.
+
+
+INCLUDE_GRAPH = YES
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented file showing the direct and indirect include dependencies of the file with other documented files.
+
+
+INCLUDED_BY_GRAPH = YES
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to YES then doxygen will generate a graph for each documented header file showing the documented files that directly or indirectly include this file.
+
+
+CALL_GRAPH = NO
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a call dependency graph for every global function or class method. Note that enabling this option will significantly increase the time of a run. So in most cases it will be better to enable call graphs for selected functions only using the \callgraph command.
+
+
+CALLER_GRAPH = NO
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will generate a caller dependency graph for every global function or class method. Note that enabling this option will significantly increase the time of a run. So in most cases it will be better to enable caller graphs for selected functions only using the \callergraph command.
+
+
+GRAPHICAL_HIERARCHY = YES
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen will graphical hierarchy of all classes instead of a textual one.
+
+
+# DIRECTORY_GRAPH
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT options are set to YES then doxygen will show the dependencies a directory has on other directories in a graphical way. The dependency relations are determined by the #include relations between the files in the directories.
+
+
+# DOT_IMAGE_FORMAT =
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images generated by dot. Possible values are gif, jpg, and png. If left blank png will be used.
+
+
+# DOT_PATH =
+# This tag can be used to specify the path where the dot tool can be found. If left blank, it is assumed the dot tool can be found on the path.
+
+
+# DOTFILE_DIRS =
+# This tag can be used to specify one or more directories that contain dot files that are included in the documentation (see the \dotfile command).
+
+
+# MAX_DOT_GRAPH_HEIGHT =
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height (in pixels) of the graphs generated by dot. If a graph becomes larger than this value, doxygen will try to truncate the graph, so that it fits within the specified constraint. Beware that most browsers cannot cope with very large images.
+
+
+# MAX_DOT_GRAPH_DEPTH =
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs generated by dot. A depth value of 3 means that only nodes reachable from the root by following a path via at most 3 edges will be shown. Nodes that lay further from the root node will be omitted. Note that setting this option to 1 or 2 may greatly reduce the computation time needed for large code bases. Also note that a graph may be further truncated if the graph's image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), the graph is not depth-constraint.
+
+
+# MAX_DOT_GRAPH_WIDTH =
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width (in pixels) of the graphs generated by dot. If a graph becomes larger than this value, doxygen will try to truncate the graph, so that it fits within the specified constraint. Beware that most browsers cannot cope with very large images.
+
+
+# DOT_TRANSPARENT =
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent background. This is disabled by default, which results in a white background. Warning: Depending on the platform used, enabling this option may lead to badly anti-aliased labels on the edges of a graph (i.e. they become hard to read).
+
+
+DOT_MULTI_TARGETS = YES
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output files in one run (i.e. multiple -o and -T options on the command line). This makes dot run faster, but since only newer versions of dot (>1.8.10) support this, this feature is disabled by default.
+
+
+GENERATE_LEGEND = YES
+# If the GENERATE_LEGEND tag is set to YES (the default) doxygen will generate a legend page explaining the meaning of the various boxes and arrows in the dot generated graphs.
+
+
+# DOT_CLEANUP =
+# If the DOT_CLEANUP tag is set to YES (the default) doxygen will remove the intermediate dot files that are used to generate the various graphs.
+
+
+
+
+###############################################################
+# Search engine options
+###############################################################
+
+
+# SEARCHENGINE =
+# The SEARCHENGINE tag specifies whether or not the HTML output should contain a search facility. Possible values are YES and NO. If set to YES, doxygen will produce a search index and a PHP script to search through the index. For this to work the documentation should be viewed via a web-server running PHP version 4.1.0 or higher. (See http://www.php.net/manual/en/installation.php for installation instructions).
diff --git a/doc/Mainpage.txt b/doc/Mainpage.txt
index 19d8115..a65ac36 100644
--- a/doc/Mainpage.txt
+++ b/doc/Mainpage.txt
@@ -27,19 +27,19 @@
* Parsing a URI with uriparser looks like this:
*
* @code
- * UriUriA uri;
- * const char * const uriString = "file:///home/user/song.mp3";
- * const char * errorPos;
- *
- * if (uriParseSingleUriA(&uri, uriString, &errorPos) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure (no need to call uriFreeUriMembersA) *COMMENT_HACK/
- * ...
- * return ...;
- * }
- *
- * /COMMENT_HACK* Success *COMMENT_HACK/
- * ...
- * uriFreeUriMembersA(&uri);
+ * UriUriA uri;
+ * const char * const uriString = "file:///home/user/song.mp3";
+ * const char * errorPos;
+ *
+ * if (uriParseSingleUriA(&uri, uriString, &errorPos) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure (no need to call uriFreeUriMembersA) *COMMENT_HACK/
+ * ...
+ * return ...;
+ * }
+ *
+ * /COMMENT_HACK* Success *COMMENT_HACK/
+ * ...
+ * uriFreeUriMembersA(&uri);
* @endcode
*
* While the URI object (::UriUriA) holds information about the recognized
@@ -47,35 +47,35 @@
* <c>errorPos</c> points to the first character starting invalid syntax.
*
* @subsection recomposition Recomposing URIs (from object back to string)
- * According to <a href="http://tools.ietf.org/html/rfc3986#section-5.3" target="_blank">RFC 3986</a>
+ * According to <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.3" target="_blank">RFC 3986</a>
* gluing parts of a URI together to form a string is called recomposition.
* Before we can recompose a URI object we have to know how much
* space the resulting string will take:
*
* @code
- * UriUriA uri;
- * char * uriString;
- * int charsRequired;
- * ...
- * if (uriToStringCharsRequiredA(&uri, &charsRequired) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * charsRequired++;
+ * UriUriA uri;
+ * char * uriString;
+ * int charsRequired;
+ * ...
+ * if (uriToStringCharsRequiredA(&uri, &charsRequired) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * charsRequired++;
* @endcode
*
* Now we can tell uriToStringA() to write the string to a given buffer:
*
* @code
- * uriString = malloc(charsRequired * sizeof(char));
- * if (uriString == NULL) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * if (uriToStringA(uriString, &uri, charsRequired, NULL) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
+ * uriString = malloc(charsRequired * sizeof(char));
+ * if (uriString == NULL) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * if (uriToStringA(uriString, &uri, charsRequired, NULL) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
* @endcode
*
* @remarks
@@ -87,25 +87,25 @@
*
*
* @subsection resolution Resolving References
- * <a href="http://tools.ietf.org/html/rfc3986#section-5" target="_blank">Reference Resolution</a>
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5" target="_blank">Reference Resolution</a>
* is the process of turning a (relative) URI reference into an absolute URI by applying a base
* URI to it. In code it looks like this:
*
* @code
- * UriUriA absoluteDest;
- * UriUriA relativeSource;
- * UriUriA absoluteBase;
- * ...
- * /COMMENT_HACK* relativeSource holds "../TWO" now *COMMENT_HACK/
- * /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
- * if (uriAddBaseUriA(&absoluteDest, &relativeSource, &absoluteBase) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * uriFreeUriMembersA(&absoluteDest);
- * ...
- * }
- * /COMMENT_HACK* absoluteDest holds "file:///one/TWO" now *COMMENT_HACK/
- * ...
- * uriFreeUriMembersA(&absoluteDest);
+ * UriUriA absoluteDest;
+ * UriUriA relativeSource;
+ * UriUriA absoluteBase;
+ * ...
+ * /COMMENT_HACK* relativeSource holds "../TWO" now *COMMENT_HACK/
+ * /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
+ * if (uriAddBaseUriA(&absoluteDest, &relativeSource, &absoluteBase) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * uriFreeUriMembersA(&absoluteDest);
+ * ...
+ * }
+ * /COMMENT_HACK* absoluteDest holds "file:///one/TWO" now *COMMENT_HACK/
+ * ...
+ * uriFreeUriMembersA(&absoluteDest);
* @endcode
*
* @remarks
@@ -120,20 +120,20 @@
* carry a scheme
*
* @code
- * UriUriA dest;
- * UriUriA absoluteSource;
- * UriUriA absoluteBase;
- * ...
- * /COMMENT_HACK* absoluteSource holds "file:///one/TWO" now *COMMENT_HACK/
- * /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
- * if (uriRemoveBaseUriA(&dest, &absoluteSource, &absoluteBase, URI_FALSE) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * uriFreeUriMembersA(&dest);
- * ...
- * }
- * /COMMENT_HACK* dest holds "../TWO" now *COMMENT_HACK/
- * ...
- * uriFreeUriMembersA(&dest);
+ * UriUriA dest;
+ * UriUriA absoluteSource;
+ * UriUriA absoluteBase;
+ * ...
+ * /COMMENT_HACK* absoluteSource holds "file:///one/TWO" now *COMMENT_HACK/
+ * /COMMENT_HACK* absoluteBase holds "file:///one/two/three" now *COMMENT_HACK/
+ * if (uriRemoveBaseUriA(&dest, &absoluteSource, &absoluteBase, URI_FALSE) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * uriFreeUriMembersA(&dest);
+ * ...
+ * }
+ * /COMMENT_HACK* dest holds "../TWO" now *COMMENT_HACK/
+ * ...
+ * uriFreeUriMembersA(&dest);
* @endcode
*
* The fourth parameter is the domain root mode. With <c>URI_FALSE</c> as above this will produce
@@ -146,17 +146,17 @@
* i.e. without creating an URI object.
*
* @code
- * const char * const absFilename = "E:\\Documents and Settings";
- * const int bytesNeeded = 8 + 3 * strlen(absFilename) + 1;
- * char * absUri = malloc(bytesNeeded * sizeof(char));
- * if (uriWindowsFilenameToUriStringA(absFilename, absUri) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * free(absUri);
- * ...
- * }
- * /COMMENT_HACK* absUri is "file:///E:/Documents%20and%20Settings" now *COMMENT_HACK/
- * ...
- * free(absUri);
+ * const char * const absFilename = "E:\\Documents and Settings";
+ * const int bytesNeeded = 8 + 3 * strlen(absFilename) + 1;
+ * char * absUri = malloc(bytesNeeded * sizeof(char));
+ * if (uriWindowsFilenameToUriStringA(absFilename, absUri) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * free(absUri);
+ * ...
+ * }
+ * /COMMENT_HACK* absUri is "file:///E:/Documents%20and%20Settings" now *COMMENT_HACK/
+ * ...
+ * free(absUri);
* @endcode
*
* Conversion works ..
@@ -183,9 +183,9 @@
* @subsection normalization Normalizing URIs
* Sometimes we come across unnecessarily long URIs like &quot;http<b></b>://example.org/one/two/../../one&quot;.
* The algorithm we can use to shorten this URI down to &quot;http<b></b>://example.org/one&quot; is called
- * <a href="http://tools.ietf.org/html/rfc3986#section-6.2.2" target="_blank">Syntax-Based Normalization</a>.
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2" target="_blank">Syntax-Based Normalization</a>.
* Note that normalizing a URI does more than just &quot;stripping dot segments&quot;. Please have a look at
- * <a href="http://tools.ietf.org/html/rfc3986#section-6.2.2" target="_blank">Section 6.2.2 of RFC 3986</a>
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2" target="_blank">Section 6.2.2 of RFC 3986</a>
* for the full description.
*
* As we asked uriToStringCharsRequiredA() for the required space when converting
@@ -194,22 +194,22 @@
* mask to uriNormalizeSyntaxExA():
*
* @code
- * const unsigned int dirtyParts = uriNormalizeSyntaxMaskRequiredA(&uri);
- * if (uriNormalizeSyntaxExA(&uri, dirtyParts) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
+ * const unsigned int dirtyParts = uriNormalizeSyntaxMaskRequiredA(&uri);
+ * if (uriNormalizeSyntaxExA(&uri, dirtyParts) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
* @endcode
*
* If you don't want to normalize all parts of the URI you can pass a custom
* mask as well:
*
* @code
- * const unsigned int normMask = URI_NORMALIZE_SCHEME | URI_NORMALIZE_USER_INFO;
- * if (uriNormalizeSyntaxExA(&uri, normMask) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
+ * const unsigned int normMask = URI_NORMALIZE_SCHEME | URI_NORMALIZE_USER_INFO;
+ * if (uriNormalizeSyntaxExA(&uri, normMask) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
* @endcode
*
* Please see ::UriNormalizationMaskEnum for the complete set of flags.
@@ -219,36 +219,36 @@
* internally:
*
* @code
- * if (uriNormalizeSyntaxA(&uri) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
+ * if (uriNormalizeSyntaxA(&uri) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
* @endcode
*
*
* @section querystrings Working with Query Strings
- * <a href="http://tools.ietf.org/html/rfc3986" target="_blank">RFC 3986</a>
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986" target="_blank">RFC 3986</a>
* itself does not understand the query part of a URI as a list of key/value pairs.
* But HTML 2.0 does and defines a media type <i>application/x-www-form-urlencoded</i>
- * in in <a href="http://tools.ietf.org/html/rfc1866#section-8.2.1" target="blank">section 8.2.1</a>
- * of <a href="http://tools.ietf.org/html/rfc1866" target="blank">RFC 1866</a>.
+ * in in <a href="https://datatracker.ietf.org/doc/html/rfc1866#section-8.2.1" target="blank">section 8.2.1</a>
+ * of <a href="https://datatracker.ietf.org/doc/html/rfc1866" target="blank">RFC 1866</a>.
* uriparser allows you to dissect (or parse) a query string into unescaped key/value pairs
* and back.
*
* To dissect the query part of a just-parsed URI you could write code like this:
*
* @code
- * UriUriA uri;
- * UriQueryListA * queryList;
- * int itemCount;
- * ...
- * if (uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
- * uri.query.afterLast) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * ...
- * uriFreeQueryListA(queryList);
+ * UriUriA uri;
+ * UriQueryListA * queryList;
+ * int itemCount;
+ * ...
+ * if (uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
+ * uri.query.afterLast) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * ...
+ * uriFreeQueryListA(queryList);
* @endcode
*
* @remarks
@@ -259,25 +259,25 @@
* To compose a query string from a query list you could write code like this:
*
* @code
- * int charsRequired;
- * int charsWritten;
- * char * queryString;
- * ...
- * if (uriComposeQueryCharsRequiredA(queryList, &charsRequired) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * queryString = malloc((charsRequired + 1) * sizeof(char));
- * if (queryString == NULL) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * if (uriComposeQueryA(queryString, queryList, charsRequired + 1, &charsWritten) != URI_SUCCESS) {
- * /COMMENT_HACK* Failure *COMMENT_HACK/
- * ...
- * }
- * ...
- * free(queryString);
+ * int charsRequired;
+ * int charsWritten;
+ * char * queryString;
+ * ...
+ * if (uriComposeQueryCharsRequiredA(queryList, &charsRequired) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * queryString = malloc((charsRequired + 1) * sizeof(char));
+ * if (queryString == NULL) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * if (uriComposeQueryA(queryString, queryList, charsRequired + 1, &charsWritten) != URI_SUCCESS) {
+ * /COMMENT_HACK* Failure *COMMENT_HACK/
+ * ...
+ * }
+ * ...
+ * free(queryString);
* @endcode
*
*
diff --git a/doc/preprocess.sh b/doc/preprocess.sh
index c77bb6a..7b7561e 100755
--- a/doc/preprocess.sh
+++ b/doc/preprocess.sh
@@ -1,4 +1,13 @@
#! /usr/bin/env bash
# Run GCC preprocessor and delete empty lines
-: ${CPP:=cpp}
-"${CPP}" -DURI_DOXYGEN -DURI_NO_UNICODE -C -I ../include "$1" | sed -e '/^$/d' -e 's/COMMENT_HACK//g'
+set -e -u -o pipefail
+: ${CC:=cc}
+PS4='doc/preprocess.sh|# '
+set -x
+{
+ if [[ "${1}" =~ \.txt$ ]]; then
+ cat "${1}"
+ else
+ "${CC}" -E -DURI_DOXYGEN -DURI_NO_UNICODE -C -I ../include "$1"
+ fi
+} | sed -e '/^$/d' -e 's/COMMENT_HACK//g' -e 's/URI_PUBLIC //g'
diff --git a/doc/release.sh.in b/doc/release.sh.in
index 6a7d09a..e1af41b 100755
--- a/doc/release.sh.in
+++ b/doc/release.sh.in
@@ -14,13 +14,13 @@ rm -Rf "${distdir}" "${distdir}.zip"
# Copy
mkdir -p "${distdir}/html/search"
cp \
- html/*.css \
- html/*.html \
- html/*.js \
- html/*.md5 \
- html/*.png \
- \
- "${distdir}/html/" || exit 1
+ html/*.css \
+ html/*.html \
+ html/*.js \
+ html/*.md5 \
+ html/*.png \
+ \
+ "${distdir}/html/" || exit 1
cp -R html/search/ "${distdir}/html/" || exit 1
# Package
diff --git a/doc/rule_dependencies.dot b/doc/rule_dependencies.dot
index cf2576c..4d3e95f 100644
--- a/doc/rule_dependencies.dot
+++ b/doc/rule_dependencies.dot
@@ -1,64 +1,64 @@
-digraph whoCallsWhom {
- size="20,20";
- fontsize=12
- node [style=bold];
- "authority" -> "authorityTwo";
- "authority" -> "ipLiteral";
- "authority" -> "ownHostUserInfoNz";
- "authorityTwo" -> "port";
- "hexZero" -> "hexZero";
- "hierPart" -> "partHelperTwo";
- "hierPart" -> "pathRootless";
- "ipFutLoop" -> "ipFutStopGo";
- "ipFutStopGo" -> "ipFutLoop";
- "ipFuture" -> "hexZero";
- "ipFuture" -> "ipFutLoop";
- "ipLit2" -> "ipFuture";
- "ipLit2" -> "IPv6address2";
- "ipLiteral" -> "ipLit2";
- "mustBeSegmentNzNc" -> "mustBeSegmentNzNc";
- "mustBeSegmentNzNc" -> "segment";
- "mustBeSegmentNzNc" -> "uriTail";
- "mustBeSegmentNzNc" -> "zeroMoreSlashSegs";
- "ownHost" -> "authorityTwo";
- "ownHost" -> "ipLiteral";
- "ownHost" -> "ownHost2";
- "ownHost2" -> "authorityTwo";
- "ownHost2" -> "ownHost2";
- "ownHostUserInfo" -> "ownHostUserInfoNz";
- "ownHostUserInfoNz" -> "ownHost";
- "ownHostUserInfoNz" -> "ownHostUserInfo";
- "ownHostUserInfoNz" -> "ownPortUserInfo";
- "ownPortUserInfo" -> "ownPortUserInfo";
- "ownPortUserInfo" -> "ownUserInfo";
- "ownUserInfo" -> "ownHost";
- "ownUserInfo" -> "ownUserInfo";
- "partHelperTwo" -> "authority";
- "partHelperTwo" -> "pathAbsEmpty";
- "partHelperTwo" -> "pathAbsNoLeadSlash";
- "pathAbsEmpty" -> "pathAbsEmpty";
- "pathAbsEmpty" -> "segment";
- "pathAbsNoLeadSlash" -> "segmentNz";
- "pathAbsNoLeadSlash" -> "zeroMoreSlashSegs";
- "pathRootless" -> "segmentNz";
- "pathRootless" -> "zeroMoreSlashSegs";
- "port" -> "port";
- "queryFrag" -> "queryFrag";
- "segment" -> "segment";
- "segmentNz" -> "segment";
- "segmentNzNcOrScheme2" -> "hierPart";
- "segmentNzNcOrScheme2" -> "mustBeSegmentNzNc";
- "segmentNzNcOrScheme2" -> "segment";
- "segmentNzNcOrScheme2" -> "segmentNzNcOrScheme2";
- "segmentNzNcOrScheme2" -> "uriTail";
- "segmentNzNcOrScheme2" -> "zeroMoreSlashSegs";
- "uriReference" -> "mustBeSegmentNzNc";
- "uriReference" -> "partHelperTwo";
- "uriReference" -> "segmentNzNcOrScheme2";
- "uriReference" -> "uriTail";
- "uriTail" -> "queryFrag";
- "uriTail" -> "uriTailTwo";
- "uriTailTwo" -> "queryFrag";
- "zeroMoreSlashSegs" -> "segment";
- "zeroMoreSlashSegs" -> "zeroMoreSlashSegs";
-}
+digraph whoCallsWhom {
+ size="20,20";
+ fontsize=12
+ node [style=bold];
+ "authority" -> "authorityTwo";
+ "authority" -> "ipLiteral";
+ "authority" -> "ownHostUserInfoNz";
+ "authorityTwo" -> "port";
+ "hexZero" -> "hexZero";
+ "hierPart" -> "partHelperTwo";
+ "hierPart" -> "pathRootless";
+ "ipFutLoop" -> "ipFutStopGo";
+ "ipFutStopGo" -> "ipFutLoop";
+ "ipFuture" -> "hexZero";
+ "ipFuture" -> "ipFutLoop";
+ "ipLit2" -> "ipFuture";
+ "ipLit2" -> "IPv6address2";
+ "ipLiteral" -> "ipLit2";
+ "mustBeSegmentNzNc" -> "mustBeSegmentNzNc";
+ "mustBeSegmentNzNc" -> "segment";
+ "mustBeSegmentNzNc" -> "uriTail";
+ "mustBeSegmentNzNc" -> "zeroMoreSlashSegs";
+ "ownHost" -> "authorityTwo";
+ "ownHost" -> "ipLiteral";
+ "ownHost" -> "ownHost2";
+ "ownHost2" -> "authorityTwo";
+ "ownHost2" -> "ownHost2";
+ "ownHostUserInfo" -> "ownHostUserInfoNz";
+ "ownHostUserInfoNz" -> "ownHost";
+ "ownHostUserInfoNz" -> "ownHostUserInfo";
+ "ownHostUserInfoNz" -> "ownPortUserInfo";
+ "ownPortUserInfo" -> "ownPortUserInfo";
+ "ownPortUserInfo" -> "ownUserInfo";
+ "ownUserInfo" -> "ownHost";
+ "ownUserInfo" -> "ownUserInfo";
+ "partHelperTwo" -> "authority";
+ "partHelperTwo" -> "pathAbsEmpty";
+ "partHelperTwo" -> "pathAbsNoLeadSlash";
+ "pathAbsEmpty" -> "pathAbsEmpty";
+ "pathAbsEmpty" -> "segment";
+ "pathAbsNoLeadSlash" -> "segmentNz";
+ "pathAbsNoLeadSlash" -> "zeroMoreSlashSegs";
+ "pathRootless" -> "segmentNz";
+ "pathRootless" -> "zeroMoreSlashSegs";
+ "port" -> "port";
+ "queryFrag" -> "queryFrag";
+ "segment" -> "segment";
+ "segmentNz" -> "segment";
+ "segmentNzNcOrScheme2" -> "hierPart";
+ "segmentNzNcOrScheme2" -> "mustBeSegmentNzNc";
+ "segmentNzNcOrScheme2" -> "segment";
+ "segmentNzNcOrScheme2" -> "segmentNzNcOrScheme2";
+ "segmentNzNcOrScheme2" -> "uriTail";
+ "segmentNzNcOrScheme2" -> "zeroMoreSlashSegs";
+ "uriReference" -> "mustBeSegmentNzNc";
+ "uriReference" -> "partHelperTwo";
+ "uriReference" -> "segmentNzNcOrScheme2";
+ "uriReference" -> "uriTail";
+ "uriTail" -> "queryFrag";
+ "uriTail" -> "uriTailTwo";
+ "uriTailTwo" -> "queryFrag";
+ "zeroMoreSlashSegs" -> "segment";
+ "zeroMoreSlashSegs" -> "zeroMoreSlashSegs";
+}
diff --git a/fuzz/COPYING b/fuzz/COPYING
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/fuzz/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/fuzz/DissectQueryMallocFuzzer.cpp b/fuzz/DissectQueryMallocFuzzer.cpp
new file mode 100644
index 0000000..e31e4a3
--- /dev/null
+++ b/fuzz/DissectQueryMallocFuzzer.cpp
@@ -0,0 +1,62 @@
+// Copyright 2020 Google LLC
+// Copyright 2025 Mikhail Khachaiants <mkhachaiants@gmail.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "uriparser/Uri.h"
+#include "FuzzingUtils.h"
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ const UriString query = consumeRemainingBytesAsString(fdp);
+
+ URI_TYPE(QueryList) * query_list = nullptr;
+ int item_count = -1;
+
+ const URI_CHAR * query_start = query.c_str();
+ const URI_CHAR * query_end = query_start + query.size();
+
+ // Break a query like "a=b&2=3" into key/value pairs.
+ int result =
+ URI_FUNC(DissectQueryMalloc)(&query_list, &item_count, query_start, query_end);
+
+ if (query_list == nullptr || result != URI_SUCCESS || item_count < 0) {
+ return 0;
+ }
+
+ int chars_required = 0;
+ if (URI_FUNC(ComposeQueryCharsRequired)(query_list, &chars_required) != URI_SUCCESS) {
+ return 0;
+ }
+
+ if (!chars_required) {
+ URI_FUNC(FreeQueryList)(query_list);
+ return 0;
+ }
+
+ // URI_FUNC(ComposeQuery) requires number of characters including terminator
+ const int buf_size = chars_required + 1;
+
+ std::vector<URI_CHAR> buf(buf_size, 0);
+ int written = -1;
+
+ // Reverse the process of uriDissectQueryMallocA.
+ result = URI_FUNC(ComposeQuery)(buf.data(), query_list, buf_size, &written);
+
+ URI_FUNC(FreeQueryList)(query_list);
+ return 0;
+}
diff --git a/fuzz/FreeFuzzer.cpp b/fuzz/FreeFuzzer.cpp
new file mode 100644
index 0000000..1eeb94f
--- /dev/null
+++ b/fuzz/FreeFuzzer.cpp
@@ -0,0 +1,30 @@
+// Copyright 2020 Google LLC
+// Copyright 2025 Mikhail Khachaiants <mkhachaiants@gmail.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "uriparser/Uri.h"
+#include "FuzzingUtils.h"
+#include <cstddef>
+#include <cstdint>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ UriString fuzz_uri = consumeRemainingBytesAsString(fdp);
+ URI_TYPE(ParserState) state;
+ URI_TYPE(Uri) uriA;
+ state.uri = &uriA;
+ URI_FUNC(ParseUri)(&state, fuzz_uri.c_str());
+ URI_FUNC(FreeUriMembers)(&uriA);
+ return 0;
+}
diff --git a/fuzz/FuzzingUtils.h b/fuzz/FuzzingUtils.h
new file mode 100644
index 0000000..74d27d3
--- /dev/null
+++ b/fuzz/FuzzingUtils.h
@@ -0,0 +1,44 @@
+// Copyright 2025 Mikhail Khachaiants <mkhachaiants@gmail.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef URI_FUZZING_UTILS_H
+# define URI_FUZZING_UTILS_H 1
+
+# include "uriparser/Uri.h"
+# include <fuzzer/FuzzedDataProvider.h>
+# include <string>
+
+using UriString = std::basic_string<URI_CHAR>;
+
+inline UriString tryConsumeBytesAsString(FuzzedDataProvider & fdp, size_t chars) {
+ UriString str(chars, 0);
+ const size_t bytes = fdp.ConsumeData(str.data(), chars * sizeof(URI_CHAR));
+ // FuzzedDataProvider may provide less data than requested if the input is
+ // insufficiently long. We need to adjust the string length accordingly.
+ str.resize(bytes / sizeof(URI_CHAR));
+ return str;
+}
+
+inline UriString consumeRandomLengthString(FuzzedDataProvider & fdp) {
+ const size_t max_chars = fdp.remaining_bytes() / sizeof(URI_CHAR);
+ const size_t chars = fdp.ConsumeIntegralInRange<size_t>(0, max_chars);
+ return tryConsumeBytesAsString(fdp, chars);
+}
+
+inline UriString consumeRemainingBytesAsString(FuzzedDataProvider & fdp) {
+ const size_t chars = fdp.remaining_bytes() / sizeof(URI_CHAR);
+ return tryConsumeBytesAsString(fdp, chars);
+}
+
+#endif /* URI_FUZZING_UTILS_H */
diff --git a/fuzz/ParseFuzzer.cpp b/fuzz/ParseFuzzer.cpp
new file mode 100644
index 0000000..adb83d7
--- /dev/null
+++ b/fuzz/ParseFuzzer.cpp
@@ -0,0 +1,125 @@
+// Copyright 2020 Google LLC
+// Copyright 2025 Mikhail Khachaiants <mkhachaiants@gmail.com>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "uriparser/Uri.h"
+#include "uriparser/UriIp4.h"
+#include "FuzzingUtils.h"
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+class UriHolder {
+public:
+ UriHolder() {
+ memset((void *)&uri_, 0, sizeof(uri_));
+ }
+
+ ~UriHolder() {
+ URI_FUNC(FreeUriMembers)(&uri_);
+ }
+
+ URI_TYPE(Uri) * get() {
+ return &uri_;
+ }
+
+private:
+ URI_TYPE(Uri) uri_;
+};
+
+void Escapes(const UriString & uri) {
+ const URI_CHAR * first = uri.c_str();
+ // Up to 6 bytes per character with normalizeBreaks enabled (\n -> %0D%0A)
+ std::vector<URI_CHAR> buf1(uri.size() * 6 + 1);
+ // and up to 3 bytes per character otherwise
+ std::vector<URI_CHAR> buf2(uri.size() * 3 + 1);
+
+ URI_FUNC(Escape)(first, &buf1[0], URI_TRUE, URI_TRUE);
+ URI_FUNC(Escape)(first, &buf1[0], URI_FALSE, URI_TRUE);
+ if (buf1.data()) {
+ URI_FUNC(UnescapeInPlace)(&buf1[0]);
+ }
+
+ URI_FUNC(Escape)(first, &buf2[0], URI_TRUE, URI_FALSE);
+ URI_FUNC(Escape)(first, &buf2[0], URI_FALSE, URI_FALSE);
+ if (buf2.data()) {
+ URI_FUNC(UnescapeInPlace)(&buf2[0]);
+ }
+}
+
+void FileNames(const UriString & uri) {
+ const size_t size = 8 + 3 * uri.size() + 1;
+ std::vector<URI_CHAR> buf(size);
+
+ URI_FUNC(UnixFilenameToUriString)(uri.c_str(), &buf[0]);
+ URI_FUNC(WindowsFilenameToUriString)(uri.c_str(), &buf[0]);
+ URI_FUNC(UriStringToUnixFilename)(uri.c_str(), &buf[0]);
+ URI_FUNC(UriStringToWindowsFilename)(uri.c_str(), &buf[0]);
+}
+
+void Ipv4(const UriString & s) {
+ const URI_CHAR * cstr = s.c_str();
+ unsigned char result[4] = {};
+ URI_FUNC(ParseIpFourAddress)(result, cstr, &cstr[s.size()]);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
+ FuzzedDataProvider stream(data, size);
+ bool domainRelative = stream.ConsumeBool();
+
+ const UriString uri1 = consumeRandomLengthString(stream);
+ const UriString uri2 = consumeRemainingBytesAsString(stream);
+
+ Escapes(uri1);
+ Escapes(uri2);
+
+ FileNames(uri1);
+ FileNames(uri2);
+
+ Ipv4(uri1);
+ Ipv4(uri2);
+
+ UriHolder uriHolder1;
+ URI_TYPE(ParserState) state1;
+ state1.uri = uriHolder1.get();
+ if (URI_FUNC(ParseUri)(&state1, uri1.c_str()) != URI_SUCCESS) {
+ return 0;
+ }
+
+ URI_CHAR buf[1024 * 8] = {0};
+ int written = 0;
+ URI_FUNC(ToString)(buf, state1.uri, sizeof(buf) / sizeof(buf[0]), &written);
+
+ UriHolder uriHolder2;
+ if (URI_FUNC(ParseSingleUri)(uriHolder2.get(), uri2.c_str(), nullptr)
+ != URI_SUCCESS) {
+ return 0;
+ }
+
+ URI_FUNC(EqualsUri)(state1.uri, uriHolder2.get());
+
+ unsigned int mask = 0;
+ URI_FUNC(NormalizeSyntaxMaskRequiredEx)(state1.uri, &mask);
+ URI_FUNC(NormalizeSyntax)(state1.uri);
+
+ URI_TYPE(Uri) absUri;
+ URI_FUNC(AddBaseUri)(&absUri, state1.uri, uriHolder2.get());
+ URI_FUNC(FreeUriMembers)(&absUri);
+
+ URI_TYPE(Uri) relUri;
+ URI_FUNC(RemoveBaseUri)(&relUri, state1.uri, uriHolder2.get(), domainRelative);
+ URI_FUNC(FreeUriMembers)(&relUri);
+
+ return 0;
+}
diff --git a/include/uriparser/COPYING b/include/uriparser/COPYING
new file mode 100644
index 0000000..261c741
--- /dev/null
+++ b/include/uriparser/COPYING
@@ -0,0 +1,36 @@
+uriparser - RFC 3986 URI parsing library
+
+Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/include/uriparser/Uri.h b/include/uriparser/Uri.h
index b80ac6c..f041f81 100644
--- a/include/uriparser/Uri.h
+++ b/include/uriparser/Uri.h
@@ -1,4 +1,4 @@
-/* e8e2c75d033ddfe256fe87c3fd5a330a6f2c9cbb376ebd83a1b3263e804c766a (0.9.8+)
+/* 53c1cb9f2f728652fe001dc72fa0fa7a0e9fa0b8baaaa9e37561c6cdf88ac4df (1.0.1+)
*
* uriparser - RFC 3986 URI parsing library
*
@@ -45,47 +45,41 @@
*/
#if (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI)) \
- || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \
- || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+ || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* What encodings are enabled? */
-#include "UriDefsConfig.h"
-#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+# include "UriDefsConfig.h"
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "Uri.h"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "Uri.h"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "Uri.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "Uri.h"
+# undef URI_PASS_UNICODE
+# endif
/* Only one pass for each encoding */
-#elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) \
- && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
- && !defined(URI_H_UNICODE) && defined(URI_ENABLE_UNICODE))
-# ifdef URI_PASS_ANSI
-# define URI_H_ANSI 1
-# include "UriDefsAnsi.h"
-# else
-# define URI_H_UNICODE 1
-# include "UriDefsUnicode.h"
-# endif
-
-
-
-#ifdef __cplusplus
+# elif (defined(URI_PASS_ANSI) && !defined(URI_H_ANSI) && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_H_ANSI 1
+# include "UriDefsAnsi.h"
+# else
+# define URI_H_UNICODE 1
+# include "UriDefsUnicode.h"
+# endif
+
+# ifdef __cplusplus
extern "C" {
-#endif
-
-
-
-#ifndef URI_DOXYGEN
-# include "UriBase.h"
-#endif
-
+# endif
+# ifndef URI_DOXYGEN
+# include "UriBase.h"
+# endif
/**
* Specifies a range of characters within a string.
@@ -99,12 +93,10 @@ extern "C" {
* @since 0.3.0
*/
typedef struct URI_TYPE(TextRangeStruct) {
- const URI_CHAR * first; /**< Pointer to first character */
- const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */
+ const URI_CHAR * first; /**< Pointer to first character */
+ const URI_CHAR * afterLast; /**< Pointer to character after the last one still in */
} URI_TYPE(TextRange); /**< @copydoc UriTextRangeStructA */
-
-
/**
* Represents a path segment within a %URI path.
* More precisely it is a node in a linked
@@ -114,14 +106,13 @@ typedef struct URI_TYPE(TextRangeStruct) {
* @since 0.3.0
*/
typedef struct URI_TYPE(PathSegmentStruct) {
- URI_TYPE(TextRange) text; /**< Path segment name */
- struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in the list, can be NULL if last already */
+ URI_TYPE(TextRange) text; /**< Path segment name */
+ struct URI_TYPE(PathSegmentStruct) * next; /**< Pointer to the next path segment in
+ the list, can be NULL if last already */
- void * reserved; /**< Reserved to the parser */
+ void * reserved; /**< Reserved to the parser */
} URI_TYPE(PathSegment); /**< @copydoc UriPathSegmentStructA */
-
-
/**
* Holds structured host information.
* This is either a IPv4, IPv6, plain
@@ -132,13 +123,16 @@ typedef struct URI_TYPE(PathSegmentStruct) {
* @since 0.3.0
*/
typedef struct URI_TYPE(HostDataStruct) {
- UriIp4 * ip4; /**< IPv4 address */
- UriIp6 * ip6; /**< IPv6 address */
- URI_TYPE(TextRange) ipFuture; /**< IPvFuture address */
+ UriIp4 * ip4; /**< IPv4 address */
+ UriIp6 * ip6; /**< IPv6 address */
+ URI_TYPE(TextRange)
+ ipFuture; /**< IPvFuture address
+@note
+With non-<c>NULL</c> members in UriUriStructA.hostData context,
+this text range's pointers must be <em>identical</em> to those
+of UriUriStructA.hostText at all times. */
} URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */
-
-
/**
* Represents an RFC 3986 %URI.
* Missing components can be {NULL, NULL} ranges.
@@ -149,24 +143,23 @@ typedef struct URI_TYPE(HostDataStruct) {
* @since 0.3.0
*/
typedef struct URI_TYPE(UriStruct) {
- URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */
- URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */
- URI_TYPE(TextRange) hostText; /**< Host text (set for all hosts, excluding square brackets) */
- URI_TYPE(HostData) hostData; /**< Structured host type specific data */
- URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */
- URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */
- URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */
- URI_TYPE(TextRange) query; /**< Query without leading "?" */
- URI_TYPE(TextRange) fragment; /**< Query without leading "#" */
- UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a";
- always <c>URI_FALSE</c> for URIs with host */
- UriBool owner; /**< Memory owner flag */
-
- void * reserved; /**< Reserved to the parser */
+ URI_TYPE(TextRange) scheme; /**< Scheme (e.g. "http") */
+ URI_TYPE(TextRange) userInfo; /**< User info (e.g. "user:pass") */
+ URI_TYPE(TextRange)
+ hostText; /**< Host text (set for all hosts, excluding square brackets) */
+ URI_TYPE(HostData) hostData; /**< Structured host type specific data */
+ URI_TYPE(TextRange) portText; /**< Port (e.g. "80") */
+ URI_TYPE(PathSegment) * pathHead; /**< Head of a linked list of path segments */
+ URI_TYPE(PathSegment) * pathTail; /**< Tail of the list behind pathHead */
+ URI_TYPE(TextRange) query; /**< Query without leading "?" */
+ URI_TYPE(TextRange) fragment; /**< Query without leading "#" */
+ UriBool absolutePath; /**< Absolute path flag, distincting "a" and "/a"; always
+ <c>URI_FALSE</c> for URIs with host */
+ UriBool owner; /**< Memory owner flag */
+
+ void * reserved; /**< Reserved to the parser */
} URI_TYPE(Uri); /**< @copydoc UriUriStructA */
-
-
/**
* Represents a state of the %URI parser.
* Missing components can be NULL to reflect
@@ -177,15 +170,14 @@ typedef struct URI_TYPE(UriStruct) {
* @since 0.3.0
*/
typedef struct URI_TYPE(ParserStateStruct) {
- URI_TYPE(Uri) * uri; /**< Plug in the %URI structure to be filled while parsing here */
- int errorCode; /**< Code identifying the error which occurred */
- const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */
+ URI_TYPE(Uri)
+ *uri; /**< Plug in the %URI structure to be filled while parsing here */
+ int errorCode; /**< Code identifying the error which occurred */
+ const URI_CHAR * errorPos; /**< Pointer to position in case of a syntax error */
- void * reserved; /**< Reserved to the parser */
+ void * reserved; /**< Reserved to the parser */
} URI_TYPE(ParserState); /**< @copydoc UriParserStateStructA */
-
-
/**
* Represents a query element.
* More precisely it is a node in a linked
@@ -194,13 +186,58 @@ typedef struct URI_TYPE(ParserStateStruct) {
* @since 0.7.0
*/
typedef struct URI_TYPE(QueryListStruct) {
- const URI_CHAR * key; /**< Key of the query element */
- const URI_CHAR * value; /**< Value of the query element, can be NULL */
+ const URI_CHAR * key; /**< Key of the query element */
+ const URI_CHAR * value; /**< Value of the query element, can be NULL */
- struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in the list, can be NULL if last already */
+ struct URI_TYPE(QueryListStruct) * next; /**< Pointer to the next key/value pair in
+ the list, can be NULL if last already */
} URI_TYPE(QueryList); /**< @copydoc UriQueryListStructA */
+/**
+ * Checks if a URI has the host component set.
+ *
+ * @param uri <b>IN</b>: %URI to check
+ * @return <c>URI_TRUE</c> when host is set, <c>URI_FALSE</c> otherwise
+ *
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri);
+/**
+ * Converts an IPv6 text representation into 16 bytes.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param output <b>OUT</b>: Output destination, can be <c>NULL</c>
+ * @param first <b>IN</b>: First character of IPv6 text to parse
+ * @param afterLast <b>IN</b>: Position to stop parsing at
+ * @return Error code or <c>URI_SUCCESS</c> on success
+ *
+ * @see uriParseIpFourAddressA
+ * @see uriParseIpSixAddressMmA
+ * @see uriIsWellFormedHostIp6A
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Converts an IPv6 text representation into 16 bytes.
+ *
+ * @param output <b>OUT</b>: Output destination, can be <c>NULL</c>
+ * @param first <b>IN</b>: First character of IPv6 text to parse
+ * @param afterLast <b>IN</b>: Position to stop parsing at
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or <c>URI_SUCCESS</c> on success
+ *
+ * @see uriParseIpFourAddressA
+ * @see uriParseIpSixAddressA
+ * @see uriIsWellFormedHostIp6MmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
/**
* Parses a RFC 3986 %URI.
@@ -208,7 +245,8 @@ typedef struct URI_TYPE(QueryListStruct) {
*
* @param state <b>INOUT</b>: Parser state with set output %URI, must not be NULL
* @param first <b>IN</b>: Pointer to the first character to parse, must not be NULL
- * @param afterLast <b>IN</b>: Pointer to the character after the last to parse, must not be NULL
+ * @param afterLast <b>IN</b>: Pointer to the character after the last to parse, must
+ * not be NULL
* @return 0 on success, error code otherwise
*
* @see uriParseUriA
@@ -216,12 +254,11 @@ typedef struct URI_TYPE(QueryListStruct) {
* @see uriParseSingleUriExA
* @see uriToStringA
* @since 0.3.0
- * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriExA (with "Single").
+ * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriExA (with
+ * "Single").
*/
-URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast);
-
-
+URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
/**
* Parses a RFC 3986 %URI.
@@ -236,12 +273,10 @@ URI_PUBLIC int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state,
* @see uriParseSingleUriExA
* @see uriToStringA
* @since 0.3.0
- * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriA (with "Single").
+ * @deprecated Deprecated since 0.9.0, please migrate to uriParseSingleUriA (with
+ * "Single").
*/
-URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state,
- const URI_CHAR * text);
-
-
+URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text);
/**
* Parses a single RFC 3986 %URI.
@@ -260,10 +295,8 @@ URI_PUBLIC int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state,
* @see uriToStringA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri,
- const URI_CHAR * text, const URI_CHAR ** errorPos);
-
-
+URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, const URI_CHAR * text,
+ const URI_CHAR ** errorPos);
/**
* Parses a single RFC 3986 %URI.
@@ -285,11 +318,9 @@ URI_PUBLIC int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri,
* @see uriToStringA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- const URI_CHAR ** errorPos);
-
-
+URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ const URI_CHAR ** errorPos);
/**
* Parses a single RFC 3986 %URI.
@@ -311,11 +342,10 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri,
* @see uriToStringA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- const URI_CHAR ** errorPos, UriMemoryManager * memory);
-
-
+URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ const URI_CHAR ** errorPos,
+ UriMemoryManager * memory);
/**
* Frees all memory associated with the members
@@ -323,6 +353,10 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri,
* itself is not freed, only its members.
* Uses default libc-based memory manager.
*
+ * @remarks
+ * Calling on an all-zeros structure (e.g. through <c>memset</c> or <c>calloc</c>) is
+ * safe.<br/> Calling on an uninitialized structure is <em>not</em> safe.
+ *
* @param uri <b>INOUT</b>: %URI structure whose members should be freed
*
* @see uriFreeUriMembersMmA
@@ -330,13 +364,15 @@ URI_PUBLIC int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri,
*/
URI_PUBLIC void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri);
-
-
/**
* Frees all memory associated with the members
* of the %URI structure. Note that the structure
* itself is not freed, only its members.
*
+ * @remarks
+ * Calling on an all-zeros structure (e.g. through <c>memset</c> or <c>calloc</c>) is
+ * safe.<br/> Calling on an uninitialized structure is <em>not</em> safe.
+ *
* @param uri <b>INOUT</b>: %URI structure whose members should be freed
* @param memory <b>IN</b>: Memory manager to use, NULL for default libc
* @return 0 on success, error code otherwise
@@ -344,13 +380,10 @@ URI_PUBLIC void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri);
* @see uriFreeUriMembersA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory);
-
-
+URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
/**
- * Percent-encodes all unreserved characters from the input string and
+ * Percent-encodes all but unreserved characters from the input string and
* writes the encoded version to the output string.
*
* NOTE: Be sure to allocate <b>3 times</b> the space of the input buffer for
@@ -378,13 +411,11 @@ URI_PUBLIC int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri,
* @since 0.5.2
*/
URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
- const URI_CHAR * inAfterLast, URI_CHAR * out,
- UriBool spaceToPlus, UriBool normalizeBreaks);
-
-
+ const URI_CHAR * inAfterLast, URI_CHAR * out,
+ UriBool spaceToPlus, UriBool normalizeBreaks);
/**
- * Percent-encodes all unreserved characters from the input string and
+ * Percent-encodes all but unreserved characters from the input string and
* writes the encoded version to the output string.
*
* NOTE: Be sure to allocate <b>3 times</b> the space of the input buffer for
@@ -411,9 +442,7 @@ URI_PUBLIC URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
* @since 0.5.0
*/
URI_PUBLIC URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out,
- UriBool spaceToPlus, UriBool normalizeBreaks);
-
-
+ UriBool spaceToPlus, UriBool normalizeBreaks);
/**
* Unescapes percent-encoded groups in a given string.
@@ -432,10 +461,9 @@ URI_PUBLIC URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out,
* @see uriEscapeExA
* @since 0.5.0
*/
-URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout,
- UriBool plusToSpace, UriBreakConversion breakConversion);
-
-
+URI_PUBLIC const URI_CHAR *
+ URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, UriBool plusToSpace,
+ UriBreakConversion breakConversion);
/**
* Unescapes percent-encoded groups in a given string.
@@ -457,13 +485,11 @@ URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout,
*/
URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout);
-
-
/**
* Performs reference resolution as described in
- * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>.
- * Uses default libc-based memory manager.
- * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later.
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2">section 5.2.2 of
+ * RFC 3986</a>. Uses default libc-based memory manager. NOTE: On success you have to call
+ * uriFreeUriMembersA on \p absoluteDest manually later.
*
* @param absoluteDest <b>OUT</b>: Result %URI
* @param relativeSource <b>IN</b>: Reference to resolve
@@ -477,16 +503,14 @@ URI_PUBLIC const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout);
* @since 0.4.0
*/
URI_PUBLIC int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest,
- const URI_TYPE(Uri) * relativeSource,
- const URI_TYPE(Uri) * absoluteBase);
-
-
+ const URI_TYPE(Uri) * relativeSource,
+ const URI_TYPE(Uri) * absoluteBase);
/**
* Performs reference resolution as described in
- * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>.
- * Uses default libc-based memory manager.
- * NOTE: On success you have to call uriFreeUriMembersA on \p absoluteDest manually later.
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2">section 5.2.2 of
+ * RFC 3986</a>. Uses default libc-based memory manager. NOTE: On success you have to call
+ * uriFreeUriMembersA on \p absoluteDest manually later.
*
* @param absoluteDest <b>OUT</b>: Result %URI
* @param relativeSource <b>IN</b>: Reference to resolve
@@ -500,16 +524,15 @@ URI_PUBLIC int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absoluteDest,
* @since 0.8.1
*/
URI_PUBLIC int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest,
- const URI_TYPE(Uri) * relativeSource,
- const URI_TYPE(Uri) * absoluteBase,
- UriResolutionOptions options);
-
-
+ const URI_TYPE(Uri) * relativeSource,
+ const URI_TYPE(Uri) * absoluteBase,
+ UriResolutionOptions options);
/**
* Performs reference resolution as described in
- * <a href="http://tools.ietf.org/html/rfc3986#section-5.2.2">section 5.2.2 of RFC 3986</a>.
- * NOTE: On success you have to call uriFreeUriMembersMmA on \p absoluteDest manually later.
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2">section 5.2.2 of
+ * RFC 3986</a>. NOTE: On success you have to call uriFreeUriMembersMmA on \p absoluteDest
+ * manually later.
*
* @param absoluteDest <b>OUT</b>: Result %URI
* @param relativeSource <b>IN</b>: Reference to resolve
@@ -525,11 +548,10 @@ URI_PUBLIC int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absoluteDest,
* @since 0.9.0
*/
URI_PUBLIC int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absoluteDest,
- const URI_TYPE(Uri) * relativeSource,
- const URI_TYPE(Uri) * absoluteBase,
- UriResolutionOptions options, UriMemoryManager * memory);
-
-
+ const URI_TYPE(Uri) * relativeSource,
+ const URI_TYPE(Uri) * absoluteBase,
+ UriResolutionOptions options,
+ UriMemoryManager * memory);
/**
* Tries to make a relative %URI (a reference) from an
@@ -554,11 +576,9 @@ URI_PUBLIC int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absoluteDest,
* @since 0.5.2
*/
URI_PUBLIC int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * absoluteSource,
- const URI_TYPE(Uri) * absoluteBase,
- UriBool domainRootMode);
-
-
+ const URI_TYPE(Uri) * absoluteSource,
+ const URI_TYPE(Uri) * absoluteBase,
+ UriBool domainRootMode);
/**
* Tries to make a relative %URI (a reference) from an
@@ -583,11 +603,10 @@ URI_PUBLIC int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest,
* @since 0.9.0
*/
URI_PUBLIC int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * absoluteSource,
- const URI_TYPE(Uri) * absoluteBase,
- UriBool domainRootMode, UriMemoryManager * memory);
-
-
+ const URI_TYPE(Uri) * absoluteSource,
+ const URI_TYPE(Uri) * absoluteBase,
+ UriBool domainRootMode,
+ UriMemoryManager * memory);
/**
* Checks two URIs for equivalence. Comparison is done
@@ -600,10 +619,7 @@ URI_PUBLIC int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest,
*
* @since 0.4.0
*/
-URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a,
- const URI_TYPE(Uri) * b);
-
-
+URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b);
/**
* Calculates the number of characters needed to store the
@@ -611,38 +627,67 @@ URI_PUBLIC UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a,
* terminator.
*
* @param uri <b>IN</b>: %URI to measure
- * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
+ * @param charsRequired <b>OUT</b>: Length of the string representation in characters
+ * <b>excluding</b> terminator
* @return Error code or 0 on success
*
* @see uriToStringA
* @since 0.5.0
*/
URI_PUBLIC int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri,
- int * charsRequired);
-
-
+ int * charsRequired);
/**
* Converts a %URI structure back to text as described in
- * <a href="http://tools.ietf.org/html/rfc3986#section-5.3">section 5.3 of RFC 3986</a>.
+ * <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-5.3">section 5.3 of RFC
+ * 3986</a>.
*
* NOTE: Scheme-based normalization
- * (<a href="http://tools.ietf.org/html/rfc3986#section-6.2.3">section 6.2.3 of RFC 3986</a>)
- * is not applied and is considered a responsibility of the application using uriparser.
+ * (<a href="https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.3">section 6.2.3 of
+ * RFC 3986</a>) is not applied and is considered a responsibility of the application
+ * using uriparser.
*
* @param dest <b>OUT</b>: Output destination
* @param uri <b>IN</b>: %URI to convert
- * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
- * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the %URI is too long!
+ * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b>
+ * terminator
+ * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than
+ * maxChars even if the %URI is too long!
* @return Error code or 0 on success
*
* @see uriToStringCharsRequiredA
* @since 0.4.0
*/
URI_PUBLIC int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
- int maxChars, int * charsWritten);
+ int maxChars, int * charsWritten);
+/**
+ * Copies a %URI structure.
+ *
+ * @param destUri <b>OUT</b>: Output destination
+ * @param sourceUri <b>IN</b>: %URI to copy
+ * @param memory <b>IN</b>: Memory manager to use, NULL for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriCopyUriA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri,
+ const URI_TYPE(Uri) * sourceUri,
+ UriMemoryManager * memory);
+/**
+ * Copies a %URI structure.
+ *
+ * @param destUri <b>OUT</b>: Output destination
+ * @param sourceUri <b>IN</b>: %URI to copy
+ * @return Error code or 0 on success
+ *
+ * @see uriCopyUriMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri,
+ const URI_TYPE(Uri) * sourceUri);
/**
* Determines the components of a %URI that are not normalized.
@@ -655,12 +700,10 @@ URI_PUBLIC int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
* @see uriNormalizeSyntaxExMmA
* @see uriNormalizeSyntaxMaskRequiredExA
* @since 0.5.0
- * @deprecated Deprecated since 0.9.0, please migrate to uriNormalizeSyntaxMaskRequiredExA (with "Ex").
+ * @deprecated Deprecated since 0.9.0, please migrate to uriNormalizeSyntaxMaskRequiredExA
+ * (with "Ex").
*/
-URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(
- const URI_TYPE(Uri) * uri);
-
-
+URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri);
/**
* Determines the components of a %URI that are not normalized.
@@ -675,10 +718,8 @@ URI_PUBLIC unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(
* @see uriNormalizeSyntaxMaskRequiredA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(
- const URI_TYPE(Uri) * uri, unsigned int * outMask);
-
-
+URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(const URI_TYPE(Uri) * uri,
+ unsigned int * outMask);
/**
* Normalizes a %URI using a normalization mask.
@@ -697,10 +738,7 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(
* @see uriNormalizeSyntaxMaskRequiredA
* @since 0.5.0
*/
-URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri,
- unsigned int mask);
-
-
+URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask);
/**
* Normalizes a %URI using a normalization mask.
@@ -719,10 +757,8 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri,
* @see uriNormalizeSyntaxMaskRequiredA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri,
- unsigned int mask, UriMemoryManager * memory);
-
-
+URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask,
+ UriMemoryManager * memory);
/**
* Normalizes all components of a %URI.
@@ -741,8 +777,6 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri,
*/
URI_PUBLIC int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri);
-
-
/**
* Converts a Unix filename to a %URI string.
* The destination buffer must be large enough to hold 7 + 3 * len(filename) + 1
@@ -762,9 +796,7 @@ URI_PUBLIC int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri);
* @since 0.5.2
*/
URI_PUBLIC int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename,
- URI_CHAR * uriString);
-
-
+ URI_CHAR * uriString);
/**
* Converts a Windows filename to a %URI string.
@@ -785,9 +817,7 @@ URI_PUBLIC int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename,
* @since 0.5.2
*/
URI_PUBLIC int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename,
- URI_CHAR * uriString);
-
-
+ URI_CHAR * uriString);
/**
* Extracts a Unix filename from a %URI string.
@@ -804,9 +834,7 @@ URI_PUBLIC int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename,
* @since 0.5.2
*/
URI_PUBLIC int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString,
- URI_CHAR * filename);
-
-
+ URI_CHAR * filename);
/**
* Extracts a Windows filename from a %URI string.
@@ -823,9 +851,7 @@ URI_PUBLIC int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString,
* @since 0.5.2
*/
URI_PUBLIC int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString,
- URI_CHAR * filename);
-
-
+ URI_CHAR * filename);
/**
* Calculates the number of characters needed to store the
@@ -834,17 +860,16 @@ URI_PUBLIC int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString,
* normalized to "%0D%0A".
*
* @param queryList <b>IN</b>: Query list to measure
- * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
+ * @param charsRequired <b>OUT</b>: Length of the string representation in characters
+ * <b>excluding</b> terminator
* @return Error code or 0 on success
*
* @see uriComposeQueryCharsRequiredExA
* @see uriComposeQueryA
* @since 0.7.0
*/
-URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)(
- const URI_TYPE(QueryList) * queryList, int * charsRequired);
-
-
+URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
+ int * charsRequired);
/**
* Calculates the number of characters needed to store the
@@ -852,7 +877,8 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)(
* terminator.
*
* @param queryList <b>IN</b>: Query list to measure
- * @param charsRequired <b>OUT</b>: Length of the string representation in characters <b>excluding</b> terminator
+ * @param charsRequired <b>OUT</b>: Length of the string representation in characters
+ * <b>excluding</b> terminator
* @param spaceToPlus <b>IN</b>: Whether to convert ' ' to '+' or not
* @param normalizeBreaks <b>IN</b>: Whether to convert CR and LF to CR-LF or not.
* @return Error code or 0 on success
@@ -861,11 +887,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequired)(
* @see uriComposeQueryExA
* @since 0.7.0
*/
-URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)(
- const URI_TYPE(QueryList) * queryList,
- int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks);
-
-
+URI_PUBLIC int
+ URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
+ int * charsRequired, UriBool spaceToPlus,
+ UriBool normalizeBreaks);
/**
* Converts a query list structure back to a query string.
@@ -875,8 +900,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)(
*
* @param dest <b>OUT</b>: Output destination
* @param queryList <b>IN</b>: Query list to convert
- * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
- * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long!
+ * @param maxChars <b>IN</b>: Maximum number of characters to copy
+ * <b>including</b> terminator
+ * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than
+ * maxChars even if the query list is too long!
* @return Error code or 0 on success
*
* @see uriComposeQueryExA
@@ -890,9 +917,8 @@ URI_PUBLIC int URI_FUNC(ComposeQueryCharsRequiredEx)(
* @since 0.7.0
*/
URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten);
-
-
+ const URI_TYPE(QueryList) * queryList, int maxChars,
+ int * charsWritten);
/**
* Converts a query list structure back to a query string.
@@ -900,8 +926,10 @@ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
*
* @param dest <b>OUT</b>: Output destination
* @param queryList <b>IN</b>: Query list to convert
- * @param maxChars <b>IN</b>: Maximum number of characters to copy <b>including</b> terminator
- * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than maxChars even if the query list is too long!
+ * @param maxChars <b>IN</b>: Maximum number of characters to copy
+ * <b>including</b> terminator
+ * @param charsWritten <b>OUT</b>: Number of characters written, can be lower than
+ * maxChars even if the query list is too long!
* @param spaceToPlus <b>IN</b>: Whether to convert ' ' to '+' or not
* @param normalizeBreaks <b>IN</b>: Whether to convert CR and LF to CR-LF or not.
* @return Error code or 0 on success
@@ -917,10 +945,9 @@ URI_PUBLIC int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
* @since 0.7.0
*/
URI_PUBLIC int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
- UriBool spaceToPlus, UriBool normalizeBreaks);
-
-
+ const URI_TYPE(QueryList) * queryList,
+ int maxChars, int * charsWritten,
+ UriBool spaceToPlus, UriBool normalizeBreaks);
/**
* Converts a query list structure back to a query string.
@@ -943,9 +970,7 @@ URI_PUBLIC int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
* @since 0.7.0
*/
URI_PUBLIC int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList);
-
-
+ const URI_TYPE(QueryList) * queryList);
/**
* Converts a query list structure back to a query string.
@@ -968,10 +993,9 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
* @since 0.7.0
*/
URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList,
- UriBool spaceToPlus, UriBool normalizeBreaks);
-
-
+ const URI_TYPE(QueryList) * queryList,
+ UriBool spaceToPlus,
+ UriBool normalizeBreaks);
/**
* Converts a query list structure back to a query string.
@@ -994,11 +1018,10 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
* @since 0.9.0
*/
URI_PUBLIC int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList,
- UriBool spaceToPlus, UriBool normalizeBreaks,
- UriMemoryManager * memory);
-
-
+ const URI_TYPE(QueryList) * queryList,
+ UriBool spaceToPlus,
+ UriBool normalizeBreaks,
+ UriMemoryManager * memory);
/**
* Constructs a query list from the raw query string of a given URI.
@@ -1018,10 +1041,9 @@ URI_PUBLIC int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest,
* @see uriFreeQueryListMmA
* @since 0.7.0
*/
-URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest,
- int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast);
-
-
+URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) * *dest, int * itemCount,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
/**
* Constructs a query list from the raw query string of a given URI.
@@ -1041,11 +1063,11 @@ URI_PUBLIC int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest,
* @see uriFreeQueryListA
* @since 0.7.0
*/
-URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest,
- int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast,
- UriBool plusToSpace, UriBreakConversion breakConversion);
-
-
+URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) * *dest,
+ int * itemCount, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriBool plusToSpace,
+ UriBreakConversion breakConversion);
/**
* Constructs a query list from the raw query string of a given URI.
@@ -1066,12 +1088,12 @@ URI_PUBLIC int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest,
* @see uriFreeQueryListMmA
* @since 0.9.0
*/
-URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest,
- int * itemCount, const URI_CHAR * first, const URI_CHAR * afterLast,
- UriBool plusToSpace, UriBreakConversion breakConversion,
- UriMemoryManager * memory);
-
-
+URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) * *dest,
+ int * itemCount, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriBool plusToSpace,
+ UriBreakConversion breakConversion,
+ UriMemoryManager * memory);
/**
* Frees all memory associated with the given query list.
@@ -1084,8 +1106,6 @@ URI_PUBLIC int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest,
*/
URI_PUBLIC void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList);
-
-
/**
* Frees all memory associated with the given query list.
* The structure itself is freed as well.
@@ -1098,9 +1118,7 @@ URI_PUBLIC void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList);
* @since 0.9.0
*/
URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList,
- UriMemoryManager * memory);
-
-
+ UriMemoryManager * memory);
/**
* Makes the %URI hold copies of strings so that it no longer depends
@@ -1117,8 +1135,6 @@ URI_PUBLIC int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList,
*/
URI_PUBLIC int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri);
-
-
/**
* Makes the %URI hold copies of strings so that it no longer depends
* on the original %URI string. If the %URI is already owner of copies,
@@ -1131,16 +1147,1163 @@ URI_PUBLIC int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri);
* @see uriMakeOwnerA
* @since 0.9.4
*/
-URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory);
+URI_PUBLIC int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
+/**
+ * Determines if the given text range contains a well-formed fragment
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentA
+ * @see uriSetFragmentMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+/**
+ * Determines if the given text range contains a well-formed IPv4 address
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp4MmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
-#ifdef __cplusplus
-}
-#endif
+/**
+ * Determines if the given text range contains a well-formed IPv6 address
+ * according to RFC 3986 or not.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_SUCCESS</c> if non-<c>NULL</c> and well-formed, else an error
+ * code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriParseIpSixAddressA
+ * @see uriParseIpSixAddressMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast);
+/**
+ * Determines if the given text range contains a well-formed IPv6 address
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return <c>URI_SUCCESS</c> if non-<c>NULL</c> and well-formed, else an error
+ * code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+/**
+ * Determines if the given text range contains a well-formed IPvFuture address
+ * according to RFC 3986 or not.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_SUCCESS</c> if non-<c>NULL</c> and well-formed, else an error
+ * code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostIpFutureMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
-#endif
+/**
+ * Determines if the given text range contains a well-formed IPvFuture address
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return <c>URI_SUCCESS</c> if non-<c>NULL</c> and well-formed, else an error
+ * code
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostIpFutureMmA
+ * @since 0.9.9
+ */
+int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Determines if the given text range contains a well-formed registered host name
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetHostRegNameA
+ * @see uriSetHostRegNameMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Determines if the given text range contains a well-formed path
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @param hasHost <b>IN</b>: Whether the target %URI has a non-<c>NULL</c> host set or
+ * not
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetPathA
+ * @see uriSetPathMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriBool hasHost);
+
+/**
+ * Determines if the given text range contains a well-formed port text
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetPortTextA
+ * @see uriSetPortTextMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Determines if the given text range contains a well-formed query
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetQueryA
+ * @see uriSetQueryMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Determines if the given text range contains a well-formed scheme
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetSchemeA
+ * @see uriSetSchemeMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Determines if the given text range contains a well-formed user info
+ * according to RFC 3986 or not.
+ *
+ * @param first <b>IN</b>: Pointer to first character
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in
+ * @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else
+ * <c>URI_FALSE</c>
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriIsWellFormedPathA
+ * @see uriIsWellFormedPortA
+ * @see uriIsWellFormedQueryA
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetUserInfoA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the fragment of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the fragment of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedFragmentA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriIsWellFormedHostIp6A
+ * @see uriIsWellFormedHostIp6MmA
+ * @see uriIsWellFormedHostIpFutureA
+ * @see uriIsWellFormedHostIpFutureMmA
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostRegNameA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp6A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp6A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the host of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedHostIp4A
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the path of the given %URI to the given value.
+ *
+ * Non-<c>NULL</c> values must start with a leading slash for %URIs that have a host.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPathA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPathMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the path of the given %URI to the given value.
+ *
+ * Non-<c>NULL</c> values must start with a leading slash for %URIs that have a host.
+ *
+ * The %URI must have a non-<c>NULL</c> host set.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPathA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPathA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory);
+
+/**
+ * Sets the port text of the given %URI to the given value.
+ *
+ * The %URI must have a non-<c>NULL</c> host set.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPortA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the port text of the given %URI to the given value.
+ *
+ * The %URI must have a non-<c>NULL</c> host set.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedPortA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the query of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedQueryA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the query of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedQueryA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the scheme of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the scheme of the given %URI to the given value.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedSchemeA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Sets the user info of the given %URI to the given value.
+ *
+ * The %URI must have a non-<c>NULL</c> host set.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * Uses default libc-based memory manager.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentA
+ * @see uriSetHostAutoA
+ * @see uriSetHostIp4A
+ * @see uriSetHostIp6A
+ * @see uriSetHostIpFutureA
+ * @see uriSetHostRegNameA
+ * @see uriSetPortTextA
+ * @see uriSetQueryA
+ * @see uriSetSchemeA
+ * @see uriSetUserInfoMmA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+
+/**
+ * Sets the user info of the given %URI to the given value.
+ *
+ * The %URI must have a non-<c>NULL</c> host set.
+ *
+ * Parameters <c>first</c> and <c>afterLast</c> must both be <c>NULL</c>
+ * or non-<c>NULL</c> at the same time.
+ *
+ * The function may make the %URI own its memory if needed (if it is not already owned).
+ *
+ * For all return values but <c>URI_ERROR_MALLOC</c>, all-or-nothing behavior
+ * can be expected, e.g. trying to apply a malformed value will leave the
+ * %URI unchanged.
+ *
+ * @param uri <b>INOUT</b>: %URI to modify
+ * @param first <b>IN</b>: Pointer to first character, can be <c>NULL</c>
+ * @param afterLast <b>IN</b>: Pointer to character after the last one still in, can be
+ * <c>NULL</c>
+ * @param memory <b>IN</b>: Memory manager to use, <c>NULL</c> for default libc
+ * @return Error code or 0 on success
+ *
+ * @see uriIsWellFormedUserInfoA
+ * @see uriSetFragmentMmA
+ * @see uriSetHostAutoMmA
+ * @see uriSetHostIp4MmA
+ * @see uriSetHostIp6MmA
+ * @see uriSetHostIpFutureMmA
+ * @see uriSetHostRegNameMmA
+ * @see uriSetPortTextMmA
+ * @see uriSetQueryMmA
+ * @see uriSetSchemeMmA
+ * @see uriSetUserInfoA
+ * @since 0.9.9
+ */
+URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+/**
+ * Obtain the base runtime version of uriparser.
+ *
+ * The string returned is based on the compile time version
+ * of uriparser.
+ *
+ * @note Distributors may have applied backports of security
+ * fixes (potentially with adjusting packaging version but often
+ * <em>without</em> adjusting runtime version)
+ * or even fully custom patches. As a result, the version string
+ * returned serves as nothing more than "based on that version",
+ * it does not guarantee equivalence to vanilla upstream releases
+ * or absence of additional downstream patches.
+ * It is nothing more than "a hint" and MUST NEVER be used to
+ * make decisions on in application code at runtime.
+ *
+ * @return Pointer to a read-only zero terminated version string
+ *
+ * @since 0.9.9
+ */
+URI_PUBLIC const URI_CHAR * URI_FUNC(BaseRuntimeVersion)(void);
+
+# ifdef __cplusplus
+}
+# endif
+
+# endif
#endif
diff --git a/include/uriparser/UriBase.h b/include/uriparser/UriBase.h
index dc3883e..abadcae 100644
--- a/include/uriparser/UriBase.h
+++ b/include/uriparser/UriBase.h
@@ -43,140 +43,136 @@
*/
#ifndef URI_BASE_H
-#define URI_BASE_H 1
-
-
+# define URI_BASE_H 1
/* Version helper macro */
-#define URI_ANSI_TO_UNICODE(x) L##x
-
-
+# define URI_ANSI_TO_UNICODE_HELPER(x) L##x
+# define URI_ANSI_TO_UNICODE(x) URI_ANSI_TO_UNICODE_HELPER(x)
/* Version */
-#define URI_VER_MAJOR 0
-#define URI_VER_MINOR 9
-#define URI_VER_RELEASE 8
-#define URI_VER_SUFFIX_ANSI ""
-#define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI)
-
-
+# define URI_VER_MAJOR 1
+# define URI_VER_MINOR 0
+# define URI_VER_RELEASE 1
+# define URI_VER_SUFFIX_ANSI ""
+# define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI)
/* More version helper macros */
-#define URI_INT_TO_ANSI_HELPER(x) #x
-#define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x)
-
-#define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x)
-#define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x)
-
-#define URI_VER_ANSI_HELPER(ma, mi, r, s) \
- URI_INT_TO_ANSI(ma) "." \
- URI_INT_TO_ANSI(mi) "." \
- URI_INT_TO_ANSI(r) \
- s
+# define URI_INT_TO_ANSI_HELPER(x) #x
+# define URI_INT_TO_ANSI(x) URI_INT_TO_ANSI_HELPER(x)
-#define URI_VER_UNICODE_HELPER(ma, mi, r, s) \
- URI_INT_TO_UNICODE(ma) L"." \
- URI_INT_TO_UNICODE(mi) L"." \
- URI_INT_TO_UNICODE(r) \
- s
+# define URI_INT_TO_UNICODE_HELPER(x) URI_ANSI_TO_UNICODE(#x)
+# define URI_INT_TO_UNICODE(x) URI_INT_TO_UNICODE_HELPER(x)
+# define URI_VER_ANSI_HELPER(ma, mi, r, s) \
+ URI_INT_TO_ANSI(ma) "." URI_INT_TO_ANSI(mi) "." URI_INT_TO_ANSI(r) s
+# define URI_VER_UNICODE_HELPER(ma, mi, r, s) \
+ URI_INT_TO_UNICODE(ma) L"." URI_INT_TO_UNICODE(mi) L"." URI_INT_TO_UNICODE(r) s
/* Full version strings */
-#define URI_VER_ANSI URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI)
-#define URI_VER_UNICODE URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_UNICODE)
-
-
+# define URI_VER_ANSI \
+ URI_VER_ANSI_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, \
+ URI_VER_SUFFIX_ANSI)
+# define URI_VER_UNICODE \
+ URI_VER_UNICODE_HELPER(URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, \
+ URI_VER_SUFFIX_UNICODE)
/* Unused parameter macro */
-#ifdef __GNUC__
-# define URI_UNUSED(x) unused_##x __attribute__((unused))
-#else
-# define URI_UNUSED(x) x
-#endif
-
-
+# ifdef __GNUC__
+# define URI_UNUSED(x) unused_##x __attribute__((unused))
+# else
+# define URI_UNUSED(x) x
+# endif
/* Import/export decorator */
-#if defined(_MSC_VER)
-# if defined(URI_STATIC_BUILD)
-# define URI_PUBLIC
-# elif defined(URI_LIBRARY_BUILD)
-# define URI_PUBLIC __declspec(dllexport)
-# else
-# define URI_PUBLIC __declspec(dllimport)
-# endif
-#else
-# if ! defined(URI_LIBRARY_BUILD) || ! defined(URI_VISIBILITY)
-# define URI_PUBLIC
-# else
-# define URI_PUBLIC __attribute__ ((visibility("default")))
-# endif
-#endif
-
-
+# if defined(_MSC_VER)
+# if defined(URI_STATIC_BUILD)
+# define URI_PUBLIC
+# elif defined(URI_LIBRARY_BUILD)
+# define URI_PUBLIC __declspec(dllexport)
+# else
+# define URI_PUBLIC __declspec(dllimport)
+# endif
+# else
+# if !defined(URI_LIBRARY_BUILD) || !defined(URI_VISIBILITY)
+# define URI_PUBLIC
+# else
+# define URI_PUBLIC __attribute__((visibility("default")))
+# endif
+# endif
typedef int UriBool; /**< Boolean type */
-#define URI_TRUE 1
-#define URI_FALSE 0
-
-
+# define URI_TRUE 1
+# define URI_FALSE 0
/* Shared errors */
-#define URI_SUCCESS 0
-#define URI_ERROR_SYNTAX 1 /* Parsed text violates expected format */
-#define URI_ERROR_NULL 2 /* One of the params passed was NULL
- although it mustn't be */
-#define URI_ERROR_MALLOC 3 /* Requested memory could not be allocated */
-#define URI_ERROR_OUTPUT_TOO_LARGE 4 /* Some output is to large for the receiving buffer */
-#define URI_ERROR_NOT_IMPLEMENTED 8 /* The called function is not implemented yet */
-#define URI_ERROR_RANGE_INVALID 9 /* The parameters passed contained invalid ranges */
-#define URI_ERROR_MEMORY_MANAGER_INCOMPLETE 10 /* [>=0.9.0] The UriMemoryManager passed does not implement all needed functions */
-
+# define URI_SUCCESS 0
+# define URI_ERROR_SYNTAX 1 /* Parsed text violates expected format */
+# define URI_ERROR_NULL \
+ 2 /* One of the params passed was NULL although it mustn't be \
+ */
+# define URI_ERROR_MALLOC 3 /* Requested memory could not be allocated */
+# define URI_ERROR_OUTPUT_TOO_LARGE \
+ 4 /* Some output is to large for the receiving buffer */
+# define URI_ERROR_NOT_IMPLEMENTED 8 /* The called function is not implemented yet */
+# define URI_ERROR_RANGE_INVALID 9 /* The parameters passed contained invalid ranges */
+# define URI_ERROR_MEMORY_MANAGER_INCOMPLETE \
+ 10 /* [>=0.9.0] The UriMemoryManager passed does not implement all needed \
+ functions */
/* Errors specific to ToString */
-#define URI_ERROR_TOSTRING_TOO_LONG URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE instead */
+# define URI_ERROR_TOSTRING_TOO_LONG \
+ URI_ERROR_OUTPUT_TOO_LARGE /* Deprecated, test for URI_ERROR_OUTPUT_TOO_LARGE \
+ instead */
/* Errors specific to AddBaseUri */
-#define URI_ERROR_ADDBASE_REL_BASE 5 /* Given base is not absolute */
+# define URI_ERROR_ADDBASE_REL_BASE 5 /* Given base is not absolute */
/* Errors specific to RemoveBaseUri */
-#define URI_ERROR_REMOVEBASE_REL_BASE 6 /* Given base is not absolute */
-#define URI_ERROR_REMOVEBASE_REL_SOURCE 7 /* Given base is not absolute */
+# define URI_ERROR_REMOVEBASE_REL_BASE 6 /* Given base is not absolute */
+# define URI_ERROR_REMOVEBASE_REL_SOURCE 7 /* Given base is not absolute */
/* Error specific to uriTestMemoryManager */
-#define URI_ERROR_MEMORY_MANAGER_FAULTY 11 /* [>=0.9.0] The UriMemoryManager given did not pass the test suite */
-
-
-#ifndef URI_DOXYGEN
-# include <stdio.h> /* For NULL, snprintf */
-# include <ctype.h> /* For wchar_t */
-# include <string.h> /* For strlen, memset, memcpy */
-# include <stdlib.h> /* For malloc */
-#endif /* URI_DOXYGEN */
-
-
+# define URI_ERROR_MEMORY_MANAGER_FAULTY \
+ 11 /* [>=0.9.0] The UriMemoryManager given did not pass the test suite */
+
+/* Error specific to uriSetUserInfo */
+# define URI_ERROR_SETUSERINFO_HOST_NOT_SET \
+ 12 /* [>=0.9.9] The %URI given does not have the host set */
+
+/* Error specific to uriSetPort */
+# define URI_ERROR_SETPORT_HOST_NOT_SET \
+ 13 /* [>=0.9.9] The %URI given does not have the host set */
+
+/* Error specific to uriSetHost* */
+# define URI_ERROR_SETHOST_USERINFO_SET \
+ 14 /* [>=0.9.9] The %URI given does have user info set */
+# define URI_ERROR_SETHOST_PORT_SET \
+ 15 /* [>=0.9.9] The %URI given does have a port set */
+
+# ifndef URI_DOXYGEN
+# include <stdio.h> /* For NULL, snprintf */
+# include <ctype.h> /* For wchar_t */
+# include <string.h> /* For strlen, memset, memcpy */
+# include <stdlib.h> /* For malloc */
+# endif /* URI_DOXYGEN */
/**
* Holds an IPv4 address.
*/
typedef struct UriIp4Struct {
- unsigned char data[4]; /**< Each octet in one byte */
+ unsigned char data[4]; /**< Each octet in one byte */
} UriIp4; /**< @copydoc UriIp4Struct */
-
-
/**
* Holds an IPv6 address.
*/
typedef struct UriIp6Struct {
- unsigned char data[16]; /**< Each quad in two bytes */
+ unsigned char data[16]; /**< Each quad in two bytes */
} UriIp6; /**< @copydoc UriIp6Struct */
-
-struct UriMemoryManagerStruct; /* foward declaration to break loop */
-
+struct UriMemoryManagerStruct; /* forward declaration to break loop */
/**
* Function signature that custom malloc(3) functions must conform to
@@ -204,7 +200,8 @@ typedef void * (*UriFuncRealloc)(struct UriMemoryManagerStruct *, void *, size_t
*
* @since 0.9.0
*/
-typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, size_t, size_t);
+typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, size_t,
+ size_t);
/**
* Function signature that custom free(3) functions must conform to
@@ -213,7 +210,6 @@ typedef void * (*UriFuncReallocarray)(struct UriMemoryManagerStruct *, void *, s
*/
typedef void (*UriFuncFree)(struct UriMemoryManagerStruct *, void *);
-
/**
* Class-like interface of custom memory managers
*
@@ -224,78 +220,87 @@ typedef void (*UriFuncFree)(struct UriMemoryManagerStruct *, void *);
* @since 0.9.0
*/
typedef struct UriMemoryManagerStruct {
- UriFuncMalloc malloc; /**< Pointer to custom malloc(3) */
- UriFuncCalloc calloc; /**< Pointer to custom calloc(3); to emulate using malloc and memset see uriEmulateCalloc */
- UriFuncRealloc realloc; /**< Pointer to custom realloc(3) */
- UriFuncReallocarray reallocarray; /**< Pointer to custom reallocarray(3); to emulate using realloc see uriEmulateReallocarray */
- UriFuncFree free; /**< Pointer to custom free(3) */
- void * userData; /**< Pointer to data that the other function members need access to */
+ UriFuncMalloc malloc; /**< Pointer to custom malloc(3) */
+ UriFuncCalloc calloc; /**< Pointer to custom calloc(3); to emulate using malloc and
+ memset see uriEmulateCalloc */
+ UriFuncRealloc realloc; /**< Pointer to custom realloc(3) */
+ UriFuncReallocarray reallocarray; /**< Pointer to custom reallocarray(3); to emulate
+ using realloc see uriEmulateReallocarray */
+ UriFuncFree free; /**< Pointer to custom free(3) */
+ void *
+ userData; /**< Pointer to data that the other function members need access to */
} UriMemoryManager; /**< @copydoc UriMemoryManagerStruct */
-
/**
* Specifies a line break conversion mode.
*/
typedef enum UriBreakConversionEnum {
- URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */
- URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */
- URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */
- URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */
- URI_BR_TO_WINDOWS = URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */
- URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */
- URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */
+ URI_BR_TO_LF, /**< Convert to Unix line breaks ("\\x0a") */
+ URI_BR_TO_CRLF, /**< Convert to Windows line breaks ("\\x0d\\x0a") */
+ URI_BR_TO_CR, /**< Convert to Macintosh line breaks ("\\x0d") */
+ URI_BR_TO_UNIX = URI_BR_TO_LF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_LF */
+ URI_BR_TO_WINDOWS =
+ URI_BR_TO_CRLF, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CRLF */
+ URI_BR_TO_MAC = URI_BR_TO_CR, /**< @copydoc UriBreakConversionEnum::URI_BR_TO_CR */
+ URI_BR_DONT_TOUCH /**< Copy line breaks unmodified */
} UriBreakConversion; /**< @copydoc UriBreakConversionEnum */
-
-
/**
* Specifies which component of a %URI has to be normalized.
*/
typedef enum UriNormalizationMaskEnum {
- URI_NORMALIZED = 0, /**< Do not normalize anything */
- URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */
- URI_NORMALIZE_USER_INFO = 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */
- URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */
- URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and redundant dot segments) */
- URI_NORMALIZE_QUERY = 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */
- URI_NORMALIZE_FRAGMENT = 1 << 5 /**< Normalize fragment (fix uppercase percent-encodings) */
+ URI_NORMALIZED = 0, /**< Do not normalize anything */
+ URI_NORMALIZE_SCHEME = 1 << 0, /**< Normalize scheme (fix uppercase letters) */
+ URI_NORMALIZE_USER_INFO =
+ 1 << 1, /**< Normalize user info (fix uppercase percent-encodings) */
+ URI_NORMALIZE_HOST = 1 << 2, /**< Normalize host (fix uppercase letters) */
+ URI_NORMALIZE_PATH = 1 << 3, /**< Normalize path (fix uppercase percent-encodings and
+ redundant dot segments) */
+ URI_NORMALIZE_QUERY =
+ 1 << 4, /**< Normalize query (fix uppercase percent-encodings) */
+ URI_NORMALIZE_FRAGMENT =
+ 1 << 5, /**< Normalize fragment (fix uppercase percent-encodings) */
+ URI_NORMALIZE_PORT = 1 << 6 /**< Normalize port (drop leading zeros) @since 0.9.9 */
} UriNormalizationMask; /**< @copydoc UriNormalizationMaskEnum */
-
-
/**
* Specifies how to resolve %URI references.
*/
typedef enum UriResolutionOptionsEnum {
- URI_RESOLVE_STRICTLY = 0, /**< Full RFC conformance */
- URI_RESOLVE_IDENTICAL_SCHEME_COMPAT = 1 << 0 /**< Treat %URI to resolve with identical scheme as having no scheme */
+ URI_RESOLVE_STRICTLY = 0, /**< Full RFC conformance */
+ URI_RESOLVE_IDENTICAL_SCHEME_COMPAT =
+ 1 << 0 /**< Treat %URI to resolve with identical scheme as having no scheme */
} UriResolutionOptions; /**< @copydoc UriResolutionOptionsEnum */
-
-
/**
- * Wraps a memory manager backend that only provides malloc and free
- * to make a complete memory manager ready to be used.
+ * Wraps a memory manager backend that only provides <c>malloc(3)</c> and
+ * <c>free(3)</c> to make a complete memory manager ready to be used.
*
* The core feature of this wrapper is that you don't need to implement
- * realloc if you don't want to. The wrapped memory manager uses
- * backend->malloc, memcpy, and backend->free and soieof(size_t) extra
- * bytes per allocation to emulate fallback realloc for you.
+ * <c>realloc(3)</c> if you don't want to. The wrapped memory manager uses
+ * <c>backend-&gt;malloc</c>, <c>memcpy(3)</c>, and <c>backend-&gt;free</c> and
+ * (at least) <c>sizeof(size_t)</c> extra bytes per allocation to emulate
+ * fallback <c>realloc(3)</c> for you.
*
- * memory->calloc is uriEmulateCalloc.
- * memory->free uses backend->free and handles the size header.
- * memory->malloc uses backend->malloc and adds a size header.
- * memory->realloc uses memory->malloc, memcpy, and memory->free and reads
- * the size header.
- * memory->reallocarray is uriEmulateReallocarray.
+ * <ul>
+ * <li><c>memory-&gt;calloc</c> is <c>uriEmulateCalloc</c>.</li>
+ * <li><c>memory-&gt;free</c> uses <c>backend-&gt;free</c>,
+ * and handles the size header.</li>
+ * <li><c>memory-&gt;malloc</c> uses <c>backend-&gt;malloc</c>,
+ * and adds a size header.</li>
+ * <li><c>memory-&gt;realloc</c> uses <c>memory-&gt;malloc</c>,
+ * <c>memcpy(3)</c> and <c>memory-&gt;free</c>,
+ * and reads the size header.</li>
+ * <li><c>memory-&gt;reallocarray</c> is <c>uriEmulateReallocarray</c>.</li>
+ * </ul>
*
- * The internal workings behind memory->free, memory->malloc, and
- * memory->realloc may change so the functions exposed by these function
- * pointer sshould be consided internal and not public API.
+ * The internal workings behind <c>memory-&gt;free</c>, <c>memory-&gt;malloc</c>,
+ * and <c>memory-&gt;realloc</c> may change, and the functions exposed by these
+ * function pointers should be considered internal and not public API.
*
* @param memory <b>OUT</b>: Where to write the wrapped memory manager to
* @param backend <b>IN</b>: Memory manager to use as a backend
- * @return Error code or 0 on success
+ * @return Error code or 0 on success
*
* @see uriEmulateCalloc
* @see uriEmulateReallocarray
@@ -303,12 +308,10 @@ typedef enum UriResolutionOptionsEnum {
* @since 0.9.0
*/
URI_PUBLIC int uriCompleteMemoryManager(UriMemoryManager * memory,
- UriMemoryManager * backend);
-
-
+ UriMemoryManager * backend);
/**
- * Offers emulation of calloc(3) based on memory->malloc and memset.
+ * Offers emulation of calloc(3) based on memory-&gt;malloc and memset.
* See "man 3 calloc" as well.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
@@ -321,17 +324,14 @@ URI_PUBLIC int uriCompleteMemoryManager(UriMemoryManager * memory,
* @see UriMemoryManager
* @since 0.9.0
*/
-URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory,
- size_t nmemb, size_t size);
-
-
+URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size);
/**
- * Offers emulation of reallocarray(3) based on memory->realloc.
+ * Offers emulation of reallocarray(3) based on memory-&gt;realloc.
* See "man 3 reallocarray" as well.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
- * @param ptr <b>IN</b>: Pointer allocated using memory->malloc/... or NULL
+ * @param ptr <b>IN</b>: Pointer allocated using memory-&gt;malloc/... or NULL
* @param nmemb <b>IN</b>: Number of elements to allocate
* @param size <b>IN</b>: Size in bytes per element
* @return Pointer to allocated memory or NULL
@@ -341,10 +341,8 @@ URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory,
* @see UriMemoryManager
* @since 0.9.0
*/
-URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory,
- void * ptr, size_t nmemb, size_t size);
-
-
+URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory, void * ptr,
+ size_t nmemb, size_t size);
/**
* Run multiple tests against a given memory manager.
@@ -356,7 +354,11 @@ URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory,
* 5. and frees that memory.
*
* It is recommended to compile with AddressSanitizer enabled
- * to take full advantage of uriTestMemoryManager.
+ * to take full advantage of <c>uriTestMemoryManager</c>.
+ *
+ * For backwards-compatibility, <c>uriTestMemoryManager</c>
+ * does not challenge pointer alignment; please see
+ * <c>uriTestMemoryManagerEx</c> for that feature.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
* @return Error code or 0 on success
@@ -364,10 +366,37 @@ URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory,
* @see uriEmulateCalloc
* @see uriEmulateReallocarray
* @see UriMemoryManager
+ * @see uriTestMemoryManagerEx
* @since 0.9.0
*/
URI_PUBLIC int uriTestMemoryManager(UriMemoryManager * memory);
-
+/**
+ * Run multiple tests against a given memory manager.
+ * For example, one test
+ * 1. allocates a small amount of memory,
+ * 2. writes some magic bytes to it,
+ * 3. reallocates it,
+ * 4. checks that previous values are still present,
+ * 5. and frees that memory.
+ *
+ * It is recommended to compile with both AddressSanitizer and
+ * UndefinedBehaviorSanitizer enabled to take full advantage of
+ * <c>uriTestMemoryManagerEx</c>. Note that environment variable
+ * <c>UBSAN_OPTIONS</c> may need adjustment to make UndefinedBehaviorSanitizer
+ * fatal (which by default it is not).
+ *
+ * @param memory <b>IN</b>: Memory manager to use, should not be NULL
+ * @param challengeAlignment <b>IN</b>: Whether to challenge pointer alignment
+ * @return Error code or 0 on success
+ *
+ * @see uriEmulateCalloc
+ * @see uriEmulateReallocarray
+ * @see UriMemoryManager
+ * @see uriTestMemoryManager
+ * @since 1.0.0
+ */
+URI_PUBLIC int uriTestMemoryManagerEx(UriMemoryManager * memory,
+ UriBool challengeAlignment);
#endif /* URI_BASE_H */
diff --git a/include/uriparser/UriDefsAnsi.h b/include/uriparser/UriDefsAnsi.h
index af581b9..17aed1b 100644
--- a/include/uriparser/UriDefsAnsi.h
+++ b/include/uriparser/UriDefsAnsi.h
@@ -46,24 +46,18 @@
/* Allow multi inclusion */
#include "UriDefsConfig.h"
-
-
#undef URI_CHAR
#define URI_CHAR char
#undef _UT
#define _UT(x) x
-
-
#undef URI_FUNC
#define URI_FUNC(x) uri##x##A
#undef URI_TYPE
#define URI_TYPE(x) Uri##x##A
-
-
#undef URI_STRLEN
#define URI_STRLEN strlen
#undef URI_STRCPY
@@ -76,7 +70,7 @@
/* TODO Remove on next source-compatibility break */
#undef URI_SNPRINTF
#if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32))
-# define URI_SNPRINTF _snprintf
+# define URI_SNPRINTF _snprintf
#else
-# define URI_SNPRINTF snprintf
+# define URI_SNPRINTF snprintf
#endif
diff --git a/include/uriparser/UriDefsConfig.h b/include/uriparser/UriDefsConfig.h
index 51bc93e..79d485d 100644
--- a/include/uriparser/UriDefsConfig.h
+++ b/include/uriparser/UriDefsConfig.h
@@ -43,59 +43,51 @@
*/
#ifndef URI_DEFS_CONFIG_H
-#define URI_DEFS_CONFIG_H 1
-
-
+# define URI_DEFS_CONFIG_H 1
/* Deny external overriding */
-#undef URI_ENABLE_ANSI /* Internal for !URI_NO_ANSI */
-#undef URI_ENABLE_UNICODE /* Internal for !URI_NO_UNICODE */
-
-
+# undef URI_ENABLE_ANSI /* Internal for !URI_NO_ANSI */
+# undef URI_ENABLE_UNICODE /* Internal for !URI_NO_UNICODE */
/* Encoding */
-#ifdef URI_NO_ANSI
-# ifdef URI_NO_UNICODE
+# ifdef URI_NO_ANSI
+# ifdef URI_NO_UNICODE
/* No encoding at all */
-# error URI_NO_ANSI and URI_NO_UNICODE cannot go together.
-# else
+# error URI_NO_ANSI and URI_NO_UNICODE cannot go together.
+# else
/* Wide strings only */
-# define URI_ENABLE_UNICODE 1
-# endif
-#else
-# ifdef URI_NO_UNICODE
+# define URI_ENABLE_UNICODE 1
+# endif
+# else
+# ifdef URI_NO_UNICODE
/* Narrow strings only */
-# define URI_ENABLE_ANSI 1
-# else
+# define URI_ENABLE_ANSI 1
+# else
/* Both narrow and wide strings */
-# define URI_ENABLE_ANSI 1
-# define URI_ENABLE_UNICODE 1
-# endif
-#endif
-
-
+# define URI_ENABLE_ANSI 1
+# define URI_ENABLE_UNICODE 1
+# endif
+# endif
/* Function inlining, not ANSI/ISO C! */
-#if defined(URI_DOXYGEN)
-# define URI_INLINE
-#elif defined(__INTEL_COMPILER)
+# if defined(URI_DOXYGEN)
+# define URI_INLINE
+# elif defined(__INTEL_COMPILER)
/* Intel C/C++ */
/* http://predef.sourceforge.net/precomp.html#sec20 */
/* http://www.intel.com/support/performancetools/c/windows/sb/CS-007751.htm#2 */
-# define URI_INLINE __forceinline
-#elif defined(_MSC_VER)
+# define URI_INLINE __forceinline
+# elif defined(_MSC_VER)
/* Microsoft Visual C++ */
/* http://predef.sourceforge.net/precomp.html#sec32 */
/* http://msdn2.microsoft.com/en-us/library/ms882281.aspx */
-# define URI_INLINE __forceinline
-#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
+# define URI_INLINE __forceinline
+# elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
/* C99, "inline" is a keyword */
-# define URI_INLINE inline
-#else
+# define URI_INLINE inline
+# else
/* No inlining */
-# define URI_INLINE
-#endif
-
-
+# define URI_INLINE
+# endif
#endif /* URI_DEFS_CONFIG_H */
diff --git a/include/uriparser/UriDefsUnicode.h b/include/uriparser/UriDefsUnicode.h
index 01421f5..6fce672 100644
--- a/include/uriparser/UriDefsUnicode.h
+++ b/include/uriparser/UriDefsUnicode.h
@@ -46,24 +46,18 @@
/* Allow multi inclusion */
#include "UriDefsConfig.h"
-
-
#undef URI_CHAR
#define URI_CHAR wchar_t
#undef _UT
#define _UT(x) L##x
-
-
#undef URI_FUNC
#define URI_FUNC(x) uri##x##W
#undef URI_TYPE
#define URI_TYPE(x) Uri##x##W
-
-
#undef URI_STRLEN
#define URI_STRLEN wcslen
#undef URI_STRCPY
@@ -76,7 +70,7 @@
/* TODO Remove on next source-compatibility break */
#undef URI_SNPRINTF
#if (defined(__WIN32__) || defined(_WIN32) || defined(WIN32))
-# define URI_SNPRINTF _snwprintf
+# define URI_SNPRINTF _snwprintf
#else
-# define URI_SNPRINTF swprintf
+# define URI_SNPRINTF swprintf
#endif
diff --git a/include/uriparser/UriIp4.h b/include/uriparser/UriIp4.h
index c2e59a6..5f84b62 100644
--- a/include/uriparser/UriIp4.h
+++ b/include/uriparser/UriIp4.h
@@ -44,67 +44,62 @@
*/
#if (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI)) \
- || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \
- || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+ || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* What encodings are enabled? */
-#include "UriDefsConfig.h"
-#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+# include "UriDefsConfig.h"
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriIp4.h"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriIp4.h"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriIp4.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriIp4.h"
+# undef URI_PASS_UNICODE
+# endif
/* Only one pass for each encoding */
-#elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \
- && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
- && !defined(URI_IP4_TWICE_H_UNICODE) && defined(URI_ENABLE_UNICODE))
-# ifdef URI_PASS_ANSI
-# define URI_IP4_TWICE_H_ANSI 1
-# include "UriDefsAnsi.h"
-# else
-# define URI_IP4_TWICE_H_UNICODE 1
-# include "UriDefsUnicode.h"
-# include <wchar.h>
-# endif
-
-
-
-#ifdef __cplusplus
+# elif (defined(URI_PASS_ANSI) && !defined(URI_IP4_TWICE_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_IP4_TWICE_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_IP4_TWICE_H_ANSI 1
+# include "UriDefsAnsi.h"
+# else
+# define URI_IP4_TWICE_H_UNICODE 1
+# include "UriDefsUnicode.h"
+# include <wchar.h>
+# endif
+
+# ifdef __cplusplus
extern "C" {
-#endif
-
-
-
-#ifndef URI_DOXYGEN
-# include "UriBase.h"
-#endif
-
+# endif
+# ifndef URI_DOXYGEN
+# include "UriBase.h"
+# endif
/**
- * Converts a IPv4 text representation into four bytes.
+ * Converts an IPv4 text representation into four bytes.
*
* @param octetOutput Output destination
* @param first First character of IPv4 text to parse
* @param afterLast Position to stop parsing at
* @return Error code or 0 on success
+ *
+ * @see uriParseIpSixAddressA
+ * @see uriParseIpSixAddressMmA
*/
URI_PUBLIC int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
- const URI_CHAR * first, const URI_CHAR * afterLast);
-
-
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
-#ifdef __cplusplus
+# ifdef __cplusplus
}
-#endif
-
+# endif
-
-#endif
+# endif
#endif
diff --git a/make-distcheck.sh b/make-distcheck.sh
index 2968dd0..8492647 100755
--- a/make-distcheck.sh
+++ b/make-distcheck.sh
@@ -70,13 +70,13 @@ check_tarball() (
mkdir build
cd build
- cmake "${@:2}" ..
+ cmake "${@:2}" -DURIPARSER_BUILD_TESTS=ON ..
make
# NOTE: We need to copy some .dll files next to the
# Windows binaries so that they are ready to be executed
if [[ "${*:2}" == *mingw* ]]; then
- cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libgcc_s_sjlj-1.dll ./
+ cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libgcc_s_dw2-1.dll ./
cp /usr/lib/gcc/i686-w64-mingw32/*-posix/libstdc++-6.dll ./
cp /usr/i686-w64-mingw32/lib/libwinpthread-1.dll ./
cp "${GTEST_PREFIX:?}"/bin/libgtest.dll ./
diff --git a/mull.yml b/mull.yml
new file mode 100644
index 0000000..e8ef996
--- /dev/null
+++ b/mull.yml
@@ -0,0 +1,2 @@
+excludePaths:
+ - test/
diff --git a/scripts/edit_version.sh b/scripts/edit_version.sh
index 372b29b..2c590e2 100755
--- a/scripts/edit_version.sh
+++ b/scripts/edit_version.sh
@@ -1,7 +1,7 @@
#! /usr/bin/env bash
kwrite \
- include/uriparser/Uri.h \
- include/uriparser/UriBase.h \
- configure.ac \
- ChangeLog \
- &
+ include/uriparser/Uri.h \
+ include/uriparser/UriBase.h \
+ configure.ac \
+ ChangeLog \
+ &
diff --git a/src/COPYING b/src/COPYING
new file mode 100644
index 0000000..261c741
--- /dev/null
+++ b/src/COPYING
@@ -0,0 +1,36 @@
+uriparser - RFC 3986 URI parsing library
+
+Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/UriCommon.c b/src/UriCommon.c
index 7ba92f2..00256f2 100644
--- a/src/UriCommon.c
+++ b/src/UriCommon.c
@@ -41,576 +41,735 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriCommon.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriCommon.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriCommon.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriCommon.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-#endif
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+# include <stddef.h>
/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
/*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
-
-
void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
- if (uri == NULL) {
- return;
- }
- memset(uri, 0, sizeof(URI_TYPE(Uri)));
+ if (uri == NULL) {
+ return;
+ }
+ memset(uri, 0, sizeof(URI_TYPE(Uri)));
}
-
+int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if (uri->pathHead != NULL) {
+ URI_TYPE(PathSegment) * segWalk = uri->pathHead;
+ while (segWalk != NULL) {
+ URI_TYPE(PathSegment) * const next = segWalk->next;
+ if ((uri->owner == URI_TRUE)
+ && (segWalk->text.first != segWalk->text.afterLast)) {
+ memory->free(memory, (URI_CHAR *)segWalk->text.first);
+ }
+ segWalk->text.first = NULL;
+ segWalk->text.afterLast = NULL;
+ segWalk->next = NULL;
+ memory->free(memory, segWalk);
+ segWalk = next;
+ }
+ uri->pathHead = NULL;
+ uri->pathTail = NULL;
+ }
+
+ return URI_SUCCESS;
+}
/* Compares two text ranges for equal text content */
-int URI_FUNC(CompareRange)(
- const URI_TYPE(TextRange) * a,
- const URI_TYPE(TextRange) * b) {
- int diff;
-
- /* NOTE: Both NULL means equal! */
- if ((a == NULL) || (b == NULL)) {
- return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
- }
-
- /* NOTE: Both NULL means equal! */
- if ((a->first == NULL) || (b->first == NULL)) {
- return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
- }
-
- diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first));
- if (diff > 0) {
- return 1;
- } else if (diff < 0) {
- return -1;
- }
-
- diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first));
-
- if (diff > 0) {
- return 1;
- } else if (diff < 0) {
- return -1;
- }
-
- return diff;
+int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
+ int diff;
+ ptrdiff_t lenA;
+ ptrdiff_t lenB;
+
+ /* NOTE: Both NULL means equal! */
+ if ((a == NULL) || (b == NULL)) {
+ return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
+ }
+
+ /* NOTE: Both NULL means equal! */
+ if ((a->first == NULL) || (b->first == NULL)) {
+ return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
+ }
+
+ lenA = a->afterLast - a->first;
+ lenB = b->afterLast - b->first;
+
+ if (lenA > lenB) {
+ return 1;
+ } else if (lenA < lenB) {
+ return -1;
+ }
+
+ diff = URI_STRNCMP(a->first, b->first, (size_t)lenA);
+
+ if (diff > 0) {
+ return 1;
+ } else if (diff < 0) {
+ return -1;
+ }
+
+ return diff;
}
-
-
-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,
- * i.e. is there a chance of changing semantics by dropping this dot segment?
- *
- * For example, changing "./http://foo" into "http://foo" would change semantics
- * and hence the dot segment is essential to that case and cannot be removed.
- */
- 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) {
- /* .. then let's go remove that segment. */
- /* Last segment? */
- if (walker->next != NULL) {
- /* Not last segment, i.e. first or middle segment
- * OLD: (prev|NULL) <- walker <- next
- * NEW: (prev|NULL) <----------- next */
- walker->next->reserved = prev;
-
- if (prev == NULL) {
- /* First but not last segment
- * OLD: head -> walker -> next
- * NEW: head -----------> next */
- uri->pathHead = walker->next;
- } else {
- /* Middle segment
- * OLD: prev -> walker -> next
- * NEW: prev -----------> next */
- 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) {
- /* We cannot remove traversal beyond because the
- * URI is relative and may be resolved later.
- * So we can simplify "a/../b/d" to "b/d" but
- * we cannot simplify "../b/d" (outside of reference resolution). */
- removeSegment = URI_FALSE;
- } else if ((prev != NULL)
- && ((prev->text.afterLast - prev->text.first) == 2)
- && ((prev->text.first)[0] == _UT('.'))
- && ((prev->text.first)[1] == _UT('.'))) {
- /* We need to protect against mis-simplifying "a/../../b" to "a/b". */
- removeSegment = URI_FALSE;
- }
- }
-
- if (removeSegment) {
- if (prev != NULL) {
- /* Not first segment */
- prevPrev = prev->reserved;
- if (prevPrev != NULL) {
- /* Not even prev is the first one
- * OLD: prevPrev -> prev -> walker -> (next|NULL)
- * NEW: prevPrev -------------------> (next|NULL) */
- prevPrev->next = walker->next;
- if (walker->next != NULL) {
- /* Update parent relationship as well
- * OLD: prevPrev <- prev <- walker <- next
- * NEW: prevPrev <------------------- next */
- 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;
- int freeWalker = URI_TRUE;
-
- /* First segment */
- if (walker->next != NULL) {
- /* First segment of multiple -> update head
- * OLD: head -> walker -> next
- * NEW: head -----------> next */
- uri->pathHead = walker->next;
-
- /* Update parent link as well
- * OLD: head <- walker <- next
- * NEW: head <----------- next */
- walker->next->reserved = NULL;
- } else {
- if (uri->absolutePath) {
- /* First and only segment -> update head
- * OLD: head -> walker -> NULL
- * NEW: head -----------> NULL */
- uri->pathHead = NULL;
-
- /* Last segment -> update tail
- * OLD: tail -> walker
- * NEW: tail -> NULL */
- uri->pathTail = NULL;
- } else {
- /* Re-use segment for "" path segment to represent trailing slash,
- * then update head and tail */
- if (pathOwned && (walker->text.first != walker->text.afterLast)) {
- memory->free(memory, (URI_CHAR *)walker->text.first);
- }
- walker->text.first = URI_FUNC(SafeToPointTo);
- walker->text.afterLast = URI_FUNC(SafeToPointTo);
- freeWalker = URI_FALSE;
- }
- }
-
- if (freeWalker) {
- if (pathOwned && (walker->text.first != walker->text.afterLast)) {
- memory->free(memory, (URI_CHAR *)walker->text.first);
- }
- memory->free(memory, walker);
- }
-
- walker = anotherNextBackup;
- }
- }
- }
- break;
- } /* end of switch */
-
- if (!removeSegment) {
- /* .. then let's move to the next element, and start again. */
- 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;
+UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
+ const URI_TYPE(TextRange) * sourceRange,
+ UriMemoryManager * memory) {
+ const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first);
+ const int lenInBytes = lenInChars * sizeof(URI_CHAR);
+ URI_CHAR * dup = memory->malloc(memory, lenInBytes);
+ if (dup == NULL) {
+ return URI_FALSE;
+ }
+ memcpy(dup, sourceRange->first, lenInBytes);
+ destRange->first = dup;
+ destRange->afterLast = dup + lenInChars;
+
+ return URI_TRUE;
}
+UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
+ const URI_TYPE(TextRange) * sourceRange,
+ UriMemoryManager * memory) {
+ if (sourceRange->first == NULL) {
+ destRange->first = NULL;
+ destRange->afterLast = NULL;
+ } else if (sourceRange->first == sourceRange->afterLast) {
+ destRange->first = URI_FUNC(SafeToPointTo);
+ destRange->afterLast = URI_FUNC(SafeToPointTo);
+ } else {
+ return URI_FUNC(CopyRange)(destRange, sourceRange, memory);
+ }
+
+ return URI_TRUE;
+}
+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,
+ * i.e. is there a chance of changing semantics by dropping this dot
+ * segment?
+ *
+ * For example, changing "./http://foo" into "http://foo" would change
+ * semantics and hence the dot segment is essential to that case and
+ * cannot be removed.
+ *
+ * Other examples that would change semantics are:
+ * - cutting "/.//" down to "//"
+ * - cutting "scheme:/.//" down to "scheme://".
+ */
+ removeSegment = URI_TRUE;
+ if ((walker == uri->pathHead) && (walker->next != NULL)) {
+ /* Detect case "/.//" (with or without scheme) */
+ if ((walker->next->text.first == walker->next->text.afterLast)
+ && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
+ removeSegment = URI_FALSE;
+ /* Detect case "./withcolon:" */
+ } else if (relative) {
+ const URI_CHAR * ch = walker->next->text.first;
+ for (; ch < walker->next->text.afterLast; ch++) {
+ if (*ch == _UT(':')) {
+ removeSegment = URI_FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (removeSegment) {
+ /* .. then let's go remove that segment. */
+ /* Last segment? */
+ if (walker->next != NULL) {
+ /* Not last segment, i.e. first or middle segment
+ * OLD: (prev|NULL) <- walker <- next
+ * NEW: (prev|NULL) <----------- next */
+ walker->next->reserved = prev;
+
+ if (prev == NULL) {
+ /* First but not last segment
+ * OLD: head -> walker -> next
+ * NEW: head -----------> next */
+ uri->pathHead = walker->next;
+ } else {
+ /* Middle segment
+ * OLD: prev -> walker -> next
+ * NEW: prev -----------> next */
+ 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(HasHost)(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) {
+ /* We cannot remove traversal beyond because the
+ * URI is relative and may be resolved later.
+ * So we can simplify "a/../b/d" to "b/d" but
+ * we cannot simplify "../b/d" (outside of reference resolution).
+ */
+ removeSegment = URI_FALSE;
+ } else if ((prev != NULL)
+ && ((prev->text.afterLast - prev->text.first) == 2)
+ && ((prev->text.first)[0] == _UT('.'))
+ && ((prev->text.first)[1] == _UT('.'))) {
+ /* We need to protect against mis-simplifying "a/../../b" to
+ * "a/b". */
+ removeSegment = URI_FALSE;
+ }
+ }
+
+ if (removeSegment) {
+ if (prev != NULL) {
+ /* Not first segment */
+ prevPrev = prev->reserved;
+ if (prevPrev != NULL) {
+ /* Not even prev is the first one
+ * OLD: prevPrev -> prev -> walker -> (next|NULL)
+ * NEW: prevPrev -------------------> (next|NULL) */
+ prevPrev->next = walker->next;
+ if (walker->next != NULL) {
+ /* Update parent relationship as well
+ * OLD: prevPrev <- prev <- walker <- next
+ * NEW: prevPrev <------------------- next */
+ 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 {
+ /* Reuse 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;
+ int freeWalker = URI_TRUE;
+
+ /* First segment */
+ if (walker->next != NULL) {
+ /* First segment of multiple -> update head
+ * OLD: head -> walker -> next
+ * NEW: head -----------> next */
+ uri->pathHead = walker->next;
+
+ /* Update parent link as well
+ * OLD: head <- walker <- next
+ * NEW: head <----------- next */
+ walker->next->reserved = NULL;
+ } else {
+ if (uri->absolutePath) {
+ /* First and only segment -> update head
+ * OLD: head -> walker -> NULL
+ * NEW: head -----------> NULL */
+ uri->pathHead = NULL;
+
+ /* Last segment -> update tail
+ * OLD: tail -> walker
+ * NEW: tail -> NULL */
+ uri->pathTail = NULL;
+ } else {
+ /* Reuse segment for "" path segment to represent trailing
+ * slash, then update head and tail */
+ if (pathOwned
+ && (walker->text.first != walker->text.afterLast)) {
+ memory->free(memory, (URI_CHAR *)walker->text.first);
+ }
+ walker->text.first = URI_FUNC(SafeToPointTo);
+ walker->text.afterLast = URI_FUNC(SafeToPointTo);
+ freeWalker = URI_FALSE;
+ }
+ }
+
+ if (freeWalker) {
+ if (pathOwned
+ && (walker->text.first != walker->text.afterLast)) {
+ memory->free(memory, (URI_CHAR *)walker->text.first);
+ }
+ memory->free(memory, walker);
+ }
+
+ walker = anotherNextBackup;
+ }
+ }
+ }
+ break;
+ } /* end of switch */
+
+ if (!removeSegment) {
+ /* .. then let's move to the next element, and start again. */
+ 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;
+}
/* Properly removes "." and ".." path segments */
UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory) {
- const UriBool ABSOLUTE = URI_FALSE;
- if (uri == NULL) {
- return URI_TRUE;
- }
- return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory);
+ UriMemoryManager * memory) {
+ const UriBool ABSOLUTE = URI_FALSE;
+ if (uri == NULL) {
+ return URI_TRUE;
+ }
+ return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory);
}
-
-
unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
- switch (hexdig) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- return (unsigned char)(9 + hexdig - _UT('9'));
-
- case _UT('a'):
- case _UT('b'):
- case _UT('c'):
- case _UT('d'):
- case _UT('e'):
- case _UT('f'):
- return (unsigned char)(15 + hexdig - _UT('f'));
-
- case _UT('A'):
- case _UT('B'):
- case _UT('C'):
- case _UT('D'):
- case _UT('E'):
- case _UT('F'):
- return (unsigned char)(15 + hexdig - _UT('F'));
-
- default:
- return 0;
- }
+ switch (hexdig) {
+ case URI_SET_DIGIT(_UT):
+ return (unsigned char)(9 + hexdig - _UT('9'));
+ case URI_SET_HEX_LETTER_LOWER(_UT):
+ return (unsigned char)(15 + hexdig - _UT('f'));
+ case URI_SET_HEX_LETTER_UPPER(_UT):
+ return (unsigned char)(15 + hexdig - _UT('F'));
+
+ default:
+ return 0;
+ }
}
-
-
-URI_CHAR URI_FUNC(HexToLetter)(unsigned int value) {
- /* Uppercase recommended in section 2.1. of RFC 3986 *
- * http://tools.ietf.org/html/rfc3986#section-2.1 */
- return URI_FUNC(HexToLetterEx)(value, URI_TRUE);
-}
-
-
-
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
- switch (value) {
- case 0: return _UT('0');
- case 1: return _UT('1');
- case 2: return _UT('2');
- case 3: return _UT('3');
- case 4: return _UT('4');
- case 5: return _UT('5');
- case 6: return _UT('6');
- case 7: return _UT('7');
- case 8: return _UT('8');
- case 9: return _UT('9');
-
- case 10: return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
- case 11: return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
- case 12: return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
- case 13: return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
- case 14: return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
- default: return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
- }
+ switch (value) {
+ case 0:
+ return _UT('0');
+ case 1:
+ return _UT('1');
+ case 2:
+ return _UT('2');
+ case 3:
+ return _UT('3');
+ case 4:
+ return _UT('4');
+ case 5:
+ return _UT('5');
+ case 6:
+ return _UT('6');
+ case 7:
+ return _UT('7');
+ case 8:
+ return _UT('8');
+ case 9:
+ return _UT('9');
+
+ case 10:
+ return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
+ case 11:
+ return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
+ case 12:
+ return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
+ case 13:
+ return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
+ case 14:
+ return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
+ default:
+ return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
+ }
}
-
-
/* Checks if a URI has the host component set. */
-UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri) {
- return (uri != NULL)
- && ((uri->hostText.first != NULL)
- || (uri->hostData.ip4 != NULL)
- || (uri->hostData.ip6 != NULL)
- || (uri->hostData.ipFuture.first != NULL)
- );
+UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri) {
+ /* NOTE: .hostData.ipFuture.first is not being checked, *
+ * because we do check .hostText.first and *
+ * .hostData.ipFuture.first has to be identical to *
+ * .hostText.first if set, and hence there is *
+ * no more information to be gained. */
+ return (uri != NULL)
+ && ((uri->hostText.first != NULL) || (uri->hostData.ip4 != NULL)
+ || (uri->hostData.ip6 != NULL));
}
+/* Copies the path segment list from one URI to another. */
+UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
+ UriMemoryManager * memory) {
+ if (source->pathHead == NULL) {
+ /* No path component */
+ dest->pathHead = NULL;
+ dest->pathTail = NULL;
+ } else {
+ /* Copy list but not the text contained */
+ URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
+ URI_TYPE(PathSegment) * destPrev = NULL;
+ do {
+ URI_TYPE(PathSegment) * cur =
+ memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
+ if (cur == NULL) {
+ /* Fix broken list */
+ if (destPrev != NULL) {
+ destPrev->next = NULL;
+ }
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ /* From this functions usage we know that *
+ * the dest URI cannot be uri->owner */
+ cur->text = sourceWalker->text;
+ if (destPrev == NULL) {
+ /* First segment ever */
+ dest->pathHead = cur;
+ } else {
+ destPrev->next = cur;
+ }
+ destPrev = cur;
+ sourceWalker = sourceWalker->next;
+ } while (sourceWalker != NULL);
+ dest->pathTail = destPrev;
+ dest->pathTail->next = NULL;
+ }
+
+ dest->absolutePath = source->absolutePath;
+ return URI_TRUE;
+}
+/* Copies the authority part of an URI over to another. */
+UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
+ UriMemoryManager * memory) {
+ /* From this functions usage we know that *
+ * the dest URI cannot be uri->owner */
+
+ /* Copy userInfo */
+ dest->userInfo = source->userInfo;
+
+ /* Copy hostText */
+ dest->hostText = source->hostText;
+
+ /* Copy hostData */
+ if (source->hostData.ip4 != NULL) {
+ dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
+ if (dest->hostData.ip4 == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ *(dest->hostData.ip4) = *(source->hostData.ip4);
+ dest->hostData.ip6 = NULL;
+ dest->hostData.ipFuture.first = NULL;
+ dest->hostData.ipFuture.afterLast = NULL;
+ } else if (source->hostData.ip6 != NULL) {
+ dest->hostData.ip4 = NULL;
+ dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
+ if (dest->hostData.ip6 == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ *(dest->hostData.ip6) = *(source->hostData.ip6);
+ dest->hostData.ipFuture.first = NULL;
+ dest->hostData.ipFuture.afterLast = NULL;
+ } else {
+ dest->hostData.ip4 = NULL;
+ dest->hostData.ip6 = NULL;
+ dest->hostData.ipFuture = source->hostData.ipFuture;
+ }
+
+ /* Copy portText */
+ dest->portText = source->portText;
+
+ return URI_TRUE;
+}
-/* Copies the path segment list from one URI to another. */
-UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * source, UriMemoryManager * memory) {
- if (source->pathHead == NULL) {
- /* No path component */
- dest->pathHead = NULL;
- dest->pathTail = NULL;
- } else {
- /* Copy list but not the text contained */
- URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
- URI_TYPE(PathSegment) * destPrev = NULL;
- do {
- URI_TYPE(PathSegment) * cur = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
- if (cur == NULL) {
- /* Fix broken list */
- if (destPrev != NULL) {
- destPrev->next = NULL;
- }
- return URI_FALSE; /* Raises malloc error */
- }
-
- /* From this functions usage we know that *
- * the dest URI cannot be uri->owner */
- cur->text = sourceWalker->text;
- if (destPrev == NULL) {
- /* First segment ever */
- dest->pathHead = cur;
- } else {
- destPrev->next = cur;
- }
- destPrev = cur;
- sourceWalker = sourceWalker->next;
- } while (sourceWalker != NULL);
- dest->pathTail = destPrev;
- dest->pathTail->next = NULL;
- }
-
- dest->absolutePath = source->absolutePath;
- return URI_TRUE;
+UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ URI_TYPE(PathSegment) * segment;
+
+ if (/* Case 1: absolute path, empty first segment */
+ (uri->absolutePath && (uri->pathHead != NULL)
+ && (uri->pathHead->text.afterLast == uri->pathHead->text.first))
+
+ /* Case 2: relative path, empty first and second segment */
+ || (!uri->absolutePath && (uri->pathHead != NULL) && (uri->pathHead->next != NULL)
+ && (uri->pathHead->text.afterLast == uri->pathHead->text.first)
+ && (uri->pathHead->next->text.afterLast
+ == uri->pathHead->next->text.first))) {
+ /* NOOP */
+ } else {
+ return URI_TRUE;
+ }
+
+ segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
+ if (segment == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ /* Insert "." segment in front */
+ segment->next = uri->pathHead;
+ segment->text.first = URI_FUNC(ConstPwd);
+ segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
+ uri->pathHead = segment;
+ return URI_TRUE;
}
+static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+ URI_TYPE(PathSegment) * const segment =
+ memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
-/* Copies the authority part of an URI over to another. */
-UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * source, UriMemoryManager * memory) {
- /* From this functions usage we know that *
- * the dest URI cannot be uri->owner */
-
- /* Copy userInfo */
- dest->userInfo = source->userInfo;
-
- /* Copy hostText */
- dest->hostText = source->hostText;
-
- /* Copy hostData */
- if (source->hostData.ip4 != NULL) {
- dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
- if (dest->hostData.ip4 == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- *(dest->hostData.ip4) = *(source->hostData.ip4);
- dest->hostData.ip6 = NULL;
- dest->hostData.ipFuture.first = NULL;
- dest->hostData.ipFuture.afterLast = NULL;
- } else if (source->hostData.ip6 != NULL) {
- dest->hostData.ip4 = NULL;
- dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
- if (dest->hostData.ip6 == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- *(dest->hostData.ip6) = *(source->hostData.ip6);
- dest->hostData.ipFuture.first = NULL;
- dest->hostData.ipFuture.afterLast = NULL;
- } else {
- dest->hostData.ip4 = NULL;
- dest->hostData.ip6 = NULL;
- dest->hostData.ipFuture = source->hostData.ipFuture;
- }
-
- /* Copy portText */
- dest->portText = source->portText;
-
- return URI_TRUE;
-}
+ if (segment == NULL) {
+ return URI_FALSE; /* i.e. raise malloc error */
+ }
+ segment->next = uri->pathHead;
+ URI_TYPE(TextRange) dotRange;
+ dotRange.first = URI_FUNC(ConstPwd);
+ dotRange.afterLast = URI_FUNC(ConstPwd) + 1;
-UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory) {
- URI_TYPE(PathSegment) * segment;
-
- if ( /* Case 1: absolute path, empty first segment */
- (uri->absolutePath
- && (uri->pathHead != NULL)
- && (uri->pathHead->text.afterLast == uri->pathHead->text.first))
-
- /* Case 2: relative path, empty first and second segment */
- || (!uri->absolutePath
- && (uri->pathHead != NULL)
- && (uri->pathHead->next != NULL)
- && (uri->pathHead->text.afterLast == uri->pathHead->text.first)
- && (uri->pathHead->next->text.afterLast == uri->pathHead->next->text.first))) {
- /* NOOP */
- } else {
- return URI_TRUE;
- }
-
- segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
- if (segment == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
-
- /* Insert "." segment in front */
- segment->next = uri->pathHead;
- segment->text.first = URI_FUNC(ConstPwd);
- segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
- uri->pathHead = segment;
- return URI_TRUE;
-}
+ if (uri->owner == URI_TRUE) {
+ if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) {
+ memory->free(memory, segment);
+ return URI_FALSE; /* i.e. raise malloc error */
+ }
+ } else {
+ segment->text = dotRange; /* copies all members */
+ }
+ uri->pathHead = segment;
+ return URI_TRUE;
+}
-void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory) {
- /* Fix path if only one empty segment */
- if (!uri->absolutePath
- && !URI_FUNC(IsHostSet)(uri)
- && (uri->pathHead != NULL)
- && (uri->pathHead->next == NULL)
- && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
- memory->free(memory, uri->pathHead);
- uri->pathHead = NULL;
- uri->pathTail = NULL;
- }
+/* When dropping a scheme from a URI without a host and with a colon (":")
+ * in the first path segment, a consecutive reparse would rightfully
+ * mis-classify the first path segment as a scheme due to the colon.
+ * To protect against this case, we prepend an artificial "." segment
+ * to the path in here; the function is called after the scheme has
+ * just been dropped.
+ *
+ * 0. We start with parsed URI "scheme:path1:/path2/path3".
+ * 1. We drop the scheme naively and yield "path1:/path2/path3".
+ * 2. We prepend "." and yield unambiguous "./path1:/path2/path3".
+ *
+ * From the view of the RFC 3986 grammar, this is replacing rule path-rootless
+ * by path-noscheme content.
+ *
+ * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
+ * Returns URI_FALSE to signal out-of-memory.
+ */
+UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((uri->absolutePath == URI_TRUE) || (uri->pathHead == NULL)
+ || (uri->scheme.first != NULL) || URI_FUNC(HasHost)(uri)) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+
+ /* Check for troublesome first path segment containing a colon */
+ UriBool colonFound = URI_FALSE;
+ const URI_CHAR * walker = uri->pathHead->text.first;
+
+ while (walker < uri->pathHead->text.afterLast) {
+ if (walker[0] == _UT(':')) {
+ colonFound = URI_TRUE;
+ break;
+ }
+ walker++;
+ }
+
+ assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE));
+
+ if (colonFound == URI_FALSE) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+
+ /* Insert "." segment in front */
+ return URI_FUNC(PrependNewDotSegment)(uri, memory);
}
+/* When dropping a host from a URI without a scheme, an absolute path
+ * and empty first path segment, a consecutive reparse would rightfully
+ * mis-classify the first path segment as a host marker due to the "//".
+ * To protect against this case, we prepend an artificial "." segment
+ * to the path in here; the function is called after the host has
+ * just been dropped.
+ *
+ * 0. We start with parsed URI "//host//path1/path2".
+ * 1. We drop the host naively and yield "//path1/path2".
+ * 2. We insert "./" and yield unambiguous "/.//path1/path2".
+ *
+ * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
+ * Returns URI_FALSE to signal out-of-memory.
+ */
+UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->absolutePath == URI_FALSE)
+ || (uri->pathHead == NULL)
+ || (uri->pathHead == uri->pathTail) /* i.e. no second slash */
+ || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
+ return URI_TRUE; /* i.e. nothing to do */
+ }
+
+ /* Insert "." segment in front */
+ return URI_FUNC(PrependNewDotSegment)(uri, memory);
+}
+void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
+ /* Fix path if only one empty segment */
+ if (!uri->absolutePath && !URI_FUNC(HasHost)(uri) && (uri->pathHead != NULL)
+ && (uri->pathHead->next == NULL)
+ && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
+ memory->free(memory, uri->pathHead);
+ uri->pathHead = NULL;
+ uri->pathTail = NULL;
+ }
+}
#endif
diff --git a/src/UriCommon.h b/src/UriCommon.h
index 42311dd..d141935 100644
--- a/src/UriCommon.h
+++ b/src/UriCommon.h
@@ -38,35 +38,34 @@
*/
#if (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI)) \
- || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \
- || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+ || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* What encodings are enabled? */
-#include <uriparser/UriDefsConfig.h>
-#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+# include <uriparser/UriDefsConfig.h>
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriCommon.h"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriCommon.h"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriCommon.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriCommon.h"
+# undef URI_PASS_UNICODE
+# endif
/* Only one pass for each encoding */
-#elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \
- && defined(URI_ENABLE_ANSI)) || (defined(URI_PASS_UNICODE) \
- && !defined(URI_COMMON_H_UNICODE) && defined(URI_ENABLE_UNICODE))
-# ifdef URI_PASS_ANSI
-# define URI_COMMON_H_ANSI 1
-# include <uriparser/UriDefsAnsi.h>
-# else
-# define URI_COMMON_H_UNICODE 1
-# include <uriparser/UriDefsUnicode.h>
-# endif
-
-
+# elif (defined(URI_PASS_ANSI) && !defined(URI_COMMON_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_COMMON_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_COMMON_H_ANSI 1
+# include <uriparser/UriDefsAnsi.h>
+# else
+# define URI_COMMON_H_UNICODE 1
+# include <uriparser/UriDefsUnicode.h>
+# endif
/* Used to point to from empty path segments.
* X.first and X.afterLast must be the same non-NULL value then. */
@@ -74,34 +73,37 @@ extern const URI_CHAR * const URI_FUNC(SafeToPointTo);
extern const URI_CHAR * const URI_FUNC(ConstPwd);
extern const URI_CHAR * const URI_FUNC(ConstParent);
+void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);
+int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
-void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);
+int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b);
-int URI_FUNC(CompareRange)(
- const URI_TYPE(TextRange) * a,
- const URI_TYPE(TextRange) * b);
+UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
+ const URI_TYPE(TextRange) * sourceRange,
+ UriMemoryManager * memory);
+UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
+ const URI_TYPE(TextRange) * sourceRange,
+ UriMemoryManager * memory);
UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory);
-UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
- UriBool relative, UriBool pathOwned, UriMemoryManager * memory);
+ UriMemoryManager * memory);
+UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative,
+ UriBool pathOwned, UriMemoryManager * memory);
unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig);
-URI_CHAR URI_FUNC(HexToLetter)(unsigned int value);
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase);
-UriBool URI_FUNC(IsHostSet)(const URI_TYPE(Uri) * uri);
-
UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
- UriMemoryManager * memory);
-UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * source, UriMemoryManager * memory);
+ UriMemoryManager * memory);
+UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
+ UriMemoryManager * memory);
UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
-void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri,
- UriMemoryManager * memory);
-
+UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
+UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory);
+void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);
-#endif
+# endif
#endif
diff --git a/src/UriCompare.c b/src/UriCompare.c
index bca3db9..781100e 100644
--- a/src/UriCompare.c
+++ b/src/UriCompare.c
@@ -41,128 +41,120 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriCompare.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriCompare.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriCompare.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriCompare.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include <uriparser/UriIp4.h>
-# include "UriCommon.h"
-#endif
-
-
-
-UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a,
- const URI_TYPE(Uri) * b) {
- /* NOTE: Both NULL means equal! */
- if ((a == NULL) || (b == NULL)) {
- return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE;
- }
-
- /* scheme */
- if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) {
- return URI_FALSE;
- }
-
- /* absolutePath */
- if ((a->scheme.first == NULL)&& (a->absolutePath != b->absolutePath)) {
- return URI_FALSE;
- }
-
- /* userInfo */
- if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) {
- return URI_FALSE;
- }
-
- /* Host */
- if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL))
- || ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL))
- || ((a->hostData.ipFuture.first == NULL)
- != (b->hostData.ipFuture.first == NULL))) {
- return URI_FALSE;
- }
-
- if (a->hostData.ip4 != NULL) {
- if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) {
- return URI_FALSE;
- }
- }
-
- if (a->hostData.ip6 != NULL) {
- if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) {
- return URI_FALSE;
- }
- }
-
- if (a->hostData.ipFuture.first != NULL) {
- if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
- return URI_FALSE;
- }
- }
-
- if ((a->hostData.ip4 == NULL)
- && (a->hostData.ip6 == NULL)
- && (a->hostData.ipFuture.first == NULL)) {
- if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) {
- return URI_FALSE;
- }
- }
-
- /* portText */
- if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) {
- return URI_FALSE;
- }
-
- /* Path */
- if ((a->pathHead == NULL) != (b->pathHead == NULL)) {
- return URI_FALSE;
- }
-
- if (a->pathHead != NULL) {
- URI_TYPE(PathSegment) * walkA = a->pathHead;
- URI_TYPE(PathSegment) * walkB = b->pathHead;
- do {
- if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) {
- return URI_FALSE;
- }
- if ((walkA->next == NULL) != (walkB->next == NULL)) {
- return URI_FALSE;
- }
- walkA = walkA->next;
- walkB = walkB->next;
- } while (walkA != NULL);
- }
-
- /* query */
- if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) {
- return URI_FALSE;
- }
-
- /* fragment */
- if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) {
- return URI_FALSE;
- }
-
- return URI_TRUE; /* Equal*/
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include <uriparser/UriIp4.h>
+# include "UriCommon.h"
+# endif
+
+UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
+ /* NOTE: Both NULL means equal! */
+ if ((a == NULL) || (b == NULL)) {
+ return ((a == NULL) && (b == NULL)) ? URI_TRUE : URI_FALSE;
+ }
+
+ /* scheme */
+ if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) {
+ return URI_FALSE;
+ }
+
+ /* absolutePath */
+ if ((a->scheme.first == NULL) && (a->absolutePath != b->absolutePath)) {
+ return URI_FALSE;
+ }
+
+ /* userInfo */
+ if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) {
+ return URI_FALSE;
+ }
+
+ /* Host */
+ if (((a->hostData.ip4 == NULL) != (b->hostData.ip4 == NULL))
+ || ((a->hostData.ip6 == NULL) != (b->hostData.ip6 == NULL))
+ || ((a->hostData.ipFuture.first == NULL)
+ != (b->hostData.ipFuture.first == NULL))) {
+ return URI_FALSE;
+ }
+
+ if (a->hostData.ip4 != NULL) {
+ if (memcmp(a->hostData.ip4->data, b->hostData.ip4->data, 4)) {
+ return URI_FALSE;
+ }
+ }
+
+ if (a->hostData.ip6 != NULL) {
+ if (memcmp(a->hostData.ip6->data, b->hostData.ip6->data, 16)) {
+ return URI_FALSE;
+ }
+ }
+
+ if (a->hostData.ipFuture.first != NULL) {
+ if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
+ return URI_FALSE;
+ }
+ }
+
+ if ((a->hostData.ip4 == NULL) && (a->hostData.ip6 == NULL)
+ && (a->hostData.ipFuture.first == NULL)) {
+ if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) {
+ return URI_FALSE;
+ }
+ }
+
+ /* portText */
+ if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) {
+ return URI_FALSE;
+ }
+
+ /* Path */
+ if ((a->pathHead == NULL) != (b->pathHead == NULL)) {
+ return URI_FALSE;
+ }
+
+ if (a->pathHead != NULL) {
+ URI_TYPE(PathSegment) * walkA = a->pathHead;
+ URI_TYPE(PathSegment) * walkB = b->pathHead;
+ do {
+ if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) {
+ return URI_FALSE;
+ }
+ if ((walkA->next == NULL) != (walkB->next == NULL)) {
+ return URI_FALSE;
+ }
+ walkA = walkA->next;
+ walkB = walkB->next;
+ } while (walkA != NULL);
+ }
+
+ /* query */
+ if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) {
+ return URI_FALSE;
+ }
+
+ /* fragment */
+ if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) {
+ return URI_FALSE;
+ }
+
+ return URI_TRUE; /* Equal*/
}
-
-
#endif
diff --git a/src/UriConfig.h.in b/src/UriConfig.h.in
index a16a933..b9a85a8 100644
--- a/src/UriConfig.h.in
+++ b/src/UriConfig.h.in
@@ -37,15 +37,11 @@
*/
#if !defined(URI_CONFIG_H)
-# define URI_CONFIG_H 1
+# define URI_CONFIG_H 1
-
-
-#define PACKAGE_VERSION "@PROJECT_VERSION@"
+# define PACKAGE_VERSION "@PROJECT_VERSION@"
#cmakedefine HAVE_WPRINTF
#cmakedefine HAVE_REALLOCARRAY
-
-
-#endif /* !defined(URI_CONFIG_H) */
+#endif /* !defined(URI_CONFIG_H) */
diff --git a/src/UriCopy.c b/src/UriCopy.c
new file mode 100644
index 0000000..3bc6b0d
--- /dev/null
+++ b/src/UriCopy.c
@@ -0,0 +1,242 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+ * Copyright (C) 2025, Máté Kocsis <kocsismate@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriCopy.c
+ * Holds the RFC 3986 %URI normalization implementation.
+ * NOTE: This source file includes itself twice.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriCopy.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriCopy.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriNormalize.h"
+# include "UriCopy.h"
+# endif
+
+static void URI_FUNC(PreventLeakageAfterCopy)(URI_TYPE(Uri) * uri,
+ unsigned int revertMask,
+ UriMemoryManager * memory) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+
+ if (uri->hostData.ip4 != NULL) {
+ memory->free(memory, uri->hostData.ip4);
+ uri->hostData.ip4 = NULL;
+ } else if (uri->hostData.ip6 != NULL) {
+ memory->free(memory, uri->hostData.ip6);
+ uri->hostData.ip6 = NULL;
+ }
+
+ if (revertMask & URI_NORMALIZE_PORT) {
+ if (uri->portText.first != uri->portText.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->portText.first);
+ }
+ uri->portText.first = NULL;
+ uri->portText.afterLast = NULL;
+ }
+}
+
+int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri,
+ UriMemoryManager * memory) {
+ unsigned int revertMask = URI_NORMALIZED;
+
+ if (sourceUri == NULL || destUri == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ URI_FUNC(ResetUri)(destUri);
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->scheme, &sourceUri->scheme, memory)
+ == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ revertMask |= URI_NORMALIZE_SCHEME;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->userInfo, &sourceUri->userInfo, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ revertMask |= URI_NORMALIZE_USER_INFO;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostText, &sourceUri->hostText, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ revertMask |= URI_NORMALIZE_HOST;
+
+ if (sourceUri->hostData.ip4 == NULL) {
+ destUri->hostData.ip4 = NULL;
+ } else {
+ destUri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
+ if (destUri->hostData.ip4 == NULL) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ *(destUri->hostData.ip4) = *(sourceUri->hostData.ip4);
+ }
+
+ if (sourceUri->hostData.ip6 == NULL) {
+ destUri->hostData.ip6 = NULL;
+ } else {
+ destUri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
+ if (destUri->hostData.ip6 == NULL) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ *(destUri->hostData.ip6) = *(sourceUri->hostData.ip6);
+ }
+
+ if (sourceUri->hostData.ipFuture.first != NULL) {
+ destUri->hostData.ipFuture.first = destUri->hostText.first;
+ destUri->hostData.ipFuture.afterLast = destUri->hostText.afterLast;
+ } else if (URI_FUNC(CopyRangeAsNeeded)(&destUri->hostData.ipFuture,
+ &sourceUri->hostData.ipFuture, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->portText, &sourceUri->portText, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ revertMask |= URI_NORMALIZE_PORT;
+
+ destUri->pathHead = NULL;
+ destUri->pathTail = NULL;
+
+ if (sourceUri->pathHead != NULL) {
+ URI_TYPE(PathSegment) * sourceWalker = sourceUri->pathHead;
+ URI_TYPE(PathSegment) * destPrev = NULL;
+
+ while (sourceWalker != NULL) {
+ URI_TYPE(PathSegment) * destWalker =
+ memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
+ if (destWalker == NULL) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ destWalker->text.first = NULL;
+ destWalker->text.afterLast = NULL;
+ destWalker->next = NULL;
+ destWalker->reserved = NULL;
+
+ if (destUri->pathHead == NULL) {
+ destUri->pathHead = destWalker;
+ revertMask |= URI_NORMALIZE_PATH;
+ }
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text,
+ memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ if (destPrev != NULL) {
+ destPrev->next = destWalker;
+ }
+
+ destPrev = destWalker;
+ sourceWalker = sourceWalker->next;
+
+ destUri->pathTail = destWalker;
+ }
+ }
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->query, &sourceUri->query, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ revertMask |= URI_NORMALIZE_QUERY;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&destUri->fragment, &sourceUri->fragment, memory)
+ == URI_FALSE) {
+ URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ destUri->absolutePath = sourceUri->absolutePath;
+ destUri->owner = URI_TRUE;
+ destUri->reserved = NULL;
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri) {
+ return URI_FUNC(CopyUriMm)(destUri, sourceUri, NULL);
+}
+
+#endif
diff --git a/src/UriCopy.h b/src/UriCopy.h
new file mode 100644
index 0000000..430f5dc
--- /dev/null
+++ b/src/UriCopy.h
@@ -0,0 +1,76 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+ * Copyright (C) 2025, Máté Kocsis <kocsismate@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if (defined(URI_PASS_ANSI) && !defined(URI_COPY_H_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_COPY_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* What encodings are enabled? */
+# include <uriparser/UriDefsConfig.h>
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriCopy.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriCopy.h"
+# undef URI_PASS_UNICODE
+# endif
+/* Only one pass for each encoding */
+# elif (defined(URI_PASS_ANSI) && !defined(URI_COPY_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_COPY_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_COPY_H_ANSI 1
+# include <uriparser/UriDefsAnsi.h>
+# else
+# define URI_COPY_H_UNICODE 1
+# include <uriparser/UriDefsUnicode.h>
+# endif
+
+int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri,
+ UriMemoryManager * memory);
+int URI_FUNC(CopyUri)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri);
+
+# endif
+#endif
diff --git a/src/UriEscape.c b/src/UriEscape.c
index ab8305f..a1763f9 100644
--- a/src/UriEscape.c
+++ b/src/UriEscape.c
@@ -41,413 +41,293 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriEscape.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriEscape.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriEscape.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriEscape.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-#endif
-
-
-
-URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out,
- UriBool spaceToPlus, UriBool normalizeBreaks) {
- return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks);
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriSets.h"
+# endif
+
+URI_CHAR * URI_FUNC(Escape)(const URI_CHAR * in, URI_CHAR * out, UriBool spaceToPlus,
+ UriBool normalizeBreaks) {
+ return URI_FUNC(EscapeEx)(in, NULL, out, spaceToPlus, normalizeBreaks);
}
-
-
-URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst,
- const URI_CHAR * inAfterLast, URI_CHAR * out,
- UriBool spaceToPlus, UriBool normalizeBreaks) {
- const URI_CHAR * read = inFirst;
- URI_CHAR * write = out;
- UriBool prevWasCr = URI_FALSE;
- if ((out == NULL) || (inFirst == out)) {
- return NULL;
- } else if (inFirst == NULL) {
- if (out != NULL) {
- out[0] = _UT('\0');
- }
- return out;
- }
-
- for (;;) {
- if ((inAfterLast != NULL) && (read >= inAfterLast)) {
- write[0] = _UT('\0');
- return write;
- }
-
- switch (read[0]) {
- case _UT('\0'):
- write[0] = _UT('\0');
- return write;
-
- case _UT(' '):
- if (spaceToPlus) {
- write[0] = _UT('+');
- write++;
- } else {
- write[0] = _UT('%');
- write[1] = _UT('2');
- write[2] = _UT('0');
- write += 3;
- }
- prevWasCr = URI_FALSE;
- break;
-
- case _UT('a'): /* ALPHA */
- case _UT('A'):
- case _UT('b'):
- case _UT('B'):
- case _UT('c'):
- case _UT('C'):
- case _UT('d'):
- case _UT('D'):
- case _UT('e'):
- case _UT('E'):
- case _UT('f'):
- case _UT('F'):
- case _UT('g'):
- case _UT('G'):
- case _UT('h'):
- case _UT('H'):
- case _UT('i'):
- case _UT('I'):
- case _UT('j'):
- case _UT('J'):
- case _UT('k'):
- case _UT('K'):
- case _UT('l'):
- case _UT('L'):
- case _UT('m'):
- case _UT('M'):
- case _UT('n'):
- case _UT('N'):
- case _UT('o'):
- case _UT('O'):
- case _UT('p'):
- case _UT('P'):
- case _UT('q'):
- case _UT('Q'):
- case _UT('r'):
- case _UT('R'):
- case _UT('s'):
- case _UT('S'):
- case _UT('t'):
- case _UT('T'):
- case _UT('u'):
- case _UT('U'):
- case _UT('v'):
- case _UT('V'):
- case _UT('w'):
- case _UT('W'):
- case _UT('x'):
- case _UT('X'):
- case _UT('y'):
- case _UT('Y'):
- case _UT('z'):
- case _UT('Z'):
- case _UT('0'): /* DIGIT */
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- case _UT('-'): /* "-" / "." / "_" / "~" */
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- /* Copy unmodified */
- write[0] = read[0];
- write++;
-
- prevWasCr = URI_FALSE;
- break;
-
- case _UT('\x0a'):
- if (normalizeBreaks) {
- if (!prevWasCr) {
- write[0] = _UT('%');
- write[1] = _UT('0');
- write[2] = _UT('D');
- write[3] = _UT('%');
- write[4] = _UT('0');
- write[5] = _UT('A');
- write += 6;
- }
- } else {
- write[0] = _UT('%');
- write[1] = _UT('0');
- write[2] = _UT('A');
- write += 3;
- }
- prevWasCr = URI_FALSE;
- break;
-
- case _UT('\x0d'):
- if (normalizeBreaks) {
- write[0] = _UT('%');
- write[1] = _UT('0');
- write[2] = _UT('D');
- write[3] = _UT('%');
- write[4] = _UT('0');
- write[5] = _UT('A');
- write += 6;
- } else {
- write[0] = _UT('%');
- write[1] = _UT('0');
- write[2] = _UT('D');
- write += 3;
- }
- prevWasCr = URI_TRUE;
- break;
-
- default:
- /* Percent encode */
- {
- const unsigned char code = (unsigned char)read[0];
- write[0] = _UT('%');
- write[1] = URI_FUNC(HexToLetter)(code >> 4);
- write[2] = URI_FUNC(HexToLetter)(code & 0x0f);
- write += 3;
- }
- prevWasCr = URI_FALSE;
- break;
- }
-
- read++;
- }
+URI_CHAR * URI_FUNC(EscapeEx)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
+ URI_CHAR * out, UriBool spaceToPlus,
+ UriBool normalizeBreaks) {
+ const URI_CHAR * read = inFirst;
+ URI_CHAR * write = out;
+ UriBool prevWasCr = URI_FALSE;
+ if ((out == NULL) || (inFirst == out)) {
+ return NULL;
+ } else if (inFirst == NULL) {
+ if (out != NULL) {
+ out[0] = _UT('\0');
+ }
+ return out;
+ }
+
+ for (;;) {
+ if ((inAfterLast != NULL) && (read >= inAfterLast)) {
+ write[0] = _UT('\0');
+ return write;
+ }
+
+ switch (read[0]) {
+ case _UT('\0'):
+ write[0] = _UT('\0');
+ return write;
+
+ case _UT(' '):
+ if (spaceToPlus) {
+ write[0] = _UT('+');
+ write++;
+ } else {
+ write[0] = _UT('%');
+ write[1] = _UT('2');
+ write[2] = _UT('0');
+ write += 3;
+ }
+ prevWasCr = URI_FALSE;
+ break;
+
+ case URI_SET_UNRESERVED(_UT):
+ /* Copy unmodified */
+ write[0] = read[0];
+ write++;
+
+ prevWasCr = URI_FALSE;
+ break;
+
+ case _UT('\x0a'):
+ if (normalizeBreaks) {
+ if (!prevWasCr) {
+ write[0] = _UT('%');
+ write[1] = _UT('0');
+ write[2] = _UT('D');
+ write[3] = _UT('%');
+ write[4] = _UT('0');
+ write[5] = _UT('A');
+ write += 6;
+ }
+ } else {
+ write[0] = _UT('%');
+ write[1] = _UT('0');
+ write[2] = _UT('A');
+ write += 3;
+ }
+ prevWasCr = URI_FALSE;
+ break;
+
+ case _UT('\x0d'):
+ if (normalizeBreaks) {
+ write[0] = _UT('%');
+ write[1] = _UT('0');
+ write[2] = _UT('D');
+ write[3] = _UT('%');
+ write[4] = _UT('0');
+ write[5] = _UT('A');
+ write += 6;
+ } else {
+ write[0] = _UT('%');
+ write[1] = _UT('0');
+ write[2] = _UT('D');
+ write += 3;
+ }
+ prevWasCr = URI_TRUE;
+ break;
+
+ default:
+ /* Percent encode */
+ {
+ const unsigned char code = (unsigned char)read[0];
+ /* Uppercase recommended in (last sentence of) section 2.1 *
+ * of RFC 3986: *
+ * https://datatracker.ietf.org/doc/html/rfc3986#section-2.1 */
+ write[0] = _UT('%');
+ write[1] = URI_FUNC(HexToLetterEx)(code >> 4, URI_TRUE);
+ write[2] = URI_FUNC(HexToLetterEx)(code & 0x0f, URI_TRUE);
+ write += 3;
+ }
+ prevWasCr = URI_FALSE;
+ break;
+ }
+
+ read++;
+ }
}
-
-
const URI_CHAR * URI_FUNC(UnescapeInPlace)(URI_CHAR * inout) {
- return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH);
+ return URI_FUNC(UnescapeInPlaceEx)(inout, URI_FALSE, URI_BR_DONT_TOUCH);
}
-
-
-const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout,
- UriBool plusToSpace, UriBreakConversion breakConversion) {
- URI_CHAR * read = inout;
- URI_CHAR * write = inout;
- UriBool prevWasCr = URI_FALSE;
-
- if (inout == NULL) {
- return NULL;
- }
-
- for (;;) {
- switch (read[0]) {
- case _UT('\0'):
- if (read > write) {
- write[0] = _UT('\0');
- }
- return write;
-
- case _UT('%'):
- switch (read[1]) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- case _UT('a'):
- case _UT('b'):
- case _UT('c'):
- case _UT('d'):
- case _UT('e'):
- case _UT('f'):
- case _UT('A'):
- case _UT('B'):
- case _UT('C'):
- case _UT('D'):
- case _UT('E'):
- case _UT('F'):
- switch (read[2]) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- case _UT('a'):
- case _UT('b'):
- case _UT('c'):
- case _UT('d'):
- case _UT('e'):
- case _UT('f'):
- case _UT('A'):
- case _UT('B'):
- case _UT('C'):
- case _UT('D'):
- case _UT('E'):
- case _UT('F'):
- {
- /* Percent group found */
- const unsigned char left = URI_FUNC(HexdigToInt)(read[1]);
- const unsigned char right = URI_FUNC(HexdigToInt)(read[2]);
- const int code = 16 * left + right;
- switch (code) {
- case 10:
- switch (breakConversion) {
- case URI_BR_TO_LF:
- if (!prevWasCr) {
- write[0] = (URI_CHAR)10;
- write++;
- }
- break;
-
- case URI_BR_TO_CRLF:
- if (!prevWasCr) {
- write[0] = (URI_CHAR)13;
- write[1] = (URI_CHAR)10;
- write += 2;
- }
- break;
-
- case URI_BR_TO_CR:
- if (!prevWasCr) {
- write[0] = (URI_CHAR)13;
- write++;
- }
- break;
-
- case URI_BR_DONT_TOUCH:
- default:
- write[0] = (URI_CHAR)10;
- write++;
-
- }
- prevWasCr = URI_FALSE;
- break;
-
- case 13:
- switch (breakConversion) {
- case URI_BR_TO_LF:
- write[0] = (URI_CHAR)10;
- write++;
- break;
-
- case URI_BR_TO_CRLF:
- write[0] = (URI_CHAR)13;
- write[1] = (URI_CHAR)10;
- write += 2;
- break;
-
- case URI_BR_TO_CR:
- write[0] = (URI_CHAR)13;
- write++;
- break;
-
- case URI_BR_DONT_TOUCH:
- default:
- write[0] = (URI_CHAR)13;
- write++;
-
- }
- prevWasCr = URI_TRUE;
- break;
-
- default:
- write[0] = (URI_CHAR)(code);
- write++;
-
- prevWasCr = URI_FALSE;
-
- }
- read += 3;
- }
- break;
-
- default:
- /* Copy two chars unmodified and */
- /* look at this char again */
- if (read > write) {
- write[0] = read[0];
- write[1] = read[1];
- }
- read += 2;
- write += 2;
-
- prevWasCr = URI_FALSE;
- }
- break;
-
- default:
- /* Copy one char unmodified and */
- /* look at this char again */
- if (read > write) {
- write[0] = read[0];
- }
- read++;
- write++;
-
- prevWasCr = URI_FALSE;
- }
- break;
-
- case _UT('+'):
- if (plusToSpace) {
- /* Convert '+' to ' ' */
- write[0] = _UT(' ');
- } else {
- /* Copy one char unmodified */
- if (read > write) {
- write[0] = read[0];
- }
- }
- read++;
- write++;
-
- prevWasCr = URI_FALSE;
- break;
-
- default:
- /* Copy one char unmodified */
- if (read > write) {
- write[0] = read[0];
- }
- read++;
- write++;
-
- prevWasCr = URI_FALSE;
- }
- }
+const URI_CHAR * URI_FUNC(UnescapeInPlaceEx)(URI_CHAR * inout, UriBool plusToSpace,
+ UriBreakConversion breakConversion) {
+ URI_CHAR * read = inout;
+ URI_CHAR * write = inout;
+ UriBool prevWasCr = URI_FALSE;
+
+ if (inout == NULL) {
+ return NULL;
+ }
+
+ for (;;) {
+ switch (read[0]) {
+ case _UT('\0'):
+ if (read > write) {
+ write[0] = _UT('\0');
+ }
+ return write;
+
+ case _UT('%'):
+ switch (read[1]) {
+ case URI_SET_HEXDIG(_UT):
+ switch (read[2]) {
+ case URI_SET_HEXDIG(_UT): {
+ /* Percent group found */
+ const unsigned char left = URI_FUNC(HexdigToInt)(read[1]);
+ const unsigned char right = URI_FUNC(HexdigToInt)(read[2]);
+ const int code = 16 * left + right;
+ switch (code) {
+ case 10:
+ switch (breakConversion) {
+ case URI_BR_TO_LF:
+ if (!prevWasCr) {
+ write[0] = (URI_CHAR)10;
+ write++;
+ }
+ break;
+
+ case URI_BR_TO_CRLF:
+ if (!prevWasCr) {
+ write[0] = (URI_CHAR)13;
+ write[1] = (URI_CHAR)10;
+ write += 2;
+ }
+ break;
+
+ case URI_BR_TO_CR:
+ if (!prevWasCr) {
+ write[0] = (URI_CHAR)13;
+ write++;
+ }
+ break;
+
+ case URI_BR_DONT_TOUCH:
+ default:
+ write[0] = (URI_CHAR)10;
+ write++;
+ }
+ prevWasCr = URI_FALSE;
+ break;
+
+ case 13:
+ switch (breakConversion) {
+ case URI_BR_TO_LF:
+ write[0] = (URI_CHAR)10;
+ write++;
+ break;
+
+ case URI_BR_TO_CRLF:
+ write[0] = (URI_CHAR)13;
+ write[1] = (URI_CHAR)10;
+ write += 2;
+ break;
+
+ case URI_BR_TO_CR:
+ write[0] = (URI_CHAR)13;
+ write++;
+ break;
+
+ case URI_BR_DONT_TOUCH:
+ default:
+ write[0] = (URI_CHAR)13;
+ write++;
+ }
+ prevWasCr = URI_TRUE;
+ break;
+
+ default:
+ write[0] = (URI_CHAR)(code);
+ write++;
+
+ prevWasCr = URI_FALSE;
+ }
+ read += 3;
+ } break;
+
+ default:
+ /* Copy two chars unmodified and */
+ /* look at this char again */
+ if (read > write) {
+ write[0] = read[0];
+ write[1] = read[1];
+ }
+ read += 2;
+ write += 2;
+
+ prevWasCr = URI_FALSE;
+ }
+ break;
+
+ default:
+ /* Copy one char unmodified and */
+ /* look at this char again */
+ if (read > write) {
+ write[0] = read[0];
+ }
+ read++;
+ write++;
+
+ prevWasCr = URI_FALSE;
+ }
+ break;
+
+ case _UT('+'):
+ if (plusToSpace) {
+ /* Convert '+' to ' ' */
+ write[0] = _UT(' ');
+ } else {
+ /* Copy one char unmodified */
+ if (read > write) {
+ write[0] = read[0];
+ }
+ }
+ read++;
+ write++;
+
+ prevWasCr = URI_FALSE;
+ break;
+
+ default:
+ /* Copy one char unmodified */
+ if (read > write) {
+ write[0] = read[0];
+ }
+ read++;
+ write++;
+
+ prevWasCr = URI_FALSE;
+ }
+ }
}
-
-
#endif
diff --git a/src/UriFile.c b/src/UriFile.c
index 232957d..7510e70 100644
--- a/src/UriFile.c
+++ b/src/UriFile.c
@@ -41,202 +41,181 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriFile.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriFile.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriFile.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriFile.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-#endif
-
-
-
-#include <stdlib.h> /* for size_t, avoiding stddef.h for older MSVCs */
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# endif
+# include <stdlib.h> /* for size_t, avoiding stddef.h for older MSVCs */
static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
- URI_CHAR * uriString, UriBool fromUnix) {
- const URI_CHAR * input = filename;
- const URI_CHAR * lastSep = input - 1;
- UriBool firstSegment = URI_TRUE;
- URI_CHAR * output = uriString;
- UriBool absolute;
- UriBool is_windows_network;
-
- if ((filename == NULL) || (uriString == NULL)) {
- return URI_ERROR_NULL;
- }
-
- is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\'));
- absolute = fromUnix
- ? (filename[0] == _UT('/'))
- : (((filename[0] != _UT('\0')) && (filename[1] == _UT(':')))
- || is_windows_network);
-
- if (absolute) {
- const URI_CHAR * const prefix = fromUnix
- ? _UT("file://")
- : is_windows_network
- ? _UT("file:")
- : _UT("file:///");
- const size_t prefixLen = URI_STRLEN(prefix);
-
- /* Copy prefix */
- memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
- output += prefixLen;
- }
-
- /* Copy and escape on the fly */
- for (;;) {
- if ((input[0] == _UT('\0'))
- || (fromUnix && input[0] == _UT('/'))
- || (!fromUnix && input[0] == _UT('\\'))) {
- /* Copy text after last separator */
- if (lastSep + 1 < input) {
- if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
- /* Quick hack to not convert "C:" to "C%3A" */
- const int charsToCopy = (int)(input - (lastSep + 1));
- memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
- output += charsToCopy;
- } else {
- output = URI_FUNC(EscapeEx)(lastSep + 1, input, output,
- URI_FALSE, URI_FALSE);
- }
- }
- firstSegment = URI_FALSE;
- }
-
- if (input[0] == _UT('\0')) {
- output[0] = _UT('\0');
- break;
- } else if (fromUnix && (input[0] == _UT('/'))) {
- /* Copy separators unmodified */
- output[0] = _UT('/');
- output++;
- lastSep = input;
- } else if (!fromUnix && (input[0] == _UT('\\'))) {
- /* Convert backslashes to forward slashes */
- output[0] = _UT('/');
- output++;
- lastSep = input;
- }
- input++;
- }
-
- return URI_SUCCESS;
+ URI_CHAR * uriString,
+ UriBool fromUnix) {
+ const URI_CHAR * input = filename;
+ const URI_CHAR * lastSep = input - 1;
+ UriBool firstSegment = URI_TRUE;
+ URI_CHAR * output = uriString;
+ UriBool absolute;
+ UriBool is_windows_network;
+
+ if ((filename == NULL) || (uriString == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\'));
+ absolute = fromUnix ? (filename[0] == _UT('/'))
+ : (((filename[0] != _UT('\0')) && (filename[1] == _UT(':')))
+ || is_windows_network);
+
+ if (absolute) {
+ const URI_CHAR * const prefix = fromUnix ? _UT("file://")
+ : is_windows_network ? _UT("file:")
+ : _UT("file:///");
+ const size_t prefixLen = URI_STRLEN(prefix);
+
+ /* Copy prefix */
+ memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
+ output += prefixLen;
+ }
+
+ /* Copy and escape on the fly */
+ for (;;) {
+ if ((input[0] == _UT('\0')) || (fromUnix && input[0] == _UT('/'))
+ || (!fromUnix && input[0] == _UT('\\'))) {
+ /* Copy text after last separator */
+ if (lastSep + 1 < input) {
+ if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
+ /* Quick hack to not convert "C:" to "C%3A" */
+ const int charsToCopy = (int)(input - (lastSep + 1));
+ memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
+ output += charsToCopy;
+ } else {
+ output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, URI_FALSE,
+ URI_FALSE);
+ }
+ }
+ firstSegment = URI_FALSE;
+ }
+
+ if (input[0] == _UT('\0')) {
+ output[0] = _UT('\0');
+ break;
+ } else if (fromUnix && (input[0] == _UT('/'))) {
+ /* Copy separators unmodified */
+ output[0] = _UT('/');
+ output++;
+ lastSep = input;
+ } else if (!fromUnix && (input[0] == _UT('\\'))) {
+ /* Convert backslashes to forward slashes */
+ output[0] = _UT('/');
+ output++;
+ lastSep = input;
+ }
+ input++;
+ }
+
+ return URI_SUCCESS;
}
-
-
static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString,
- URI_CHAR * filename, UriBool toUnix) {
- if ((uriString == NULL) || (filename == NULL)) {
- return URI_ERROR_NULL;
- }
-
- {
- const UriBool file_unknown_slashes =
- URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0;
- const UriBool file_one_or_more_slashes = file_unknown_slashes
- && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0);
- const UriBool file_two_or_more_slashes = file_one_or_more_slashes
- && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0);
- const UriBool file_three_or_more_slashes = file_two_or_more_slashes
- && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0);
-
- const size_t charsToSkip = file_two_or_more_slashes
- ? file_three_or_more_slashes
- ? toUnix
- /* file:///bin/bash */
- ? URI_STRLEN(_UT("file://"))
- /* file:///E:/Documents%20and%20Settings */
- : URI_STRLEN(_UT("file:///"))
- /* file://Server01/Letter.txt */
- : URI_STRLEN(_UT("file://"))
- : ((file_one_or_more_slashes && toUnix)
- /* file:/bin/bash */
- /* https://tools.ietf.org/html/rfc8089#appendix-B */
- ? URI_STRLEN(_UT("file:"))
- : ((! toUnix && file_unknown_slashes && ! file_one_or_more_slashes)
- /* file:c:/path/to/file */
- /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */
- ? URI_STRLEN(_UT("file:"))
- : 0));
- const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1;
-
- const UriBool is_windows_network_with_authority =
- (toUnix == URI_FALSE)
- && file_two_or_more_slashes
- && ! file_three_or_more_slashes;
-
- URI_CHAR * const unescape_target = is_windows_network_with_authority
- ? (filename + 2)
- : filename;
-
- if (is_windows_network_with_authority) {
- filename[0] = '\\';
- filename[1] = '\\';
- }
-
- memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR));
- URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH);
- }
-
- /* Convert forward slashes to backslashes */
- if (!toUnix) {
- URI_CHAR * walker = filename;
- while (walker[0] != _UT('\0')) {
- if (walker[0] == _UT('/')) {
- walker[0] = _UT('\\');
- }
- walker++;
- }
- }
-
- return URI_SUCCESS;
+ URI_CHAR * filename, UriBool toUnix) {
+ if ((uriString == NULL) || (filename == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ const UriBool file_unknown_slashes =
+ URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0;
+ const UriBool file_one_or_more_slashes =
+ file_unknown_slashes
+ && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0);
+ const UriBool file_two_or_more_slashes =
+ file_one_or_more_slashes
+ && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0);
+ const UriBool file_three_or_more_slashes =
+ file_two_or_more_slashes
+ && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0);
+
+ const size_t charsToSkip =
+ file_two_or_more_slashes
+ ? file_three_or_more_slashes ? toUnix
+ /* file:///bin/bash */
+ ? URI_STRLEN(_UT("file://"))
+ /* file:///E:/Documents%20and%20Settings */
+ : URI_STRLEN(_UT("file:///"))
+ /* file://Server01/Letter.txt */
+ : URI_STRLEN(_UT("file://"))
+ : ((file_one_or_more_slashes && toUnix)
+ /* file:/bin/bash */
+ /* https://tools.ietf.org/html/rfc8089#appendix-B */
+ ? URI_STRLEN(_UT("file:"))
+ : ((!toUnix && file_unknown_slashes && !file_one_or_more_slashes)
+ /* file:c:/path/to/file */
+ /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */
+ ? URI_STRLEN(_UT("file:"))
+ : 0));
+ const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1;
+
+ const UriBool is_windows_network_with_authority =
+ (toUnix == URI_FALSE) && file_two_or_more_slashes && !file_three_or_more_slashes;
+
+ URI_CHAR * const unescape_target =
+ is_windows_network_with_authority ? (filename + 2) : filename;
+
+ if (is_windows_network_with_authority) {
+ filename[0] = '\\';
+ filename[1] = '\\';
+ }
+
+ memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR));
+ URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH);
+
+ /* Convert forward slashes to backslashes */
+ if (!toUnix) {
+ URI_CHAR * walker = filename;
+ while (walker[0] != _UT('\0')) {
+ if (walker[0] == _UT('/')) {
+ walker[0] = _UT('\\');
+ }
+ walker++;
+ }
+ }
+
+ return URI_SUCCESS;
}
-
-
int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) {
- return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE);
+ return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE);
}
-
-
-int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) {
- return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE);
+int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename,
+ URI_CHAR * uriString) {
+ return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE);
}
-
-
int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, URI_CHAR * filename) {
- return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE);
+ return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE);
}
-
-
-int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString, URI_CHAR * filename) {
- return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE);
+int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString,
+ URI_CHAR * filename) {
+ return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE);
}
-
-
#endif
diff --git a/src/UriIp4.c b/src/UriIp4.c
index a794265..ae61141 100644
--- a/src/UriIp4.c
+++ b/src/UriIp4.c
@@ -47,97 +47,94 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriIp4.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriIp4.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriIp4.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriIp4.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/UriIp4.h>
-# include "UriIp4Base.h"
-# include <uriparser/UriBase.h>
-#endif
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/UriIp4.h>
+# include "UriIp4Base.h"
+# include <uriparser/UriBase.h>
+# include "UriSets.h"
+# endif
/* Prototypes */
static const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast);
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
static const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast);
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
static const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast);
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
static const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast);
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
static const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast);
-
-
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
/*
* [ipFourAddress]->[decOctet]<.>[decOctet]<.>[decOctet]<.>[decOctet]
*/
-int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- const URI_CHAR * after;
- UriIp4Parser parser;
-
- /* Essential checks */
- if ((octetOutput == NULL) || (first == NULL)
- || (afterLast <= first)) {
- return URI_ERROR_SYNTAX;
- }
-
- /* Reset parser */
- parser.stackCount = 0;
-
- /* Octet #1 */
- after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast);
- if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
- return URI_ERROR_SYNTAX;
- }
- uriStackToOctet(&parser, octetOutput);
-
- /* Octet #2 */
- after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
- if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
- return URI_ERROR_SYNTAX;
- }
- uriStackToOctet(&parser, octetOutput + 1);
-
- /* Octet #3 */
- after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
- if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
- return URI_ERROR_SYNTAX;
- }
- uriStackToOctet(&parser, octetOutput + 2);
-
- /* Octet #4 */
- after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
- if (after != afterLast) {
- return URI_ERROR_SYNTAX;
- }
- uriStackToOctet(&parser, octetOutput + 3);
-
- return URI_SUCCESS;
+int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ const URI_CHAR * after;
+ UriIp4Parser parser;
+
+ /* Essential checks */
+ if ((octetOutput == NULL) || (first == NULL) || (afterLast <= first)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Reset parser */
+ parser.stackCount = 0;
+
+ /* Octet #1 */
+ after = URI_FUNC(ParseDecOctet)(&parser, first, afterLast);
+ if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
+ return URI_ERROR_SYNTAX;
+ }
+ uriStackToOctet(&parser, octetOutput);
+
+ /* Octet #2 */
+ after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
+ if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
+ return URI_ERROR_SYNTAX;
+ }
+ uriStackToOctet(&parser, octetOutput + 1);
+
+ /* Octet #3 */
+ after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
+ if ((after == NULL) || (after >= afterLast) || (*after != _UT('.'))) {
+ return URI_ERROR_SYNTAX;
+ }
+ uriStackToOctet(&parser, octetOutput + 2);
+
+ /* Octet #4 */
+ after = URI_FUNC(ParseDecOctet)(&parser, after + 1, afterLast);
+ if (after != afterLast) {
+ return URI_ERROR_SYNTAX;
+ }
+ uriStackToOctet(&parser, octetOutput + 3);
+
+ return URI_SUCCESS;
}
-
-
/*
* [decOctet]-><0>
* [decOctet]-><1>[decOctetOne]
@@ -151,72 +148,63 @@ int URI_FUNC(ParseIpFourAddress)(unsigned char * octetOutput,
* [decOctet]-><9>[decOctetThree]
*/
static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctet)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return NULL;
- }
-
- switch (*first) {
- case _UT('0'):
- uriPushToStack(parser, 0);
- return first + 1;
-
- case _UT('1'):
- uriPushToStack(parser, 1);
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast);
-
- case _UT('2'):
- uriPushToStack(parser, 2);
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast);
-
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
-
- default:
- return NULL;
- }
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return NULL;
+ }
+
+ switch (*first) {
+ case _UT('0'):
+ uriPushToStack(parser, 0);
+ return first + 1;
+
+ case _UT('1'):
+ uriPushToStack(parser, 1);
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetOne)(parser, first + 1, afterLast);
+
+ case _UT('2'):
+ uriPushToStack(parser, 2);
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetTwo)(parser, first + 1, afterLast);
+
+ case _UT('3'):
+ case _UT('4'):
+ case _UT('5'):
+ case _UT('6'):
+ case _UT('7'):
+ case _UT('8'):
+ case _UT('9'):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1,
+ afterLast);
+
+ default:
+ return NULL;
+ }
}
-
-
/*
* [decOctetOne]-><NULL>
* [decOctetOne]->[DIGIT][decOctetThree]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseDecOctetOne)(UriIp4Parser * parser, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_DIGIT(_UT):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1,
+ afterLast);
+
+ default:
+ return first;
+ }
}
-
-
/*
* [decOctetTwo]-><NULL>
* [decOctetTwo]-><0>[decOctetThree]
@@ -229,71 +217,62 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetOne)(UriIp4Parser * par
* [decOctetTwo]-><7>
* [decOctetTwo]-><8>
* [decOctetTwo]-><9>
-*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1, afterLast);
-
- case _UT('5'):
- uriPushToStack(parser, 5);
- return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1, afterLast);
-
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return first + 1;
-
- default:
- return first;
- }
+ */
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseDecOctetTwo)(UriIp4Parser * parser, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('0'):
+ case _UT('1'):
+ case _UT('2'):
+ case _UT('3'):
+ case _UT('4'):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetThree)(parser, first + 1,
+ afterLast);
+
+ case _UT('5'):
+ uriPushToStack(parser, 5);
+ return (const URI_CHAR *)URI_FUNC(ParseDecOctetFour)(parser, first + 1,
+ afterLast);
+
+ case _UT('6'):
+ case _UT('7'):
+ case _UT('8'):
+ case _UT('9'):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return first + 1;
+
+ default:
+ return first;
+ }
}
-
-
/*
* [decOctetThree]-><NULL>
* [decOctetThree]->[DIGIT]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- case _UT('6'):
- case _UT('7'):
- case _UT('8'):
- case _UT('9'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return first + 1;
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseDecOctetThree)(UriIp4Parser * parser, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_DIGIT(_UT):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return first + 1;
+
+ default:
+ return first;
+ }
}
-
-
/*
* [decOctetFour]-><NULL>
* [decOctetFour]-><0>
@@ -303,27 +282,26 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetThree)(UriIp4Parser * p
* [decOctetFour]-><4>
* [decOctetFour]-><5>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('0'):
- case _UT('1'):
- case _UT('2'):
- case _UT('3'):
- case _UT('4'):
- case _UT('5'):
- uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
- return first + 1;
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseDecOctetFour)(UriIp4Parser * parser, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('0'):
+ case _UT('1'):
+ case _UT('2'):
+ case _UT('3'):
+ case _UT('4'):
+ case _UT('5'):
+ uriPushToStack(parser, (unsigned char)(9 + *first - _UT('9')));
+ return first + 1;
+
+ default:
+ return first;
+ }
}
-
-
#endif
diff --git a/src/UriIp4Base.c b/src/UriIp4Base.c
index ded7c32..900234c 100644
--- a/src/UriIp4Base.c
+++ b/src/UriIp4Base.c
@@ -43,54 +43,45 @@
*/
#ifndef URI_DOXYGEN
-# include "UriIp4Base.h"
+# include "UriIp4Base.h"
#endif
-
-
void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet) {
- switch (parser->stackCount) {
- case 1:
- *octet = parser->stackOne;
- break;
+ switch (parser->stackCount) {
+ case 1:
+ *octet = parser->stackOne;
+ break;
- case 2:
- *octet = parser->stackOne * 10
- + parser->stackTwo;
- break;
+ case 2:
+ *octet = parser->stackOne * 10 + parser->stackTwo;
+ break;
- case 3:
- *octet = parser->stackOne * 100
- + parser->stackTwo * 10
- + parser->stackThree;
- break;
+ case 3:
+ *octet = parser->stackOne * 100 + parser->stackTwo * 10 + parser->stackThree;
+ break;
- default:
- ;
- }
- parser->stackCount = 0;
+ default:;
+ }
+ parser->stackCount = 0;
}
-
-
void uriPushToStack(UriIp4Parser * parser, unsigned char digit) {
- switch (parser->stackCount) {
- case 0:
- parser->stackOne = digit;
- parser->stackCount = 1;
- break;
+ switch (parser->stackCount) {
+ case 0:
+ parser->stackOne = digit;
+ parser->stackCount = 1;
+ break;
- case 1:
- parser->stackTwo = digit;
- parser->stackCount = 2;
- break;
+ case 1:
+ parser->stackTwo = digit;
+ parser->stackCount = 2;
+ break;
- case 2:
- parser->stackThree = digit;
- parser->stackCount = 3;
- break;
+ case 2:
+ parser->stackThree = digit;
+ parser->stackCount = 3;
+ break;
- default:
- ;
- }
+ default:;
+ }
}
diff --git a/src/UriIp4Base.h b/src/UriIp4Base.h
index 4867850..1a2ff14 100644
--- a/src/UriIp4Base.h
+++ b/src/UriIp4Base.h
@@ -38,22 +38,16 @@
*/
#ifndef URI_IP4_BASE_H
-#define URI_IP4_BASE_H 1
-
-
+# define URI_IP4_BASE_H 1
typedef struct UriIp4ParserStruct {
- unsigned char stackCount;
- unsigned char stackOne;
- unsigned char stackTwo;
- unsigned char stackThree;
+ unsigned char stackCount;
+ unsigned char stackOne;
+ unsigned char stackTwo;
+ unsigned char stackThree;
} UriIp4Parser;
-
-
void uriPushToStack(UriIp4Parser * parser, unsigned char digit);
void uriStackToOctet(UriIp4Parser * parser, unsigned char * octet);
-
-
#endif /* URI_IP4_BASE_H */
diff --git a/src/UriMemory.c b/src/UriMemory.c
index 916d7ce..669f48d 100644
--- a/src/UriMemory.c
+++ b/src/UriMemory.c
@@ -42,430 +42,436 @@
* Holds memory manager implementation.
*/
-#include "UriConfig.h" /* for HAVE_REALLOCARRAY */
+#include "UriConfig.h" /* for HAVE_REALLOCARRAY */
#ifdef HAVE_REALLOCARRAY
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-# endif
-# ifdef __NetBSD__
-# define _OPENBSD_SOURCE 1
-# endif
+// For glibc >=2.29 of 2019-02-01
+# if !defined(_DEFAULT_SOURCE)
+# define _DEFAULT_SOURCE 1
+# endif
+
+// For NetBSD (stdlib.h revision 1.122 of 2020-05-26)
+# if defined(__NetBSD__) && !defined(_OPENBSD_SOURCE)
+# define _OPENBSD_SOURCE 1
+# endif
+
+// POSIX 2024 (XPG8) for e.g. Illumos/SmartOS
+# if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0 < 800)
+# undef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 800
+# endif
+# if !defined(_POSIX_C_SOURCE) || (_POSIX_C_SOURCE - 0 < 202405L)
+# undef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 202405L
+# endif
#endif
#include <errno.h>
#include <stdlib.h>
-
-
#ifndef URI_DOXYGEN
-# include "UriMemory.h"
+# include "UriMemory.h"
#endif
+#define URI_MAX(a, b) (((a) > (b)) ? (a) : (b))
+/* NOTE: This intends to mimic MALLOC_ALIGNMENT of glibc */
+#define URI_MALLOC_ALIGNMENT URI_MAX(2 * sizeof(size_t), sizeof(long double))
-#define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \
- do { \
- /* check for unsigned overflow */ \
- if ((nmemb != 0) && (total_size / nmemb != size)) { \
- errno = ENOMEM; \
- return NULL; \
- } \
- } while (0)
-
-
+#define URI_MALLOC_PADDING (URI_MALLOC_ALIGNMENT - sizeof(size_t))
-static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory),
- size_t size) {
- return malloc(size);
+#define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \
+ do { \
+ /* check for unsigned overflow */ \
+ if ((nmemb != 0) && (total_size / nmemb != size)) { \
+ errno = ENOMEM; \
+ return NULL; \
+ } \
+ } while (0)
+
+static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory), size_t size) {
+ return malloc(size);
}
-
-
-static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory),
- size_t nmemb, size_t size) {
- return calloc(nmemb, size);
+static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory), size_t nmemb,
+ size_t size) {
+ return calloc(nmemb, size);
}
-
-
-static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory),
- void * ptr, size_t size) {
- return realloc(ptr, size);
+static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory), void * ptr,
+ size_t size) {
+ return realloc(ptr, size);
}
-
-
-static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory),
- void * ptr, size_t nmemb, size_t size) {
+static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory), void * ptr,
+ size_t nmemb, size_t size) {
#ifdef HAVE_REALLOCARRAY
- return reallocarray(ptr, nmemb, size);
+ return reallocarray(ptr, nmemb, size);
#else
- const size_t total_size = nmemb * size;
+ const size_t total_size = nmemb * size;
- URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
+ URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
- return realloc(ptr, total_size);
+ return realloc(ptr, total_size);
#endif
}
-
-
-static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory),
- void * ptr) {
- free(ptr);
+static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory), void * ptr) {
+ free(ptr);
}
-
-
UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory) {
- return (memory
- && memory->malloc
- && memory->calloc
- && memory->realloc
- && memory->reallocarray
- && memory->free) ? URI_TRUE : URI_FALSE;
+ return (memory && memory->malloc && memory->calloc && memory->realloc
+ && memory->reallocarray && memory->free)
+ ? URI_TRUE
+ : URI_FALSE;
}
-
-
void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) {
- void * buffer;
- const size_t total_size = nmemb * size;
-
- if (memory == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
-
- buffer = memory->malloc(memory, total_size);
- if (buffer == NULL) {
- /* errno set by malloc */
- return NULL;
- }
- memset(buffer, 0, total_size);
- return buffer;
+ void * buffer;
+ const size_t total_size = nmemb * size;
+
+ if (memory == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
+
+ buffer = memory->malloc(memory, total_size);
+ if (buffer == NULL) {
+ /* errno set by malloc */
+ return NULL;
+ }
+ memset(buffer, 0, total_size);
+ return buffer;
}
+void * uriEmulateReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb,
+ size_t size) {
+ const size_t total_size = nmemb * size;
+ if (memory == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
-void * uriEmulateReallocarray(UriMemoryManager * memory,
- void * ptr, size_t nmemb, size_t size) {
- const size_t total_size = nmemb * size;
-
- if (memory == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
+ URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
- return memory->realloc(memory, ptr, total_size);
+ return memory->realloc(memory, ptr, total_size);
}
+static void * uriDecorateMalloc(UriMemoryManager * memory, size_t size) {
+ UriMemoryManager * backend;
+ const size_t extraBytes = sizeof(size_t) + URI_MALLOC_PADDING;
+ void * buffer;
+ if (memory == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
-static void * uriDecorateMalloc(UriMemoryManager * memory,
- size_t size) {
- UriMemoryManager * backend;
- const size_t extraBytes = sizeof(size_t);
- void * buffer;
+ /* check for unsigned overflow */
+ if (size > ((size_t)-1) - extraBytes) {
+ errno = ENOMEM;
+ return NULL;
+ }
- if (memory == NULL) {
- errno = EINVAL;
- return NULL;
- }
+ backend = (UriMemoryManager *)memory->userData;
+ if (backend == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
- /* check for unsigned overflow */
- if (size > ((size_t)-1) - extraBytes) {
- errno = ENOMEM;
- return NULL;
- }
+ buffer = backend->malloc(backend, extraBytes + size);
+ if (buffer == NULL) {
+ return NULL;
+ }
- backend = (UriMemoryManager *)memory->userData;
- if (backend == NULL) {
- errno = EINVAL;
- return NULL;
- }
+ *(size_t *)buffer = size;
- buffer = backend->malloc(backend, extraBytes + size);
- if (buffer == NULL) {
- return NULL;
- }
-
- *(size_t *)buffer = size;
-
- return (char *)buffer + extraBytes;
+ return (char *)buffer + extraBytes;
}
+static void * uriDecorateRealloc(UriMemoryManager * memory, void * ptr, size_t size) {
+ void * newBuffer;
+ size_t prevSize;
+ if (memory == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
-static void * uriDecorateRealloc(UriMemoryManager * memory,
- void * ptr, size_t size) {
- void * newBuffer;
- size_t prevSize;
-
- if (memory == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- /* man realloc: "If ptr is NULL, then the call is equivalent to
- * malloc(size), for *all* values of size" */
- if (ptr == NULL) {
- return memory->malloc(memory, size);
- }
+ /* man realloc: "If ptr is NULL, then the call is equivalent to
+ * malloc(size), for *all* values of size" */
+ if (ptr == NULL) {
+ return memory->malloc(memory, size);
+ }
- /* man realloc: "If size is equal to zero, and ptr is *not* NULL,
- * then the call is equivalent to free(ptr)." */
- if (size == 0) {
- memory->free(memory, ptr);
- return NULL;
- }
+ /* man realloc: "If size is equal to zero, and ptr is *not* NULL,
+ * then the call is equivalent to free(ptr)." */
+ if (size == 0) {
+ memory->free(memory, ptr);
+ return NULL;
+ }
- prevSize = *((size_t *)((char *)ptr - sizeof(size_t)));
+ prevSize = *((size_t *)((char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING));
- /* Anything to do? */
- if (size <= prevSize) {
- return ptr;
- }
+ /* Anything to do? */
+ /* mull-ignore-next cxx_le_to_lt */
+ if (size <= prevSize) {
+ return ptr;
+ }
- newBuffer = memory->malloc(memory, size);
- if (newBuffer == NULL) {
- /* errno set by malloc */
- return NULL;
- }
+ newBuffer = memory->malloc(memory, size);
+ if (newBuffer == NULL) {
+ /* errno set by malloc */
+ return NULL;
+ }
- memcpy(newBuffer, ptr, prevSize);
+ memcpy(newBuffer, ptr, prevSize);
- memory->free(memory, ptr);
+ memory->free(memory, ptr);
- return newBuffer;
+ return newBuffer;
}
-
-
static void uriDecorateFree(UriMemoryManager * memory, void * ptr) {
- UriMemoryManager * backend;
+ UriMemoryManager * backend;
- if ((ptr == NULL) || (memory == NULL)) {
- return;
- }
+ if ((ptr == NULL) || (memory == NULL)) {
+ return;
+ }
- backend = (UriMemoryManager *)memory->userData;
- if (backend == NULL) {
- return;
- }
+ backend = (UriMemoryManager *)memory->userData;
+ if (backend == NULL) {
+ return;
+ }
- backend->free(backend, (char *)ptr - sizeof(size_t));
+ backend->free(backend, (char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING);
}
+int uriCompleteMemoryManager(UriMemoryManager * memory, UriMemoryManager * backend) {
+ if ((memory == NULL) || (backend == NULL)) {
+ return URI_ERROR_NULL;
+ }
+ if ((backend->malloc == NULL) || (backend->free == NULL)) {
+ return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
+ }
-int uriCompleteMemoryManager(UriMemoryManager * memory,
- UriMemoryManager * backend) {
- if ((memory == NULL) || (backend == NULL)) {
- return URI_ERROR_NULL;
- }
-
- if ((backend->malloc == NULL) || (backend->free == NULL)) {
- return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
- }
-
- memory->calloc = uriEmulateCalloc;
- memory->reallocarray = uriEmulateReallocarray;
+ memory->calloc = uriEmulateCalloc;
+ memory->reallocarray = uriEmulateReallocarray;
- memory->malloc = uriDecorateMalloc;
- memory->realloc = uriDecorateRealloc;
- memory->free = uriDecorateFree;
+ memory->malloc = uriDecorateMalloc;
+ memory->realloc = uriDecorateRealloc;
+ memory->free = uriDecorateFree;
- memory->userData = backend;
+ memory->userData = backend;
- return URI_SUCCESS;
+ return URI_SUCCESS;
}
-
+/* mull-off */
+int uriTestMemoryManagerEx(UriMemoryManager * memory, UriBool challengeAlignment) {
+ const size_t mallocSize = 7;
+ const size_t callocNmemb = 3;
+ const size_t callocSize = 5;
+ const size_t callocTotalSize = callocNmemb * callocSize;
+ const size_t reallocSize = 11;
+ const size_t reallocarrayNmemb = 5;
+ const size_t reallocarraySize = 7;
+ const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize;
+ size_t index;
+ char * buffer;
+
+ if (memory == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ if (uriMemoryManagerIsComplete(memory) != URI_TRUE) {
+ return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
+ }
+
+ /* malloc + free*/
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xF1';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* calloc + free */
+ buffer = memory->calloc(memory, callocNmemb, callocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ for (index = 0; index < callocTotalSize; index++) { /* all zeros? */
+ if (buffer[index] != '\0') {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ }
+ buffer[callocTotalSize - 1] = '\xF2';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* malloc + realloc + free */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ for (index = 0; index < mallocSize; index++) {
+ buffer[index] = '\xF3';
+ }
+ buffer = memory->realloc(memory, buffer, reallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ for (index = 0; index < mallocSize; index++) { /* previous content? */
+ if (buffer[index] != '\xF3') {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ }
+ buffer[reallocSize - 1] = '\xF4';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* malloc + realloc ptr!=NULL size==0 (equals free) */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xF5';
+ memory->realloc(memory, buffer, 0);
+ buffer = NULL;
+
+ /* realloc ptr==NULL size!=0 (equals malloc) + free */
+ buffer = memory->realloc(memory, NULL, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xF6';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* realloc ptr==NULL size==0 (equals malloc) + free */
+ buffer = memory->realloc(memory, NULL, 0);
+ if (buffer != NULL) {
+ memory->free(memory, buffer);
+ buffer = NULL;
+ }
+
+ /* malloc + reallocarray + free */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ for (index = 0; index < mallocSize; index++) {
+ buffer[index] = '\xF7';
+ }
+ buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb, reallocarraySize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ for (index = 0; index < mallocSize; index++) { /* previous content? */
+ if (buffer[index] != '\xF7') {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ }
+ buffer[reallocarrayTotal - 1] = '\xF8';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xF9';
+ memory->reallocarray(memory, buffer, 0, reallocarraySize);
+ buffer = NULL;
+
+ /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xFA';
+ memory->reallocarray(memory, buffer, reallocarrayNmemb, 0);
+ buffer = NULL;
+
+ /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */
+ buffer = memory->malloc(memory, mallocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[mallocSize - 1] = '\xFB';
+ memory->reallocarray(memory, buffer, 0, 0);
+ buffer = NULL;
+
+ /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */
+ buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize);
+ if (buffer == NULL) {
+ return URI_ERROR_MEMORY_MANAGER_FAULTY;
+ }
+ buffer[callocTotalSize - 1] = '\xFC';
+ memory->free(memory, buffer);
+ buffer = NULL;
+
+ /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */
+ buffer = memory->reallocarray(memory, NULL, 0, callocSize);
+ if (buffer != NULL) {
+ memory->free(memory, buffer);
+ buffer = NULL;
+ }
+
+ /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */
+ buffer = memory->reallocarray(memory, NULL, callocNmemb, 0);
+ if (buffer != NULL) {
+ memory->free(memory, buffer);
+ buffer = NULL;
+ }
+
+ /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */
+ buffer = memory->reallocarray(memory, NULL, 0, 0);
+ if (buffer != NULL) {
+ memory->free(memory, buffer);
+ buffer = NULL;
+ }
+
+ /* challenge pointer alignment */
+ if (challengeAlignment == URI_TRUE) {
+ long double * ptr = memory->malloc(memory, 4 * sizeof(long double));
+ if (ptr != NULL) {
+ ptr[0] = 0.0L;
+ ptr[1] = 1.1L;
+ ptr[2] = 2.2L;
+ ptr[3] = 3.3L;
+
+ long double * const ptrNew =
+ memory->realloc(memory, ptr, 8 * sizeof(long double));
+ if (ptrNew != NULL) {
+ ptr = ptrNew;
+ ptr[4] = 4.4L;
+ ptr[5] = 5.5L;
+ ptr[6] = 6.6L;
+ ptr[7] = 7.7L;
+ }
+
+ memory->free(memory, ptr);
+ }
+ }
+
+ return URI_SUCCESS;
+}
+/* mull-on */
int uriTestMemoryManager(UriMemoryManager * memory) {
- const size_t mallocSize = 7;
- const size_t callocNmemb = 3;
- const size_t callocSize = 5;
- const size_t callocTotalSize = callocNmemb * callocSize;
- const size_t reallocSize = 11;
- const size_t reallocarrayNmemb = 5;
- const size_t reallocarraySize = 7;
- const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize;
- size_t index;
- char * buffer;
-
- if (memory == NULL) {
- return URI_ERROR_NULL;
- }
-
- if (uriMemoryManagerIsComplete(memory) != URI_TRUE) {
- return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
- }
-
- /* malloc + free*/
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xF1';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* calloc + free */
- buffer = memory->calloc(memory, callocNmemb, callocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- for (index = 0; index < callocTotalSize; index++) { /* all zeros? */
- if (buffer[index] != '\0') {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- }
- buffer[callocTotalSize - 1] = '\xF2';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* malloc + realloc + free */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- for (index = 0; index < mallocSize; index++) {
- buffer[index] = '\xF3';
- }
- buffer = memory->realloc(memory, buffer, reallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- for (index = 0; index < mallocSize; index++) { /* previous content? */
- if (buffer[index] != '\xF3') {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- }
- buffer[reallocSize - 1] = '\xF4';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* malloc + realloc ptr!=NULL size==0 (equals free) */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xF5';
- memory->realloc(memory, buffer, 0);
- buffer = NULL;
-
- /* realloc ptr==NULL size!=0 (equals malloc) + free */
- buffer = memory->realloc(memory, NULL, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xF6';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* realloc ptr==NULL size==0 (equals malloc) + free */
- buffer = memory->realloc(memory, NULL, 0);
- if (buffer != NULL) {
- memory->free(memory, buffer);
- buffer = NULL;
- }
-
- /* malloc + reallocarray + free */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- for (index = 0; index < mallocSize; index++) {
- buffer[index] = '\xF7';
- }
- buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb,
- reallocarraySize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- for (index = 0; index < mallocSize; index++) { /* previous content? */
- if (buffer[index] != '\xF7') {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- }
- buffer[reallocarrayTotal - 1] = '\xF8';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xF9';
- memory->reallocarray(memory, buffer, 0, reallocarraySize);
- buffer = NULL;
-
- /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xFA';
- memory->reallocarray(memory, buffer, reallocarrayNmemb, 0);
- buffer = NULL;
-
- /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */
- buffer = memory->malloc(memory, mallocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[mallocSize - 1] = '\xFB';
- memory->reallocarray(memory, buffer, 0, 0);
- buffer = NULL;
-
- /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */
- buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize);
- if (buffer == NULL) {
- return URI_ERROR_MEMORY_MANAGER_FAULTY;
- }
- buffer[callocTotalSize - 1] = '\xFC';
- memory->free(memory, buffer);
- buffer = NULL;
-
- /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */
- buffer = memory->reallocarray(memory, NULL, 0, callocSize);
- if (buffer != NULL) {
- memory->free(memory, buffer);
- buffer = NULL;
- }
-
- /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */
- buffer = memory->reallocarray(memory, NULL, callocNmemb, 0);
- if (buffer != NULL) {
- memory->free(memory, buffer);
- buffer = NULL;
- }
-
- /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */
- buffer = memory->reallocarray(memory, NULL, 0, 0);
- if (buffer != NULL) {
- memory->free(memory, buffer);
- buffer = NULL;
- }
-
- return URI_SUCCESS;
+ return uriTestMemoryManagerEx(memory, /*challengeAlignment=*/URI_FALSE);
}
-
-
/*extern*/ UriMemoryManager defaultMemoryManager = {
- uriDefaultMalloc,
- uriDefaultCalloc,
- uriDefaultRealloc,
- uriDefaultReallocarray,
- uriDefaultFree,
- NULL /* userData */
+ uriDefaultMalloc, uriDefaultCalloc, uriDefaultRealloc,
+ uriDefaultReallocarray, uriDefaultFree, NULL /* userData */
};
diff --git a/src/UriMemory.h b/src/UriMemory.h
index a930f93..b03ca4a 100644
--- a/src/UriMemory.h
+++ b/src/UriMemory.h
@@ -38,41 +38,31 @@
*/
#ifndef URI_MEMORY_H
-#define URI_MEMORY_H 1
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-#endif
-
-
-
-#define URI_CHECK_MEMORY_MANAGER(memory) \
- do { \
- if (memory == NULL) { \
- memory = &defaultMemoryManager; \
- } else if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { \
- return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; \
- } \
- } while (0)
-
-
-
-#ifdef __cplusplus
-# define URIPARSER_EXTERN extern "C"
-#else
-# define URIPARSER_EXTERN extern
-#endif
+# define URI_MEMORY_H 1
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# endif
+
+# define URI_CHECK_MEMORY_MANAGER(memory) \
+ do { \
+ if (memory == NULL) { \
+ memory = &defaultMemoryManager; \
+ } else if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { \
+ return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; \
+ } \
+ } while (0)
+
+# ifdef __cplusplus
+# define URIPARSER_EXTERN extern "C"
+# else
+# define URIPARSER_EXTERN extern
+# endif
URIPARSER_EXTERN UriMemoryManager defaultMemoryManager;
-#undef URIPARSER_EXTERN
-
-
+# undef URIPARSER_EXTERN
UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory);
-
-
#endif /* URI_MEMORY_H */
diff --git a/src/UriNormalize.c b/src/UriNormalize.c
index eb072b2..8c812d3 100644
--- a/src/UriNormalize.c
+++ b/src/UriNormalize.c
@@ -47,763 +47,818 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriNormalize.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriNormalize.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriNormalize.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriNormalize.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriNormalizeBase.h"
-# include "UriCommon.h"
-# include "UriMemory.h"
-#endif
-
-
-
-#include <assert.h>
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriNormalizeBase.h"
+# include "UriCommon.h"
+# include "UriMemory.h"
+# endif
+
+# include <assert.h>
static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
- unsigned int * outMask, UriMemoryManager * memory);
+ unsigned int * outMask,
+ UriMemoryManager * memory);
-static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
- unsigned int maskTest, URI_TYPE(TextRange) * range,
- UriMemoryManager * memory);
-static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
- unsigned int * doneMask, UriMemoryManager * memory);
+static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask, unsigned int maskTest,
+ URI_TYPE(TextRange) * range,
+ UriMemoryManager * memory);
+static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri, unsigned int * revertMask,
+ UriMemoryManager * memory);
static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
- const URI_CHAR ** afterLast);
+ const URI_CHAR ** afterLast);
static UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
- const URI_CHAR ** afterLast, UriMemoryManager * memory);
-static void URI_FUNC(FixPercentEncodingEngine)(
- const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
- const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast);
+ const URI_CHAR ** afterLast,
+ UriMemoryManager * memory);
+static void URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst,
+ const URI_CHAR * inAfterLast,
+ const URI_CHAR * outFirst,
+ const URI_CHAR ** outAfterLast);
static UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
- const URI_CHAR * afterLast);
+ const URI_CHAR * afterLast);
static UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first,
- const URI_CHAR * afterLast);
+ const URI_CHAR * afterLast);
static void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
- const URI_CHAR * afterLast);
+ const URI_CHAR * afterLast);
+static void URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
static UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
- const URI_CHAR ** afterLast, UriMemoryManager * memory);
-
-static void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri,
- unsigned int revertMask, UriMemoryManager * memory);
-
-
-
-static URI_INLINE void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri,
- unsigned int revertMask, UriMemoryManager * memory) {
- if (revertMask & URI_NORMALIZE_SCHEME) {
- /* NOTE: A scheme cannot be the empty string
- * so no need to compare .first with .afterLast, here. */
- memory->free(memory, (URI_CHAR *)uri->scheme.first);
- uri->scheme.first = NULL;
- uri->scheme.afterLast = NULL;
- }
-
- if (revertMask & URI_NORMALIZE_USER_INFO) {
- if (uri->userInfo.first != uri->userInfo.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->userInfo.first);
- }
- uri->userInfo.first = NULL;
- uri->userInfo.afterLast = NULL;
- }
-
- if (revertMask & URI_NORMALIZE_HOST) {
- if (uri->hostData.ipFuture.first != NULL) {
- /* IPvFuture */
- /* NOTE: An IPvFuture address cannot be the empty string
- * so no need to compare .first with .afterLast, here. */
- memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
- uri->hostData.ipFuture.first = NULL;
- uri->hostData.ipFuture.afterLast = NULL;
- uri->hostText.first = NULL;
- uri->hostText.afterLast = NULL;
- } else if (uri->hostText.first != NULL) {
- /* Regname */
- if (uri->hostText.first != uri->hostText.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->hostText.first);
- }
- uri->hostText.first = NULL;
- uri->hostText.afterLast = NULL;
- }
- }
-
- /* NOTE: Port cannot happen! */
-
- if (revertMask & URI_NORMALIZE_PATH) {
- URI_TYPE(PathSegment) * walker = uri->pathHead;
- while (walker != NULL) {
- URI_TYPE(PathSegment) * const next = walker->next;
- if (walker->text.afterLast > walker->text.first) {
- memory->free(memory, (URI_CHAR *)walker->text.first);
- }
- memory->free(memory, walker);
- walker = next;
- }
- uri->pathHead = NULL;
- uri->pathTail = NULL;
- }
-
- if (revertMask & URI_NORMALIZE_QUERY) {
- if (uri->query.first != uri->query.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->query.first);
- }
- uri->query.first = NULL;
- uri->query.afterLast = NULL;
- }
-
- if (revertMask & URI_NORMALIZE_FRAGMENT) {
- if (uri->fragment.first != uri->fragment.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->fragment.first);
- }
- uri->fragment.first = NULL;
- uri->fragment.afterLast = NULL;
- }
+ const URI_CHAR ** afterLast,
+ UriMemoryManager * memory);
+
+void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, unsigned int revertMask,
+ UriMemoryManager * memory) {
+ if (revertMask & URI_NORMALIZE_SCHEME) {
+ /* NOTE: A scheme cannot be the empty string
+ * so no need to compare .first with .afterLast, here. */
+ memory->free(memory, (URI_CHAR *)uri->scheme.first);
+ uri->scheme.first = NULL;
+ uri->scheme.afterLast = NULL;
+ }
+
+ if (revertMask & URI_NORMALIZE_USER_INFO) {
+ if (uri->userInfo.first != uri->userInfo.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->userInfo.first);
+ }
+ uri->userInfo.first = NULL;
+ uri->userInfo.afterLast = NULL;
+ }
+
+ if (revertMask & URI_NORMALIZE_HOST) {
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* IPvFuture */
+ /* NOTE: An IPvFuture address cannot be the empty string
+ * so no need to compare .first with .afterLast, here. */
+ memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
+ uri->hostData.ipFuture.first = NULL;
+ uri->hostData.ipFuture.afterLast = NULL;
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+ } else if (uri->hostText.first != NULL) {
+ /* Regname */
+ if (uri->hostText.first != uri->hostText.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->hostText.first);
+ }
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+ }
+ }
+
+ /* NOTE: Port cannot happen! */
+
+ if (revertMask & URI_NORMALIZE_PATH) {
+ URI_TYPE(PathSegment) * walker = uri->pathHead;
+ while (walker != NULL) {
+ URI_TYPE(PathSegment) * const next = walker->next;
+ if (walker->text.afterLast > walker->text.first) {
+ memory->free(memory, (URI_CHAR *)walker->text.first);
+ }
+ memory->free(memory, walker);
+ walker = next;
+ }
+ uri->pathHead = NULL;
+ uri->pathTail = NULL;
+ }
+
+ if (revertMask & URI_NORMALIZE_QUERY) {
+ if (uri->query.first != uri->query.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->query.first);
+ }
+ uri->query.first = NULL;
+ uri->query.afterLast = NULL;
+ }
+
+ if (revertMask & URI_NORMALIZE_FRAGMENT) {
+ if (uri->fragment.first != uri->fragment.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->fragment.first);
+ }
+ uri->fragment.first = NULL;
+ uri->fragment.afterLast = NULL;
+ }
}
-
-
static URI_INLINE UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
- const URI_CHAR * afterLast) {
- if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
- const URI_CHAR * i = first;
- for (; i < afterLast; i++) {
- /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */
- if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
- return URI_TRUE;
- }
- }
- }
- return URI_FALSE;
+ const URI_CHAR * afterLast) {
+ if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
+ const URI_CHAR * i = first;
+ for (; i < afterLast; i++) {
+ /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */
+ if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
+ return URI_TRUE;
+ }
+ }
+ }
+ return URI_FALSE;
}
-
-
-static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first,
- const URI_CHAR * afterLast) {
- if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
- const URI_CHAR * i = first;
- for (; i + 2 < afterLast; i++) {
- if (i[0] == _UT('%')) {
- /* 6.2.2.1 Case Normalization: *
- * lowercase percent-encodings */
- if (((i[1] >= _UT('a')) && (i[1] <= _UT('f')))
- || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) {
- return URI_TRUE;
- } else {
- /* 6.2.2.2 Percent-Encoding Normalization: *
- * percent-encoded unreserved characters */
- const unsigned char left = URI_FUNC(HexdigToInt)(i[1]);
- const unsigned char right = URI_FUNC(HexdigToInt)(i[2]);
- const int code = 16 * left + right;
- if (uriIsUnreserved(code)) {
- return URI_TRUE;
- }
- }
- }
- }
- }
- return URI_FALSE;
+static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(
+ const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
+ const URI_CHAR * i = first;
+ for (; i + 2 < afterLast; i++) {
+ if (i[0] == _UT('%')) {
+ /* 6.2.2.1 Case Normalization: *
+ * lowercase percent-encodings */
+ if (((i[1] >= _UT('a')) && (i[1] <= _UT('f')))
+ || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) {
+ return URI_TRUE;
+ } else {
+ /* 6.2.2.2 Percent-Encoding Normalization: *
+ * percent-encoded unreserved characters */
+ const unsigned char left = URI_FUNC(HexdigToInt)(i[1]);
+ const unsigned char right = URI_FUNC(HexdigToInt)(i[2]);
+ const int code = 16 * left + right;
+ if (uriIsUnreserved(code)) {
+ return URI_TRUE;
+ }
+ }
+ }
+ }
+ }
+ return URI_FALSE;
}
-
-
static URI_INLINE void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
- const URI_CHAR * afterLast) {
- if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
- URI_CHAR * i = (URI_CHAR *)first;
- const int lowerUpperDiff = (_UT('a') - _UT('A'));
- for (; i < afterLast; i++) {
- if ((*i >= _UT('A')) && (*i <=_UT('Z'))) {
- *i = (URI_CHAR)(*i + lowerUpperDiff);
- }
- }
- }
+ const URI_CHAR * afterLast) {
+ if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
+ URI_CHAR * i = (URI_CHAR *)first;
+ const int lowerUpperDiff = (_UT('a') - _UT('A'));
+ for (; i < afterLast; i++) {
+ if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
+ *i = (URI_CHAR)(*i + lowerUpperDiff);
+ }
+ }
+ }
}
-
+static URI_INLINE void
+URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
+ URI_CHAR * i = (URI_CHAR *)first;
+ const int lowerUpperDiff = (_UT('a') - _UT('A'));
+ for (; i < afterLast; i++) {
+ if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
+ *i = (URI_CHAR)(*i + lowerUpperDiff);
+ } else if (*i == _UT('%')) {
+ if (i + 3 >= afterLast) {
+ return;
+ }
+ i += 2;
+ }
+ }
+ }
+}
static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
- const URI_CHAR ** afterLast, UriMemoryManager * memory) {
- int lenInChars;
- const int lowerUpperDiff = (_UT('a') - _UT('A'));
- URI_CHAR * buffer;
- int i = 0;
-
- if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
- || (*afterLast == NULL)) {
- return URI_FALSE;
- }
-
- lenInChars = (int)(*afterLast - *first);
- if (lenInChars == 0) {
- return URI_TRUE;
- } else if (lenInChars < 0) {
- return URI_FALSE;
- }
-
- buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
- if (buffer == NULL) {
- return URI_FALSE;
- }
-
- for (; i < lenInChars; i++) {
- if (((*first)[i] >= _UT('A')) && ((*first)[i] <=_UT('Z'))) {
- buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff);
- } else {
- buffer[i] = (*first)[i];
- }
- }
-
- *first = buffer;
- *afterLast = buffer + lenInChars;
- return URI_TRUE;
+ const URI_CHAR ** afterLast,
+ UriMemoryManager * memory) {
+ int lenInChars;
+ const int lowerUpperDiff = (_UT('a') - _UT('A'));
+ URI_CHAR * buffer;
+ int i = 0;
+
+ if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
+ || (*afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ lenInChars = (int)(*afterLast - *first);
+ if (lenInChars == 0) {
+ return URI_TRUE;
+ } else if (lenInChars < 0) {
+ return URI_FALSE;
+ }
+
+ buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
+ if (buffer == NULL) {
+ return URI_FALSE;
+ }
+
+ for (; i < lenInChars; i++) {
+ if (((*first)[i] >= _UT('A')) && ((*first)[i] <= _UT('Z'))) {
+ buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff);
+ } else {
+ buffer[i] = (*first)[i];
+ }
+ }
+
+ *first = buffer;
+ *afterLast = buffer + lenInChars;
+ return URI_TRUE;
}
-
-
/* NOTE: Implementation must stay inplace-compatible */
-static URI_INLINE void URI_FUNC(FixPercentEncodingEngine)(
- const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
- const URI_CHAR * outFirst, const URI_CHAR ** outAfterLast) {
- URI_CHAR * write = (URI_CHAR *)outFirst;
- const int lenInChars = (int)(inAfterLast - inFirst);
- int i = 0;
-
- /* All but last two */
- for (; i + 2 < lenInChars; i++) {
- if (inFirst[i] != _UT('%')) {
- write[0] = inFirst[i];
- write++;
- } else {
- /* 6.2.2.2 Percent-Encoding Normalization: *
- * percent-encoded unreserved characters */
- const URI_CHAR one = inFirst[i + 1];
- const URI_CHAR two = inFirst[i + 2];
- const unsigned char left = URI_FUNC(HexdigToInt)(one);
- const unsigned char right = URI_FUNC(HexdigToInt)(two);
- const int code = 16 * left + right;
- if (uriIsUnreserved(code)) {
- write[0] = (URI_CHAR)(code);
- write++;
- } else {
- /* 6.2.2.1 Case Normalization: *
- * lowercase percent-encodings */
- write[0] = _UT('%');
- write[1] = URI_FUNC(HexToLetter)(left);
- write[2] = URI_FUNC(HexToLetter)(right);
- write += 3;
- }
-
- i += 2; /* For the two chars of the percent group we just ate */
- }
- }
-
- /* Last two */
- for (; i < lenInChars; i++) {
- write[0] = inFirst[i];
- write++;
- }
-
- *outAfterLast = write;
+static URI_INLINE void
+URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
+ const URI_CHAR * outFirst,
+ const URI_CHAR ** outAfterLast) {
+ URI_CHAR * write = (URI_CHAR *)outFirst;
+ const int lenInChars = (int)(inAfterLast - inFirst);
+ int i = 0;
+
+ /* All but last two */
+ for (; i + 2 < lenInChars; i++) {
+ if (inFirst[i] != _UT('%')) {
+ write[0] = inFirst[i];
+ write++;
+ } else {
+ /* 6.2.2.2 Percent-Encoding Normalization: *
+ * percent-encoded unreserved characters */
+ const URI_CHAR one = inFirst[i + 1];
+ const URI_CHAR two = inFirst[i + 2];
+ const unsigned char left = URI_FUNC(HexdigToInt)(one);
+ const unsigned char right = URI_FUNC(HexdigToInt)(two);
+ const int code = 16 * left + right;
+ if (uriIsUnreserved(code)) {
+ write[0] = (URI_CHAR)(code);
+ write++;
+ } else {
+ /* 6.2.2.1 Case Normalization: *
+ * uppercase percent-encodings */
+ write[0] = _UT('%');
+ write[1] = URI_FUNC(HexToLetterEx)(left, URI_TRUE);
+ write[2] = URI_FUNC(HexToLetterEx)(right, URI_TRUE);
+ write += 3;
+ }
+
+ i += 2; /* For the two chars of the percent group we just ate */
+ }
+ }
+
+ /* Last two */
+ for (; i < lenInChars; i++) {
+ write[0] = inFirst[i];
+ write++;
+ }
+
+ *outAfterLast = write;
}
-
-
static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
- const URI_CHAR ** afterLast) {
- /* Death checks */
- if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) {
- return;
- }
-
- /* Fix inplace */
- URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast);
+ const URI_CHAR ** afterLast) {
+ /* Death checks */
+ if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) {
+ return;
+ }
+
+ /* Fix inplace */
+ URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast);
}
-
-
static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
- const URI_CHAR ** afterLast, UriMemoryManager * memory) {
- int lenInChars;
- URI_CHAR * buffer;
-
- /* Death checks */
- if ((first == NULL) || (afterLast == NULL)
- || (*first == NULL) || (*afterLast == NULL)) {
- return URI_FALSE;
- }
-
- /* Old text length */
- lenInChars = (int)(*afterLast - *first);
- if (lenInChars == 0) {
- return URI_TRUE;
- } else if (lenInChars < 0) {
- return URI_FALSE;
- }
-
- /* New buffer */
- buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
- if (buffer == NULL) {
- return URI_FALSE;
- }
-
- /* Fix on copy */
- URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast);
- *first = buffer;
- return URI_TRUE;
+ const URI_CHAR ** afterLast,
+ UriMemoryManager * memory) {
+ int lenInChars;
+ URI_CHAR * buffer;
+
+ /* Death checks */
+ if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
+ || (*afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* Old text length */
+ lenInChars = (int)(*afterLast - *first);
+ if (lenInChars == 0) {
+ return URI_TRUE;
+ } else if (lenInChars < 0) {
+ return URI_FALSE;
+ }
+
+ /* New buffer */
+ buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
+ if (buffer == NULL) {
+ return URI_FALSE;
+ }
+
+ /* Fix on copy */
+ URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast);
+ *first = buffer;
+ return URI_TRUE;
}
-
-
-static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * doneMask,
- unsigned int maskTest, URI_TYPE(TextRange) * range,
- UriMemoryManager * memory) {
- if (((*doneMask & maskTest) == 0)
- && (range->first != NULL)
- && (range->afterLast != NULL)
- && (range->afterLast > range->first)) {
- const int lenInChars = (int)(range->afterLast - range->first);
- const int lenInBytes = lenInChars * sizeof(URI_CHAR);
- URI_CHAR * dup = memory->malloc(memory, lenInBytes);
- if (dup == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- memcpy(dup, range->first, lenInBytes);
- range->first = dup;
- range->afterLast = dup + lenInChars;
- *doneMask |= maskTest;
- }
- return URI_TRUE;
+static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask,
+ unsigned int maskTest,
+ URI_TYPE(TextRange) * range,
+ UriMemoryManager * memory) {
+ if (((*revertMask & maskTest) == 0) && (range->first != NULL)
+ && (range->afterLast != NULL) && (range->afterLast > range->first)) {
+ if (URI_FUNC(CopyRange)(range, range, memory) == URI_FALSE) {
+ return URI_FALSE;
+ }
+ *revertMask |= maskTest;
+ }
+ return URI_TRUE;
}
-
-
static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
- unsigned int * doneMask, UriMemoryManager * memory) {
- URI_TYPE(PathSegment) * walker = uri->pathHead;
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_SCHEME,
- &(uri->scheme), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_USER_INFO,
- &(uri->userInfo), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_QUERY,
- &(uri->query), memory)
- || !URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_FRAGMENT,
- &(uri->fragment), memory)) {
- return URI_FALSE; /* Raises malloc error */
- }
-
- /* Host */
- if ((*doneMask & URI_NORMALIZE_HOST) == 0) {
- if (uri->hostData.ipFuture.first != NULL) {
- /* IPvFuture */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
- &(uri->hostData.ipFuture), memory)) {
- return URI_FALSE; /* Raises malloc error */
- }
- uri->hostText.first = uri->hostData.ipFuture.first;
- uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
- } else if (uri->hostText.first != NULL) {
- /* Regname */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, URI_NORMALIZE_HOST,
- &(uri->hostText), memory)) {
- return URI_FALSE; /* Raises malloc error */
- }
- }
- }
-
- /* Path */
- if ((*doneMask & URI_NORMALIZE_PATH) == 0) {
- while (walker != NULL) {
- if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(walker->text), memory)) {
- /* Free allocations done so far and kill path */
-
- /* Kill path to one before walker (if any) */
- URI_TYPE(PathSegment) * ranger = uri->pathHead;
- while (ranger != walker) {
- URI_TYPE(PathSegment) * const next = ranger->next;
- if ((ranger->text.first != NULL)
- && (ranger->text.afterLast != NULL)
- && (ranger->text.afterLast > ranger->text.first)) {
- memory->free(memory, (URI_CHAR *)ranger->text.first);
- }
- memory->free(memory, ranger);
- ranger = next;
- }
-
- /* Kill path from walker */
- while (walker != NULL) {
- URI_TYPE(PathSegment) * const next = walker->next;
- memory->free(memory, walker);
- walker = next;
- }
-
- uri->pathHead = NULL;
- uri->pathTail = NULL;
- return URI_FALSE; /* Raises malloc error */
- }
- walker = walker->next;
- }
- *doneMask |= URI_NORMALIZE_PATH;
- }
-
- /* Port text, must come last so we don't have to undo that one if it fails. *
- * Otherwise we would need and extra enum flag for it although the port *
- * cannot go unnormalized... */
- if (!URI_FUNC(MakeRangeOwner)(doneMask, 0, &(uri->portText), memory)) {
- return URI_FALSE; /* Raises malloc error */
- }
-
- return URI_TRUE;
+ unsigned int * revertMask,
+ UriMemoryManager * memory) {
+ URI_TYPE(PathSegment) * walker = uri->pathHead;
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_SCHEME, &(uri->scheme),
+ memory)
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_USER_INFO,
+ &(uri->userInfo), memory)
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_QUERY, &(uri->query),
+ memory)
+ || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_FRAGMENT, &(uri->fragment),
+ memory)) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ /* Host */
+ if ((*revertMask & URI_NORMALIZE_HOST) == 0) {
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* IPvFuture */
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
+ &(uri->hostData.ipFuture), memory)) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ uri->hostText.first = uri->hostData.ipFuture.first;
+ uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
+ } else if (uri->hostText.first != NULL) {
+ /* Regname */
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
+ &(uri->hostText), memory)) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ }
+ }
+
+ /* Path */
+ if ((*revertMask & URI_NORMALIZE_PATH) == 0) {
+ while (walker != NULL) {
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(walker->text), memory)) {
+ /* Free allocations done so far and kill path */
+
+ /* Kill path to one before walker (if any) */
+ URI_TYPE(PathSegment) * ranger = uri->pathHead;
+ while (ranger != walker) {
+ URI_TYPE(PathSegment) * const next = ranger->next;
+ if ((ranger->text.first != NULL) && (ranger->text.afterLast != NULL)
+ && (ranger->text.afterLast > ranger->text.first)) {
+ memory->free(memory, (URI_CHAR *)ranger->text.first);
+ }
+ memory->free(memory, ranger);
+ ranger = next;
+ }
+
+ /* Kill path from walker */
+ while (walker != NULL) {
+ URI_TYPE(PathSegment) * const next = walker->next;
+ memory->free(memory, walker);
+ walker = next;
+ }
+
+ uri->pathHead = NULL;
+ uri->pathTail = NULL;
+ return URI_FALSE; /* Raises malloc error */
+ }
+ walker = walker->next;
+ }
+ *revertMask |= URI_NORMALIZE_PATH;
+ }
+
+ /* Port text, must come last so we don't have to undo that one if it fails. *
+ * Otherwise we would need and extra enum flag for it although the port *
+ * cannot go unnormalized... */
+ if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(uri->portText), memory)) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ return URI_TRUE;
}
-
-
unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri) {
- unsigned int outMask = URI_NORMALIZED; /* for NULL uri */
- URI_FUNC(NormalizeSyntaxMaskRequiredEx)(uri, &outMask);
- return outMask;
+ unsigned int outMask = URI_NORMALIZED; /* for NULL uri */
+ URI_FUNC(NormalizeSyntaxMaskRequiredEx)(uri, &outMask);
+ return outMask;
}
-
-
int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(const URI_TYPE(Uri) * uri,
- unsigned int * outMask) {
- UriMemoryManager * const memory = NULL; /* no use of memory manager */
-
-#if defined(__GNUC__) && ((__GNUC__ > 4) \
- || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
- /* Slower code that fixes a warning, not sure if this is a smart idea */
- URI_TYPE(Uri) writeableClone;
-#endif
-
- if ((uri == NULL) || (outMask == NULL)) {
- return URI_ERROR_NULL;
- }
-
-#if defined(__GNUC__) && ((__GNUC__ > 4) \
- || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
- /* Slower code that fixes a warning, not sure if this is a smart idea */
- memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri)));
- URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, outMask, memory);
-#else
- URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, outMask, memory);
-#endif
- return URI_SUCCESS;
+ unsigned int * outMask) {
+ UriMemoryManager * const memory = NULL; /* no use of memory manager */
+
+# if defined(__GNUC__) \
+ && ((__GNUC__ > 4) \
+ || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
+ /* Slower code that fixes a warning, not sure if this is a smart idea */
+ URI_TYPE(Uri) writeableClone;
+# endif
+
+ if ((uri == NULL) || (outMask == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+# if defined(__GNUC__) \
+ && ((__GNUC__ > 4) \
+ || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
+ /* Slower code that fixes a warning, not sure if this is a smart idea */
+ memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri)));
+ URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, outMask, memory);
+# else
+ URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, outMask, memory);
+# endif
+ return URI_SUCCESS;
}
-
-
int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask) {
- return URI_FUNC(NormalizeSyntaxExMm)(uri, mask, NULL);
+ return URI_FUNC(NormalizeSyntaxExMm)(uri, mask, NULL);
}
+int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask,
+ UriMemoryManager * memory) {
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+ return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL, memory);
+}
+int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) {
+ return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1);
+}
-int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask,
- UriMemoryManager * memory) {
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
- return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL, memory);
+static const URI_CHAR * URI_FUNC(PastLeadingZeros)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ assert(first != NULL);
+ assert(afterLast != NULL);
+ assert(first != afterLast);
+
+ /* Find the first non-zero character */
+ const URI_CHAR * remainderFirst = first;
+ while ((remainderFirst < afterLast) && (remainderFirst[0] == _UT('0'))) {
+ remainderFirst++;
+ }
+
+ /* Is the string /all/ zeros? */
+ if (remainderFirst == afterLast) {
+ /* Yes, and length is >=1 because we ruled out the empty string earlier;
+ * pull back onto rightmost zero */
+ assert(remainderFirst > first);
+ remainderFirst--;
+ assert(remainderFirst[0] == _UT('0'));
+ }
+
+ return remainderFirst;
}
+static void URI_FUNC(DropLeadingZerosInplace)(URI_CHAR * first,
+ const URI_CHAR ** afterLast) {
+ assert(first != NULL);
+ assert(afterLast != NULL);
+ assert(*afterLast != NULL);
+ if (first == *afterLast) {
+ return;
+ }
-int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) {
- return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1);
+ const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(first, *afterLast);
+
+ if (remainderFirst > first) {
+ const size_t remainderLen = *afterLast - remainderFirst;
+ memmove(first, remainderFirst, remainderLen * sizeof(URI_CHAR));
+ first[remainderLen] = _UT('\0');
+ *afterLast = first + remainderLen;
+ }
}
+static void URI_FUNC(AdvancePastLeadingZeros)(const URI_CHAR ** first,
+ const URI_CHAR * afterLast) {
+ assert(first != NULL);
+ assert(*first != NULL);
+ assert(afterLast != NULL);
+ if (*first == afterLast) {
+ return;
+ }
-static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
- unsigned int inMask, unsigned int * outMask,
- UriMemoryManager * memory) {
- unsigned int doneMask = URI_NORMALIZED;
-
- /* Not just doing inspection? -> memory manager required! */
- if (outMask == NULL) {
- assert(memory != NULL);
- }
-
- if (uri == NULL) {
- if (outMask != NULL) {
- *outMask = URI_NORMALIZED;
- return URI_SUCCESS;
- } else {
- return URI_ERROR_NULL;
- }
- }
-
- if (outMask != NULL) {
- /* Reset mask */
- *outMask = URI_NORMALIZED;
- } else if (inMask == URI_NORMALIZED) {
- /* Nothing to do */
- return URI_SUCCESS;
- }
-
- /* Scheme, host */
- if (outMask != NULL) {
- const UriBool normalizeScheme = URI_FUNC(ContainsUppercaseLetters)(
- uri->scheme.first, uri->scheme.afterLast);
- const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)(
- uri->hostText.first, uri->hostText.afterLast);
- if (normalizeScheme) {
- *outMask |= URI_NORMALIZE_SCHEME;
- }
-
- if (normalizeHostCase) {
- *outMask |= URI_NORMALIZE_HOST;
- } else {
- const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)(
- uri->hostText.first, uri->hostText.afterLast);
- if (normalizeHostPrecent) {
- *outMask |= URI_NORMALIZE_HOST;
- }
- }
- } else {
- /* Scheme */
- if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) {
- if (uri->owner) {
- URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast);
- } else {
- if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first), &(uri->scheme.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_SCHEME;
- }
- }
-
- /* Host */
- if (inMask & URI_NORMALIZE_HOST) {
- if (uri->hostData.ipFuture.first != NULL) {
- /* IPvFuture */
- if (uri->owner) {
- URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first,
- uri->hostData.ipFuture.afterLast);
- } else {
- if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first),
- &(uri->hostData.ipFuture.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_HOST;
- }
- uri->hostText.first = uri->hostData.ipFuture.first;
- uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
- } else if ((uri->hostText.first != NULL)
- && (uri->hostData.ip4 == NULL)
- && (uri->hostData.ip6 == NULL)) {
- /* Regname */
- if (uri->owner) {
- URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first,
- &(uri->hostText.afterLast));
- } else {
- if (!URI_FUNC(FixPercentEncodingMalloc)(
- &(uri->hostText.first),
- &(uri->hostText.afterLast),
- memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_HOST;
- }
-
- URI_FUNC(LowercaseInplace)(uri->hostText.first,
- uri->hostText.afterLast);
- }
- }
- }
-
- /* User info */
- if (outMask != NULL) {
- const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)(
- uri->userInfo.first, uri->userInfo.afterLast);
- if (normalizeUserInfo) {
- *outMask |= URI_NORMALIZE_USER_INFO;
- }
- } else {
- if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) {
- if (uri->owner) {
- URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first, &(uri->userInfo.afterLast));
- } else {
- if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->userInfo.first),
- &(uri->userInfo.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_USER_INFO;
- }
- }
- }
-
- /* Path */
- if (outMask != NULL) {
- const URI_TYPE(PathSegment) * walker = uri->pathHead;
- while (walker != NULL) {
- const URI_CHAR * const first = walker->text.first;
- const URI_CHAR * const afterLast = walker->text.afterLast;
- if ((first != NULL)
- && (afterLast != NULL)
- && (afterLast > first)
- && (
- (((afterLast - first) == 1)
- && (first[0] == _UT('.')))
- ||
- (((afterLast - first) == 2)
- && (first[0] == _UT('.'))
- && (first[1] == _UT('.')))
- ||
- URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast)
- )) {
- *outMask |= URI_NORMALIZE_PATH;
- break;
- }
- walker = walker->next;
- }
- } else if (inMask & URI_NORMALIZE_PATH) {
- URI_TYPE(PathSegment) * walker;
- const UriBool relative = ((uri->scheme.first == NULL)
- && !uri->absolutePath) ? URI_TRUE : URI_FALSE;
-
- /* Fix percent-encoding for each segment */
- walker = uri->pathHead;
- if (uri->owner) {
- while (walker != NULL) {
- URI_FUNC(FixPercentEncodingInplace)(walker->text.first, &(walker->text.afterLast));
- walker = walker->next;
- }
- } else {
- while (walker != NULL) {
- if (!URI_FUNC(FixPercentEncodingMalloc)(&(walker->text.first),
- &(walker->text.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- walker = walker->next;
- }
- doneMask |= URI_NORMALIZE_PATH;
- }
-
- /* 6.2.2.3 Path Segment Normalization */
- if (!URI_FUNC(RemoveDotSegmentsEx)(uri, relative,
- (uri->owner == URI_TRUE)
- || ((doneMask & URI_NORMALIZE_PATH) != 0),
- memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- URI_FUNC(FixEmptyTrailSegment)(uri, memory);
- }
-
- /* Query, fragment */
- if (outMask != NULL) {
- const UriBool normalizeQuery = URI_FUNC(ContainsUglyPercentEncoding)(
- uri->query.first, uri->query.afterLast);
- const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)(
- uri->fragment.first, uri->fragment.afterLast);
- if (normalizeQuery) {
- *outMask |= URI_NORMALIZE_QUERY;
- }
-
- if (normalizeFragment) {
- *outMask |= URI_NORMALIZE_FRAGMENT;
- }
- } else {
- /* Query */
- if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) {
- if (uri->owner) {
- URI_FUNC(FixPercentEncodingInplace)(uri->query.first, &(uri->query.afterLast));
- } else {
- if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->query.first),
- &(uri->query.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_QUERY;
- }
- }
-
- /* Fragment */
- if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) {
- if (uri->owner) {
- URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first, &(uri->fragment.afterLast));
- } else {
- if (!URI_FUNC(FixPercentEncodingMalloc)(&(uri->fragment.first),
- &(uri->fragment.afterLast), memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- doneMask |= URI_NORMALIZE_FRAGMENT;
- }
- }
- }
-
- /* Dup all not duped yet */
- if ((outMask == NULL) && !uri->owner) {
- if (!URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
- uri->owner = URI_TRUE;
- }
-
- return URI_SUCCESS;
-}
+ const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(*first, afterLast);
+ /* Cut off leading zeros */
+ *first = remainderFirst;
+}
+static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
+ unsigned int inMask,
+ unsigned int * outMask,
+ UriMemoryManager * memory) {
+ unsigned int revertMask = URI_NORMALIZED;
+
+ /* Not just doing inspection? -> memory manager required! */
+ if (outMask == NULL) {
+ assert(memory != NULL);
+ }
+
+ if (uri == NULL) {
+ if (outMask != NULL) {
+ *outMask = URI_NORMALIZED;
+ return URI_SUCCESS;
+ } else {
+ return URI_ERROR_NULL;
+ }
+ }
+
+ if (outMask != NULL) {
+ /* Reset mask */
+ *outMask = URI_NORMALIZED;
+ } else if (inMask == URI_NORMALIZED) {
+ /* Nothing to do */
+ return URI_SUCCESS;
+ }
+
+ /* Scheme, host */
+ if (outMask != NULL) {
+ const UriBool normalizeScheme =
+ URI_FUNC(ContainsUppercaseLetters)(uri->scheme.first, uri->scheme.afterLast);
+ const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)(
+ uri->hostText.first, uri->hostText.afterLast);
+ if (normalizeScheme) {
+ *outMask |= URI_NORMALIZE_SCHEME;
+ }
+
+ if (normalizeHostCase) {
+ *outMask |= URI_NORMALIZE_HOST;
+ } else {
+ const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)(
+ uri->hostText.first, uri->hostText.afterLast);
+ if (normalizeHostPrecent) {
+ *outMask |= URI_NORMALIZE_HOST;
+ }
+ }
+ } else {
+ /* Scheme */
+ if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) {
+ if (uri->owner) {
+ URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast);
+ } else {
+ if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first),
+ &(uri->scheme.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_SCHEME;
+ }
+ }
+
+ /* Host */
+ if (inMask & URI_NORMALIZE_HOST) {
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* IPvFuture */
+ if (uri->owner) {
+ URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first,
+ uri->hostData.ipFuture.afterLast);
+ } else {
+ if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first),
+ &(uri->hostData.ipFuture.afterLast),
+ memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_HOST;
+ }
+ uri->hostText.first = uri->hostData.ipFuture.first;
+ uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
+ } else if ((uri->hostText.first != NULL) && (uri->hostData.ip4 == NULL)) {
+ /* Regname or IPv6 */
+ if (uri->owner) {
+ URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first,
+ &(uri->hostText.afterLast));
+ } else {
+ if (!URI_FUNC(FixPercentEncodingMalloc)(
+ &(uri->hostText.first), &(uri->hostText.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_HOST;
+ }
+
+ URI_FUNC(LowercaseInplaceExceptPercentEncoding)(uri->hostText.first,
+ uri->hostText.afterLast);
+ }
+ }
+ }
+
+ /* Port */
+ if (outMask != NULL) {
+ /* Is there a port even? */
+ if (uri->portText.first != NULL) {
+ /* Determine whether the port is already normalized, i.e. either "", "0" or no
+ * leading zeros */
+ const size_t portLen = uri->portText.afterLast - uri->portText.first;
+ if ((portLen > 1) && (uri->portText.first[0] == _UT('0'))) {
+ *outMask |= URI_NORMALIZE_PORT;
+ }
+ }
+ } else {
+ /* Normalize the port, i.e. drop leading zeros (except for string "0") */
+ if ((inMask & URI_NORMALIZE_PORT) && (uri->portText.first != NULL)) {
+ if (uri->owner) {
+ URI_FUNC(DropLeadingZerosInplace)((URI_CHAR *)uri->portText.first,
+ &(uri->portText.afterLast));
+ } else {
+ URI_FUNC(AdvancePastLeadingZeros)(&(uri->portText.first),
+ uri->portText.afterLast);
+ }
+ }
+ }
+
+ /* User info */
+ if (outMask != NULL) {
+ const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)(
+ uri->userInfo.first, uri->userInfo.afterLast);
+ if (normalizeUserInfo) {
+ *outMask |= URI_NORMALIZE_USER_INFO;
+ }
+ } else {
+ if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) {
+ if (uri->owner) {
+ URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first,
+ &(uri->userInfo.afterLast));
+ } else {
+ if (!URI_FUNC(FixPercentEncodingMalloc)(
+ &(uri->userInfo.first), &(uri->userInfo.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_USER_INFO;
+ }
+ }
+ }
+
+ /* Path */
+ if (outMask != NULL) {
+ const URI_TYPE(PathSegment) * walker = uri->pathHead;
+ while (walker != NULL) {
+ const URI_CHAR * const first = walker->text.first;
+ const URI_CHAR * const afterLast = walker->text.afterLast;
+ if ((first != NULL) && (afterLast != NULL) && (afterLast > first)
+ && ((((afterLast - first) == 1) && (first[0] == _UT('.')))
+ || (((afterLast - first) == 2) && (first[0] == _UT('.'))
+ && (first[1] == _UT('.')))
+ || URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast))) {
+ *outMask |= URI_NORMALIZE_PATH;
+ break;
+ }
+ walker = walker->next;
+ }
+ } else if (inMask & URI_NORMALIZE_PATH) {
+ URI_TYPE(PathSegment) * walker;
+ const UriBool relative =
+ ((uri->scheme.first == NULL) && !uri->absolutePath) ? URI_TRUE : URI_FALSE;
+
+ /* Fix percent-encoding for each segment */
+ walker = uri->pathHead;
+ if (uri->owner) {
+ while (walker != NULL) {
+ URI_FUNC(FixPercentEncodingInplace)(walker->text.first,
+ &(walker->text.afterLast));
+ walker = walker->next;
+ }
+ } else {
+ while (walker != NULL) {
+ if (!URI_FUNC(FixPercentEncodingMalloc)(
+ &(walker->text.first), &(walker->text.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ walker = walker->next;
+ }
+ revertMask |= URI_NORMALIZE_PATH;
+ }
+
+ /* 6.2.2.3 Path Segment Normalization */
+ if (!URI_FUNC(RemoveDotSegmentsEx)(
+ uri, relative,
+ (uri->owner == URI_TRUE) || ((revertMask & URI_NORMALIZE_PATH) != 0),
+ memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ URI_FUNC(FixEmptyTrailSegment)(uri, memory);
+ }
+
+ /* Query, fragment */
+ if (outMask != NULL) {
+ const UriBool normalizeQuery =
+ URI_FUNC(ContainsUglyPercentEncoding)(uri->query.first, uri->query.afterLast);
+ const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)(
+ uri->fragment.first, uri->fragment.afterLast);
+ if (normalizeQuery) {
+ *outMask |= URI_NORMALIZE_QUERY;
+ }
+
+ if (normalizeFragment) {
+ *outMask |= URI_NORMALIZE_FRAGMENT;
+ }
+ } else {
+ /* Query */
+ if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) {
+ if (uri->owner) {
+ URI_FUNC(FixPercentEncodingInplace)(uri->query.first,
+ &(uri->query.afterLast));
+ } else {
+ if (!URI_FUNC(FixPercentEncodingMalloc)(
+ &(uri->query.first), &(uri->query.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_QUERY;
+ }
+ }
+
+ /* Fragment */
+ if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) {
+ if (uri->owner) {
+ URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first,
+ &(uri->fragment.afterLast));
+ } else {
+ if (!URI_FUNC(FixPercentEncodingMalloc)(
+ &(uri->fragment.first), &(uri->fragment.afterLast), memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ revertMask |= URI_NORMALIZE_FRAGMENT;
+ }
+ }
+ }
+
+ /* Dup all not duped yet */
+ if ((outMask == NULL) && !uri->owner) {
+ if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
+ uri->owner = URI_TRUE;
+ }
+
+ return URI_SUCCESS;
+}
int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
- unsigned int doneMask = URI_NORMALIZED;
+ unsigned int revertMask = URI_NORMALIZED;
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
- if (uri == NULL) {
- return URI_ERROR_NULL;
- }
+ if (uri == NULL) {
+ return URI_ERROR_NULL;
+ }
- if (uri->owner == URI_TRUE) {
- return URI_SUCCESS;
- }
+ if (uri->owner == URI_TRUE) {
+ return URI_SUCCESS;
+ }
- if (! URI_FUNC(MakeOwnerEngine)(uri, &doneMask, memory)) {
- URI_FUNC(PreventLeakage)(uri, doneMask, memory);
- return URI_ERROR_MALLOC;
- }
+ if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
+ URI_FUNC(PreventLeakage)(uri, revertMask, memory);
+ return URI_ERROR_MALLOC;
+ }
- uri->owner = URI_TRUE;
+ uri->owner = URI_TRUE;
- return URI_SUCCESS;
+ return URI_SUCCESS;
}
-
-
int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri) {
- return URI_FUNC(MakeOwnerMm)(uri, NULL);
+ return URI_FUNC(MakeOwnerMm)(uri, NULL);
}
-
-
#endif
diff --git a/src/UriNormalize.h b/src/UriNormalize.h
new file mode 100644
index 0000000..41c87a3
--- /dev/null
+++ b/src/UriNormalize.h
@@ -0,0 +1,75 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2018, Weijia Song <songweijia@gmail.com>
+ * Copyright (C) 2018, Sebastian Pipping <sebastian@pipping.org>
+ * Copyright (C) 2025, Máté Kocsis <kocsismate@php.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if (defined(URI_PASS_ANSI) && !defined(URI_NORMALIZE_H_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_NORMALIZE_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* What encodings are enabled? */
+# include <uriparser/UriDefsConfig.h>
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriNormalize.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriNormalize.h"
+# undef URI_PASS_UNICODE
+# endif
+/* Only one pass for each encoding */
+# elif (defined(URI_PASS_ANSI) && !defined(URI_NORMALIZE_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_NORMALIZE_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_NORMALIZE_H_ANSI 1
+# include <uriparser/UriDefsAnsi.h>
+# else
+# define URI_NORMALIZE_H_UNICODE 1
+# include <uriparser/UriDefsUnicode.h>
+# endif
+
+void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, unsigned int revertMask,
+ UriMemoryManager * memory);
+
+# endif
+#endif
diff --git a/src/UriNormalizeBase.c b/src/UriNormalizeBase.c
index a74fcd3..9c2acee 100644
--- a/src/UriNormalizeBase.c
+++ b/src/UriNormalizeBase.c
@@ -38,82 +38,80 @@
*/
#ifndef URI_DOXYGEN
-# include "UriNormalizeBase.h"
+# include "UriNormalizeBase.h"
#endif
-
-
UriBool uriIsUnreserved(int code) {
- switch (code) {
- case L'a': /* ALPHA */
- case L'A':
- case L'b':
- case L'B':
- case L'c':
- case L'C':
- case L'd':
- case L'D':
- case L'e':
- case L'E':
- case L'f':
- case L'F':
- case L'g':
- case L'G':
- case L'h':
- case L'H':
- case L'i':
- case L'I':
- case L'j':
- case L'J':
- case L'k':
- case L'K':
- case L'l':
- case L'L':
- case L'm':
- case L'M':
- case L'n':
- case L'N':
- case L'o':
- case L'O':
- case L'p':
- case L'P':
- case L'q':
- case L'Q':
- case L'r':
- case L'R':
- case L's':
- case L'S':
- case L't':
- case L'T':
- case L'u':
- case L'U':
- case L'v':
- case L'V':
- case L'w':
- case L'W':
- case L'x':
- case L'X':
- case L'y':
- case L'Y':
- case L'z':
- case L'Z':
- case L'0': /* DIGIT */
- case L'1':
- case L'2':
- case L'3':
- case L'4':
- case L'5':
- case L'6':
- case L'7':
- case L'8':
- case L'9':
- case L'-': /* "-" / "." / "_" / "~" */
- case L'.':
- case L'_':
- case L'~':
- return URI_TRUE;
+ switch (code) {
+ case L'a': /* ALPHA */
+ case L'A':
+ case L'b':
+ case L'B':
+ case L'c':
+ case L'C':
+ case L'd':
+ case L'D':
+ case L'e':
+ case L'E':
+ case L'f':
+ case L'F':
+ case L'g':
+ case L'G':
+ case L'h':
+ case L'H':
+ case L'i':
+ case L'I':
+ case L'j':
+ case L'J':
+ case L'k':
+ case L'K':
+ case L'l':
+ case L'L':
+ case L'm':
+ case L'M':
+ case L'n':
+ case L'N':
+ case L'o':
+ case L'O':
+ case L'p':
+ case L'P':
+ case L'q':
+ case L'Q':
+ case L'r':
+ case L'R':
+ case L's':
+ case L'S':
+ case L't':
+ case L'T':
+ case L'u':
+ case L'U':
+ case L'v':
+ case L'V':
+ case L'w':
+ case L'W':
+ case L'x':
+ case L'X':
+ case L'y':
+ case L'Y':
+ case L'z':
+ case L'Z':
+ case L'0': /* DIGIT */
+ case L'1':
+ case L'2':
+ case L'3':
+ case L'4':
+ case L'5':
+ case L'6':
+ case L'7':
+ case L'8':
+ case L'9':
+ case L'-': /* "-" / "." / "_" / "~" */
+ case L'.':
+ case L'_':
+ case L'~':
+ return URI_TRUE;
- default:
- return URI_FALSE;
- }
+ default:
+ return URI_FALSE;
+ }
}
diff --git a/src/UriNormalizeBase.h b/src/UriNormalizeBase.h
index 8651c86..3ff4911 100644
--- a/src/UriNormalizeBase.h
+++ b/src/UriNormalizeBase.h
@@ -38,16 +38,10 @@
*/
#ifndef URI_NORMALIZE_BASE_H
-#define URI_NORMALIZE_BASE_H 1
-
-
-
-#include <uriparser/UriBase.h>
-
+# define URI_NORMALIZE_BASE_H 1
+# include <uriparser/UriBase.h>
UriBool uriIsUnreserved(int code);
-
-
#endif /* URI_NORMALIZE_BASE_H */
diff --git a/src/UriParse.c b/src/UriParse.c
index a672c8e..cada023 100644
--- a/src/UriParse.c
+++ b/src/UriParse.c
@@ -47,839 +47,757 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriParse.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriParse.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriParse.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriParse.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include <uriparser/UriIp4.h>
-# include "UriCommon.h"
-# include "UriMemory.h"
-# include "UriParseBase.h"
-#endif
-
-
-
-#define URI_SET_DIGIT \
- _UT('0'): \
- case _UT('1'): \
- case _UT('2'): \
- case _UT('3'): \
- case _UT('4'): \
- case _UT('5'): \
- case _UT('6'): \
- case _UT('7'): \
- case _UT('8'): \
- case _UT('9')
-
-#define URI_SET_HEX_LETTER_UPPER \
- _UT('A'): \
- case _UT('B'): \
- case _UT('C'): \
- case _UT('D'): \
- case _UT('E'): \
- case _UT('F')
-
-#define URI_SET_HEX_LETTER_LOWER \
- _UT('a'): \
- case _UT('b'): \
- case _UT('c'): \
- case _UT('d'): \
- case _UT('e'): \
- case _UT('f')
-
-#define URI_SET_HEXDIG \
- URI_SET_DIGIT: \
- case URI_SET_HEX_LETTER_UPPER: \
- case URI_SET_HEX_LETTER_LOWER
-
-#define URI_SET_ALPHA \
- URI_SET_HEX_LETTER_UPPER: \
- case URI_SET_HEX_LETTER_LOWER: \
- case _UT('g'): \
- case _UT('G'): \
- case _UT('h'): \
- case _UT('H'): \
- case _UT('i'): \
- case _UT('I'): \
- case _UT('j'): \
- case _UT('J'): \
- case _UT('k'): \
- case _UT('K'): \
- case _UT('l'): \
- case _UT('L'): \
- case _UT('m'): \
- case _UT('M'): \
- case _UT('n'): \
- case _UT('N'): \
- case _UT('o'): \
- case _UT('O'): \
- case _UT('p'): \
- case _UT('P'): \
- case _UT('q'): \
- case _UT('Q'): \
- case _UT('r'): \
- case _UT('R'): \
- case _UT('s'): \
- case _UT('S'): \
- case _UT('t'): \
- case _UT('T'): \
- case _UT('u'): \
- case _UT('U'): \
- case _UT('v'): \
- case _UT('V'): \
- case _UT('w'): \
- case _UT('W'): \
- case _UT('x'): \
- case _UT('X'): \
- case _UT('y'): \
- case _UT('Y'): \
- case _UT('z'): \
- case _UT('Z')
-
-
-
-static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast, UriMemoryManager * memory);
-
-static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory);
-static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory);
-static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory);
-static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory);
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include <uriparser/UriIp4.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriParseBase.h"
+# include "UriSets.h"
+# endif
+
+static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first,
+ const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+static UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory);
+static UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory);
+static UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory);
+static UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory);
static void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state);
static void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState) * state);
static UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory);
-
-static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos, UriMemoryManager * memory);
-static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, UriMemoryManager * memory);
-
-static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory);
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+static void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state, const URI_CHAR * errorPos,
+ UriMemoryManager * memory);
+static void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state,
+ UriMemoryManager * memory);
+static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory);
static URI_INLINE void URI_FUNC(StopSyntax)(URI_TYPE(ParserState) * state,
- const URI_CHAR * errorPos, UriMemoryManager * memory) {
- URI_FUNC(FreeUriMembersMm)(state->uri, memory);
- state->errorPos = errorPos;
- state->errorCode = URI_ERROR_SYNTAX;
+ const URI_CHAR * errorPos,
+ UriMemoryManager * memory) {
+ URI_FUNC(FreeUriMembersMm)(state->uri, memory);
+ state->errorPos = errorPos;
+ state->errorCode = URI_ERROR_SYNTAX;
}
-
-
-static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state, UriMemoryManager * memory) {
- URI_FUNC(FreeUriMembersMm)(state->uri, memory);
- state->errorPos = NULL;
- state->errorCode = URI_ERROR_MALLOC;
+static URI_INLINE void URI_FUNC(StopMalloc)(URI_TYPE(ParserState) * state,
+ UriMemoryManager * memory) {
+ URI_FUNC(FreeUriMembersMm)(state->uri, memory);
+ state->errorPos = NULL;
+ state->errorCode = URI_ERROR_MALLOC;
}
-
-
/*
* [authority]-><[>[ipLit2][authorityTwo]
* [authority]->[ownHostUserInfoNz]
* [authority]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- /* "" regname host */
- state->uri->hostText.first = URI_FUNC(SafeToPointTo);
- state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
- return afterLast;
- }
-
- switch (*first) {
- case _UT('['):
- {
- const URI_CHAR * const afterIpLit2
- = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory);
- if (afterIpLit2 == NULL) {
- return NULL;
- }
- state->uri->hostText.first = first + 1; /* HOST BEGIN */
- return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
- }
-
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- state->uri->userInfo.first = first; /* USERINFO BEGIN */
- return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory);
-
- default:
- /* "" regname host */
- state->uri->hostText.first = URI_FUNC(SafeToPointTo);
- state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
- return first;
- }
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ /* "" regname host */
+ state->uri->hostText.first = URI_FUNC(SafeToPointTo);
+ state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('['): {
+ const URI_CHAR * const afterIpLit2 =
+ URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory);
+ if (afterIpLit2 == NULL) {
+ return NULL;
+ }
+ state->uri->hostText.first = first + 1; /* HOST BEGIN */
+ return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
+ }
+
+ case URI_SET_PCHAR(_UT):
+ state->uri->userInfo.first = first; /* USERINFO BEGIN */
+ return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory);
+
+ default:
+ /* "" regname host */
+ state->uri->hostText.first = URI_FUNC(SafeToPointTo);
+ state->uri->hostText.afterLast = URI_FUNC(SafeToPointTo);
+ return first;
+ }
}
-
-
/*
* [authorityTwo]-><:>[port]
* [authorityTwo]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT(':'):
- {
- const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(state, first + 1, afterLast);
- if (afterPort == NULL) {
- return NULL;
- }
- state->uri->portText.first = first + 1; /* PORT BEGIN */
- state->uri->portText.afterLast = afterPort; /* PORT END */
- return afterPort;
- }
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT(':'): {
+ const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(first + 1, afterLast);
+ if (afterPort == NULL) {
+ return NULL;
+ }
+ state->uri->portText.first = first + 1; /* PORT BEGIN */
+ state->uri->portText.afterLast = afterPort; /* PORT END */
+ return afterPort;
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [hexZero]->[HEXDIG][hexZero]
* [hexZero]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case URI_SET_HEXDIG:
- return URI_FUNC(ParseHexZero)(state, first + 1, afterLast);
-
- default:
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_HEXDIG(_UT):
+ first += 1;
+ goto tail_call;
+
+ default:
+ return first;
+ }
}
-
-
/*
* [hierPart]->[pathRootless]
* [hierPart]-></>[partHelperTwo]
* [hierPart]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return URI_FUNC(ParsePathRootless)(state, first, afterLast, memory);
-
- case _UT('/'):
- return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory);
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_PCHAR(_UT):
+ return URI_FUNC(ParsePathRootless)(state, first, afterLast, memory);
+
+ case _UT('/'):
+ return URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory);
+
+ default:
+ return first;
+ }
}
-
-
/*
* [ipFutLoop]->[subDelims][ipFutStopGo]
* [ipFutLoop]->[unreserved][ipFutStopGo]
* [ipFutLoop]-><:>[ipFutStopGo]
- */
-static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return URI_FUNC(ParseIpFutStopGo)(state, first + 1, afterLast, memory);
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
-}
-
-
-
-/*
+ *
* [ipFutStopGo]->[ipFutLoop]
* [ipFutStopGo]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return URI_FUNC(ParseIpFutLoop)(state, first, afterLast, memory);
-
- default:
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ const URI_CHAR * const originalFirst = first;
+
+ while (first < afterLast) {
+ switch (*first) {
+ case _UT(':'):
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT):
+ first += 1;
+ break;
+
+ default:
+ goto done_looping;
+ break;
+ }
+ }
+
+done_looping:
+ if (first == originalFirst) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+
+ return first;
}
-
-
/*
* [ipFuture]-><v>[HEXDIG][hexZero]<.>[ipFutLoop]
*/
static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- /*
- First character has already been
- checked before entering this rule.
-
- switch (*first) {
- case _UT('v'):
- case _UT('V'):
- */
- if (first + 1 >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (first[1]) {
- case URI_SET_HEXDIG:
- {
- const URI_CHAR * afterIpFutLoop;
- const URI_CHAR * const afterHexZero
- = URI_FUNC(ParseHexZero)(state, first + 2, afterLast);
- if (afterHexZero == NULL) {
- return NULL;
- }
- if (afterHexZero >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
- if (*afterHexZero != _UT('.')) {
- URI_FUNC(StopSyntax)(state, afterHexZero, memory);
- return NULL;
- }
- state->uri->hostText.first = first; /* HOST BEGIN */
- state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */
- afterIpFutLoop = URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast, memory);
- if (afterIpFutLoop == NULL) {
- return NULL;
- }
- state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */
- state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */
- return afterIpFutLoop;
- }
-
- default:
- URI_FUNC(StopSyntax)(state, first + 1, memory);
- return NULL;
- }
-
- /*
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- */
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ /*
+ First character has already been
+ checked before entering this rule.
+
+ switch (*first) {
+ case _UT('v'):
+ case _UT('V'):
+ */
+ if (afterLast - first < 2) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT): {
+ const URI_CHAR * afterIpFutLoop;
+ const URI_CHAR * const afterHexZero =
+ URI_FUNC(ParseHexZero)(first + 2, afterLast);
+ if (afterHexZero == NULL) {
+ return NULL;
+ }
+ if (afterHexZero >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+ if (*afterHexZero != _UT('.')) {
+ URI_FUNC(StopSyntax)(state, afterHexZero, memory);
+ return NULL;
+ }
+ state->uri->hostText.first = first; /* HOST BEGIN */
+ state->uri->hostData.ipFuture.first = first; /* IPFUTURE BEGIN */
+ afterIpFutLoop =
+ URI_FUNC(ParseIpFutLoop)(state, afterHexZero + 1, afterLast, memory);
+ if (afterIpFutLoop == NULL) {
+ return NULL;
+ }
+ state->uri->hostText.afterLast = afterIpFutLoop; /* HOST END */
+ state->uri->hostData.ipFuture.afterLast = afterIpFutLoop; /* IPFUTURE END */
+ return afterIpFutLoop;
+ }
+
+ default:
+ URI_FUNC(StopSyntax)(state, first + 1, memory);
+ return NULL;
+ }
+
+ /*
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ */
}
-
-
/*
* [ipLit2]->[ipFuture]<]>
* [ipLit2]->[IPv6address2]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- /* The leading "v" of IPvFuture is case-insensitive. */
- case _UT('v'):
- case _UT('V'):
- {
- const URI_CHAR * const afterIpFuture
- = URI_FUNC(ParseIpFuture)(state, first, afterLast, memory);
- if (afterIpFuture == NULL) {
- return NULL;
- }
- if (afterIpFuture >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
- if (*afterIpFuture != _UT(']')) {
- URI_FUNC(StopSyntax)(state, afterIpFuture, memory);
- return NULL;
- }
- return afterIpFuture + 1;
- }
-
- case _UT(':'):
- case _UT(']'):
- case URI_SET_HEXDIG:
- state->uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6)); /* Freed when stopping on parse error */
- if (state->uri->hostData.ip6 == NULL) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParseIPv6address2)(state, first, afterLast, memory);
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (*first) {
+ /* The leading "v" of IPvFuture is case-insensitive. */
+ case _UT('v'):
+ case _UT('V'): {
+ const URI_CHAR * const afterIpFuture =
+ URI_FUNC(ParseIpFuture)(state, first, afterLast, memory);
+ if (afterIpFuture == NULL) {
+ return NULL;
+ }
+ if (afterIpFuture >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+ if (*afterIpFuture != _UT(']')) {
+ URI_FUNC(StopSyntax)(state, afterIpFuture, memory);
+ return NULL;
+ }
+ return afterIpFuture + 1;
+ }
+
+ case _UT(':'):
+ case _UT(']'):
+ case URI_SET_HEXDIG(_UT):
+ state->uri->hostData.ip6 = memory->malloc(
+ memory, 1 * sizeof(UriIp6)); /* Freed when stopping on parse error */
+ if (state->uri->hostData.ip6 == NULL) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return URI_FUNC(ParseIPv6address2)(state, first, afterLast, memory);
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
}
-
-
/*
* [IPv6address2]->..<]>
*/
-static const URI_CHAR * URI_FUNC(ParseIPv6address2)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- int zipperEver = 0;
- int quadsDone = 0;
- int digitCount = 0;
- unsigned char digitHistory[4];
- int ip4OctetsDone = 0;
-
- unsigned char quadsAfterZipper[14];
- int quadsAfterZipperCount = 0;
-
-
- for (;;) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- /* Inside IPv4 part? */
- if (ip4OctetsDone > 0) {
- /* Eat rest of IPv4 address */
- for (;;) {
- switch (*first) {
- case URI_SET_DIGIT:
- if (digitCount == 4) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9'));
- break;
-
- case _UT('.'):
- if ((ip4OctetsDone == 4) /* NOTE! */
- || (digitCount == 0)
- || (digitCount == 4)) {
- /* Invalid digit or octet count */
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- } else if ((digitCount > 1)
- && (digitHistory[0] == 0)) {
- /* Leading zero */
- URI_FUNC(StopSyntax)(state, first - digitCount, memory);
- return NULL;
- } else if ((digitCount == 3)
- && (100 * digitHistory[0]
- + 10 * digitHistory[1]
- + digitHistory[2] > 255)) {
- /* Octet value too large */
- if (digitHistory[0] > 2) {
- URI_FUNC(StopSyntax)(state, first - 3, memory);
- } else if (digitHistory[1] > 5) {
- URI_FUNC(StopSyntax)(state, first - 2, memory);
- } else {
- URI_FUNC(StopSyntax)(state, first - 1, memory);
- }
- return NULL;
- }
-
- /* Copy IPv4 octet */
- state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] = uriGetOctetValue(digitHistory, digitCount);
- digitCount = 0;
- ip4OctetsDone++;
- break;
-
- case _UT(']'):
- if ((ip4OctetsDone != 3) /* NOTE! */
- || (digitCount == 0)
- || (digitCount == 4)) {
- /* Invalid digit or octet count */
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- } else if ((digitCount > 1)
- && (digitHistory[0] == 0)) {
- /* Leading zero */
- URI_FUNC(StopSyntax)(state, first - digitCount, memory);
- return NULL;
- } else if ((digitCount == 3)
- && (100 * digitHistory[0]
- + 10 * digitHistory[1]
- + digitHistory[2] > 255)) {
- /* Octet value too large */
- if (digitHistory[0] > 2) {
- URI_FUNC(StopSyntax)(state, first - 3, memory);
- } else if (digitHistory[1] > 5) {
- URI_FUNC(StopSyntax)(state, first - 2, memory);
- } else {
- URI_FUNC(StopSyntax)(state, first - 1, memory);
- }
- return NULL;
- }
-
- state->uri->hostText.afterLast = first; /* HOST END */
-
- /* Copy missing quads right before IPv4 */
- memcpy(state->uri->hostData.ip6->data + 16 - 4 - 2 * quadsAfterZipperCount,
- quadsAfterZipper, 2 * quadsAfterZipperCount);
-
- /* Copy last IPv4 octet */
- state->uri->hostData.ip6->data[16 - 4 + 3] = uriGetOctetValue(digitHistory, digitCount);
-
- return first + 1;
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- first++;
-
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
- }
- } else {
- /* Eat while no dot in sight */
- int letterAmong = 0;
- int walking = 1;
- do {
- switch (*first) {
- case URI_SET_HEX_LETTER_LOWER:
- letterAmong = 1;
- if (digitCount == 4) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f'));
- digitCount++;
- break;
-
- case URI_SET_HEX_LETTER_UPPER:
- letterAmong = 1;
- if (digitCount == 4) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F'));
- digitCount++;
- break;
-
- case URI_SET_DIGIT:
- if (digitCount == 4) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9'));
- digitCount++;
- break;
-
- case _UT(':'):
- {
- int setZipper = 0;
-
- if (digitCount > 0) {
- if (zipperEver) {
- uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount);
- quadsAfterZipperCount++;
- } else {
- uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone);
- }
- quadsDone++;
- digitCount = 0;
- }
- letterAmong = 0;
-
- /* Too many quads? */
- if (quadsDone >= 8 - zipperEver) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
-
- /* "::"? */
- if (first + 1 >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
- if (first[1] == _UT(':')) {
- const int resetOffset = 2 * (quadsDone + (digitCount > 0));
-
- first++;
- if (zipperEver) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL; /* "::.+::" */
- }
-
- /* Zero everything after zipper */
- memset(state->uri->hostData.ip6->data + resetOffset, 0, 16 - resetOffset);
- setZipper = 1;
-
- /* ":::+"? */
- if (first + 1 >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL; /* No ']' yet */
- }
- if (first[1] == _UT(':')) {
- URI_FUNC(StopSyntax)(state, first + 1, memory);
- return NULL; /* ":::+ "*/
- }
- } else if (quadsDone == 0 || first[1] == _UT(']')) {
- /* Single leading or trailing ":" */
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
-
- if (setZipper) {
- zipperEver = 1;
- }
- }
- break;
-
- case _UT('.'):
- if ((quadsDone + zipperEver > 6) /* NOTE */
- || (!zipperEver && (quadsDone < 6))
- || letterAmong
- || (digitCount == 0)
- || (digitCount == 4)) {
- /* Invalid octet before */
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- } else if ((digitCount > 1)
- && (digitHistory[0] == 0)) {
- /* Leading zero */
- URI_FUNC(StopSyntax)(state, first - digitCount, memory);
- return NULL;
- } else if ((digitCount == 3)
- && (100 * digitHistory[0]
- + 10 * digitHistory[1]
- + digitHistory[2] > 255)) {
- /* Octet value too large */
- if (digitHistory[0] > 2) {
- URI_FUNC(StopSyntax)(state, first - 3, memory);
- } else if (digitHistory[1] > 5) {
- URI_FUNC(StopSyntax)(state, first - 2, memory);
- } else {
- URI_FUNC(StopSyntax)(state, first - 1, memory);
- }
- return NULL;
- }
-
- /* Copy first IPv4 octet */
- state->uri->hostData.ip6->data[16 - 4] = uriGetOctetValue(digitHistory, digitCount);
- digitCount = 0;
-
- /* Switch over to IPv4 loop */
- ip4OctetsDone = 1;
- walking = 0;
- break;
-
- case _UT(']'):
- /* Too little quads? */
- if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
-
- if (digitCount > 0) {
- if (zipperEver) {
- /* Too many quads? */
- if (quadsDone >= 7) {
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- uriWriteQuadToDoubleByte(digitHistory, digitCount, quadsAfterZipper + 2 * quadsAfterZipperCount);
- quadsAfterZipperCount++;
- } else {
- uriWriteQuadToDoubleByte(digitHistory, digitCount, state->uri->hostData.ip6->data + 2 * quadsDone);
- }
- /*
- quadsDone++;
- digitCount = 0;
- */
- }
-
- /* Copy missing quads to the end */
- memcpy(state->uri->hostData.ip6->data + 16 - 2 * quadsAfterZipperCount,
- quadsAfterZipper, 2 * quadsAfterZipperCount);
-
- state->uri->hostText.afterLast = first; /* HOST END */
- return first + 1; /* Fine */
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- first++;
-
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL; /* No ']' yet */
- }
- } while (walking);
- }
- }
+static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ int zipperEver = 0;
+ int quadsDone = 0;
+ int digitCount = 0;
+ unsigned char digitHistory[4];
+ int ip4OctetsDone = 0;
+
+ unsigned char quadsAfterZipper[14];
+ int quadsAfterZipperCount = 0;
+
+ for (;;) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ /* Inside IPv4 part? */
+ if (ip4OctetsDone > 0) {
+ /* Eat rest of IPv4 address */
+ for (;;) {
+ switch (*first) {
+ case URI_SET_DIGIT(_UT):
+ if (digitCount == 4) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ digitHistory[digitCount++] = (unsigned char)(9 + *first - _UT('9'));
+ break;
+
+ case _UT('.'):
+ if ((ip4OctetsDone == 4) /* NOTE! */
+ || (digitCount == 0) || (digitCount == 4)) {
+ /* Invalid digit or octet count */
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ } else if ((digitCount > 1) && (digitHistory[0] == 0)) {
+ /* Leading zero */
+ URI_FUNC(StopSyntax)(state, first - digitCount, memory);
+ return NULL;
+ } else if ((digitCount == 3)
+ && (100 * digitHistory[0] + 10 * digitHistory[1]
+ + digitHistory[2]
+ > 255)) {
+ /* Octet value too large */
+ if (digitHistory[0] > 2) {
+ URI_FUNC(StopSyntax)(state, first - 3, memory);
+ } else if (digitHistory[1] > 5) {
+ URI_FUNC(StopSyntax)(state, first - 2, memory);
+ } else {
+ URI_FUNC(StopSyntax)(state, first - 1, memory);
+ }
+ return NULL;
+ }
+
+ /* Copy IPv4 octet */
+ state->uri->hostData.ip6->data[16 - 4 + ip4OctetsDone] =
+ uriGetOctetValue(digitHistory, digitCount);
+ digitCount = 0;
+ ip4OctetsDone++;
+ break;
+
+ case _UT(']'):
+ if ((ip4OctetsDone != 3) /* NOTE! */
+ || (digitCount == 0) || (digitCount == 4)) {
+ /* Invalid digit or octet count */
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ } else if ((digitCount > 1) && (digitHistory[0] == 0)) {
+ /* Leading zero */
+ URI_FUNC(StopSyntax)(state, first - digitCount, memory);
+ return NULL;
+ } else if ((digitCount == 3)
+ && (100 * digitHistory[0] + 10 * digitHistory[1]
+ + digitHistory[2]
+ > 255)) {
+ /* Octet value too large */
+ if (digitHistory[0] > 2) {
+ URI_FUNC(StopSyntax)(state, first - 3, memory);
+ } else if (digitHistory[1] > 5) {
+ URI_FUNC(StopSyntax)(state, first - 2, memory);
+ } else {
+ URI_FUNC(StopSyntax)(state, first - 1, memory);
+ }
+ return NULL;
+ }
+
+ state->uri->hostText.afterLast = first; /* HOST END */
+
+ /* Copy missing quads right before IPv4 */
+ memcpy(state->uri->hostData.ip6->data + 16 - 4
+ - 2 * quadsAfterZipperCount,
+ quadsAfterZipper, 2 * quadsAfterZipperCount);
+
+ /* Copy last IPv4 octet */
+ state->uri->hostData.ip6->data[16 - 4 + 3] =
+ uriGetOctetValue(digitHistory, digitCount);
+
+ return first + 1;
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ first++;
+
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+ }
+ } else {
+ /* Eat while no dot in sight */
+ int letterAmong = 0;
+ int walking = 1;
+ do {
+ switch (*first) {
+ case URI_SET_HEX_LETTER_LOWER(_UT):
+ letterAmong = 1;
+ if (digitCount == 4) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('f'));
+ digitCount++;
+ break;
+
+ case URI_SET_HEX_LETTER_UPPER(_UT):
+ letterAmong = 1;
+ if (digitCount == 4) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ digitHistory[digitCount] = (unsigned char)(15 + *first - _UT('F'));
+ digitCount++;
+ break;
+
+ case URI_SET_DIGIT(_UT):
+ if (digitCount == 4) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ digitHistory[digitCount] = (unsigned char)(9 + *first - _UT('9'));
+ digitCount++;
+ break;
+
+ case _UT(':'): {
+ int setZipper = 0;
+
+ if (digitCount > 0) {
+ if (zipperEver) {
+ uriWriteQuadToDoubleByte(digitHistory, digitCount,
+ quadsAfterZipper
+ + 2 * quadsAfterZipperCount);
+ quadsAfterZipperCount++;
+ } else {
+ uriWriteQuadToDoubleByte(digitHistory, digitCount,
+ state->uri->hostData.ip6->data
+ + 2 * quadsDone);
+ }
+ quadsDone++;
+ digitCount = 0;
+ }
+ letterAmong = 0;
+
+ /* Too many quads? */
+ if (quadsDone >= 8 - zipperEver) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+
+ /* "::"? */
+ if (afterLast - first < 2) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+ if (first[1] == _UT(':')) {
+ const int resetOffset = 2 * (quadsDone + (digitCount > 0));
+
+ first++;
+ if (zipperEver) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL; /* "::.+::" */
+ }
+
+ /* Zero everything after zipper */
+ memset(state->uri->hostData.ip6->data + resetOffset, 0,
+ 16 - resetOffset);
+ setZipper = 1;
+
+ /* ":::+"? */
+ if (afterLast - first < 2) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL; /* No ']' yet */
+ }
+ if (first[1] == _UT(':')) {
+ URI_FUNC(StopSyntax)(state, first + 1, memory);
+ return NULL; /* ":::+ "*/
+ }
+ } else if (quadsDone == 0 || first[1] == _UT(']')) {
+ /* Single leading or trailing ":" */
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+
+ if (setZipper) {
+ zipperEver = 1;
+ }
+ } break;
+
+ case _UT('.'):
+ if ((quadsDone + zipperEver > 6) /* NOTE */
+ || (!zipperEver && (quadsDone < 6)) || letterAmong
+ || (digitCount == 0) || (digitCount == 4)) {
+ /* Invalid octet before */
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ } else if ((digitCount > 1) && (digitHistory[0] == 0)) {
+ /* Leading zero */
+ URI_FUNC(StopSyntax)(state, first - digitCount, memory);
+ return NULL;
+ } else if ((digitCount == 3)
+ && (100 * digitHistory[0] + 10 * digitHistory[1]
+ + digitHistory[2]
+ > 255)) {
+ /* Octet value too large */
+ if (digitHistory[0] > 2) {
+ URI_FUNC(StopSyntax)(state, first - 3, memory);
+ } else if (digitHistory[1] > 5) {
+ URI_FUNC(StopSyntax)(state, first - 2, memory);
+ } else {
+ URI_FUNC(StopSyntax)(state, first - 1, memory);
+ }
+ return NULL;
+ }
+
+ /* Copy first IPv4 octet */
+ state->uri->hostData.ip6->data[16 - 4] =
+ uriGetOctetValue(digitHistory, digitCount);
+ digitCount = 0;
+
+ /* Switch over to IPv4 loop */
+ ip4OctetsDone = 1;
+ walking = 0;
+ break;
+
+ case _UT(']'):
+ /* Too little quads? */
+ if (!zipperEver && !((quadsDone == 7) && (digitCount > 0))) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+
+ if (digitCount > 0) {
+ if (zipperEver) {
+ /* Too many quads? */
+ if (quadsDone >= 7) {
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ uriWriteQuadToDoubleByte(digitHistory, digitCount,
+ quadsAfterZipper
+ + 2 * quadsAfterZipperCount);
+ quadsAfterZipperCount++;
+ } else {
+ uriWriteQuadToDoubleByte(digitHistory, digitCount,
+ state->uri->hostData.ip6->data
+ + 2 * quadsDone);
+ }
+ /*
+ quadsDone++;
+ digitCount = 0;
+ */
+ }
+
+ /* Copy missing quads to the end */
+ memcpy(state->uri->hostData.ip6->data + 16
+ - 2 * quadsAfterZipperCount,
+ quadsAfterZipper, 2 * quadsAfterZipperCount);
+
+ state->uri->hostText.afterLast = first; /* HOST END */
+ return first + 1; /* Fine */
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ first++;
+
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL; /* No ']' yet */
+ }
+ } while (walking);
+ }
+ }
}
-
-
/*
* [mustBeSegmentNzNc]->[pctEncoded][mustBeSegmentNzNc]
* [mustBeSegmentNzNc]->[subDelims][mustBeSegmentNzNc]
@@ -888,346 +806,277 @@ static const URI_CHAR * URI_FUNC(ParseIPv6address2)(
* [mustBeSegmentNzNc]-></>[segment][zeroMoreSlashSegs][uriTail]
* [mustBeSegmentNzNc]-><@>[mustBeSegmentNzNc]
*/
-static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- state->uri->scheme.first = NULL; /* Not a scheme, reset */
- return afterLast;
- }
-
- switch (*first) {
- case _UT('%'):
- {
- const URI_CHAR * const afterPctEncoded
- = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
- if (afterPctEncoded == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory);
- }
-
- case _UT('@'):
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT(','):
- case _UT(';'):
- case _UT('\''):
- case _UT('+'):
- case _UT('='):
- case _UT('-'):
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory);
-
- case _UT('/'):
- {
- const URI_CHAR * afterZeroMoreSlashSegs;
- const URI_CHAR * afterSegment;
- if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- state->uri->scheme.first = NULL; /* Not a scheme, reset */
- afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
- if (afterSegment == NULL) {
- return NULL;
- }
- if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- afterZeroMoreSlashSegs
- = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory);
- if (afterZeroMoreSlashSegs == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory);
- }
-
- default:
- if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- state->uri->scheme.first = NULL; /* Not a scheme, reset */
- return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
- }
+static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ state->uri->scheme.first = NULL; /* Not a scheme, reset */
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('%'): {
+ const URI_CHAR * const afterPctEncoded =
+ URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+ if (afterPctEncoded == NULL) {
+ return NULL;
+ }
+ first = afterPctEncoded;
+ goto tail_call;
+ }
+
+ case _UT('@'):
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT):
+ first += 1;
+ goto tail_call;
+
+ case _UT('/'): {
+ const URI_CHAR * afterZeroMoreSlashSegs;
+ const URI_CHAR * afterSegment;
+ if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ state->uri->scheme.first = NULL; /* Not a scheme, reset */
+ afterSegment = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
+ if (afterSegment == NULL) {
+ return NULL;
+ }
+ if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ afterZeroMoreSlashSegs =
+ URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory);
+ if (afterZeroMoreSlashSegs == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory);
+ }
+
+ default:
+ if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ state->uri->scheme.first = NULL; /* Not a scheme, reset */
+ return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
+ }
}
-
-
/*
* [ownHost]-><[>[ipLit2][authorityTwo]
* [ownHost]->[ownHost2] // can take <NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- state->uri->hostText.afterLast = afterLast; /* HOST END */
- return afterLast;
- }
-
- switch (*first) {
- case _UT('['):
- {
- const URI_CHAR * const afterIpLit2
- = URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory);
- if (afterIpLit2 == NULL) {
- return NULL;
- }
- state->uri->hostText.first = first + 1; /* HOST BEGIN */
- return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
- }
-
- default:
- return URI_FUNC(ParseOwnHost2)(state, first, afterLast, memory);
- }
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ state->uri->hostText.afterLast = afterLast; /* HOST END */
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('['): {
+ const URI_CHAR * const afterIpLit2 =
+ URI_FUNC(ParseIpLit2)(state, first + 1, afterLast, memory);
+ if (afterIpLit2 == NULL) {
+ return NULL;
+ }
+ state->uri->hostText.first = first + 1; /* HOST BEGIN */
+ return URI_FUNC(ParseAuthorityTwo)(state, afterIpLit2, afterLast);
+ }
+
+ default:
+ return URI_FUNC(ParseOwnHost2)(state, first, afterLast, memory);
+ }
}
-
-
-static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- UriMemoryManager * memory) {
- state->uri->hostText.afterLast = first; /* HOST END */
-
- /* Valid IPv4 or just a regname? */
- state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
- if (state->uri->hostData.ip4 == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
- state->uri->hostText.first, state->uri->hostText.afterLast)) {
- /* Not IPv4 */
- memory->free(memory, state->uri->hostData.ip4);
- state->uri->hostData.ip4 = NULL;
- }
- return URI_TRUE; /* Success */
+static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory) {
+ state->uri->hostText.afterLast = first; /* HOST END */
+
+ /* Valid IPv4 or just a regname? */
+ state->uri->hostData.ip4 = memory->malloc(
+ memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+ if (state->uri->hostData.ip4 == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+ state->uri->hostText.first,
+ state->uri->hostText.afterLast)) {
+ /* Not IPv4 */
+ memory->free(memory, state->uri->hostData.ip4);
+ state->uri->hostData.ip4 = NULL;
+ }
+ return URI_TRUE; /* Success */
}
-
-
/*
* [ownHost2]->[authorityTwo] // can take <NULL>
* [ownHost2]->[pctSubUnres][ownHost2]
*/
-static const URI_CHAR * URI_FUNC(ParseOwnHost2)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(';'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterPctSubUnres
- = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
- if (afterPctSubUnres == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseOwnHost2)(state, afterPctSubUnres, afterLast, memory);
- }
-
- default:
- if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast);
- }
+static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('%'):
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT): {
+ const URI_CHAR * const afterPctSubUnres =
+ URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
+ if (afterPctSubUnres == NULL) {
+ return NULL;
+ }
+ first = afterPctSubUnres;
+ goto tail_call;
+ }
+
+ default:
+ if (!URI_FUNC(OnExitOwnHost2)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return URI_FUNC(ParseAuthorityTwo)(state, first, afterLast);
+ }
}
-
-
-static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- UriMemoryManager * memory) {
- state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */
- state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
- state->uri->hostText.afterLast = first; /* HOST END */
-
- /* Valid IPv4 or just a regname? */
- state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
- if (state->uri->hostData.ip4 == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
- state->uri->hostText.first, state->uri->hostText.afterLast)) {
- /* Not IPv4 */
- memory->free(memory, state->uri->hostData.ip4);
- state->uri->hostData.ip4 = NULL;
- }
- return URI_TRUE; /* Success */
+static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory) {
+ state->uri->hostText.first =
+ state->uri->userInfo.first; /* Host instead of userInfo, update */
+ state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
+ state->uri->hostText.afterLast = first; /* HOST END */
+
+ /* Valid IPv4 or just a regname? */
+ state->uri->hostData.ip4 = memory->malloc(
+ memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+ if (state->uri->hostData.ip4 == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+ state->uri->hostText.first,
+ state->uri->hostText.afterLast)) {
+ /* Not IPv4 */
+ memory->free(memory, state->uri->hostData.ip4);
+ state->uri->hostData.ip4 = NULL;
+ }
+ return URI_TRUE; /* Success */
}
-
-
-/*
- * [ownHostUserInfo]->[ownHostUserInfoNz]
- * [ownHostUserInfo]-><NULL>
- */
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast, memory);
-
- default:
- if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return first;
- }
-}
-
-
-
/*
* [ownHostUserInfoNz]->[pctSubUnres][ownHostUserInfo]
* [ownHostUserInfoNz]-><:>[ownPortUserInfo]
* [ownHostUserInfoNz]-><@>[ownHost]
+ *
+ * [ownHostUserInfo]->[ownHostUserInfoNz]
+ * [ownHostUserInfo]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(';'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterPctSubUnres
- = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
- if (afterPctSubUnres == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseOwnHostUserInfo)(state, afterPctSubUnres, afterLast, memory);
- }
-
- case _UT(':'):
- state->uri->hostText.afterLast = first; /* HOST END */
- state->uri->portText.first = first + 1; /* PORT BEGIN */
- return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory);
-
- case _UT('@'):
- state->uri->userInfo.afterLast = first; /* USERINFO END */
- state->uri->hostText.first = first + 1; /* HOST BEGIN */
- return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
+static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ const URI_CHAR * const originalFirst = first;
+
+ while (first < afterLast) {
+ switch (*first) {
+ case _UT('%'):
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT): {
+ const URI_CHAR * const afterPctSubUnres =
+ URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
+ if (afterPctSubUnres == NULL) {
+ return NULL;
+ }
+ first = afterPctSubUnres;
+ break;
+ }
+
+ default:
+ goto done_looping;
+ break;
+ }
+ }
+
+done_looping:
+ if (first < afterLast) {
+ switch (*first) {
+ case _UT(':'):
+ state->uri->hostText.afterLast = first; /* HOST END */
+ state->uri->portText.first = first + 1; /* PORT BEGIN */
+ return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory);
+
+ case _UT('@'):
+ state->uri->userInfo.afterLast = first; /* USERINFO END */
+ state->uri->hostText.first = first + 1; /* HOST BEGIN */
+ return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
+
+ default:
+ break;
+ }
+ }
+
+ if (first == originalFirst) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+
+ return first;
}
-
-
-static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- UriMemoryManager * memory) {
- state->uri->hostText.first = state->uri->userInfo.first; /* Host instead of userInfo, update */
- state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
- state->uri->portText.afterLast = first; /* PORT END */
-
- /* Valid IPv4 or just a regname? */
- state->uri->hostData.ip4 = memory->malloc(memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
- if (state->uri->hostData.ip4 == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
- state->uri->hostText.first, state->uri->hostText.afterLast)) {
- /* Not IPv4 */
- memory->free(memory, state->uri->hostData.ip4);
- state->uri->hostData.ip4 = NULL;
- }
- return URI_TRUE; /* Success */
+static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ UriMemoryManager * memory) {
+ state->uri->hostText.first =
+ state->uri->userInfo.first; /* Host instead of userInfo, update */
+ state->uri->userInfo.first = NULL; /* Not a userInfo, reset */
+ state->uri->portText.afterLast = first; /* PORT END */
+
+ /* Valid IPv4 or just a regname? */
+ state->uri->hostData.ip4 = memory->malloc(
+ memory, 1 * sizeof(UriIp4)); /* Freed when stopping on parse error */
+ if (state->uri->hostData.ip4 == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ if (URI_FUNC(ParseIpFourAddress)(state->uri->hostData.ip4->data,
+ state->uri->hostText.first,
+ state->uri->hostText.afterLast)) {
+ /* Not IPv4 */
+ memory->free(memory, state->uri->hostData.ip4);
+ state->uri->hostData.ip4 = NULL;
+ }
+ return URI_TRUE; /* Success */
}
-
-
/*
* [ownPortUserInfo]->[ALPHA][ownUserInfo]
* [ownPortUserInfo]->[DIGIT][ownPortUserInfo]
@@ -1241,281 +1090,229 @@ static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(
* [ownPortUserInfo]-><@>[ownHost]
* [ownPortUserInfo]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return afterLast;
- }
-
- switch (*first) {
- /* begin sub-delims */
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('\''):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT('+'):
- case _UT(','):
- case _UT(';'):
- case _UT('='):
- /* end sub-delims */
- /* begin unreserved (except alpha and digit) */
- case _UT('-'):
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- /* end unreserved (except alpha and digit) */
- case _UT(':'):
- case URI_SET_ALPHA:
- state->uri->hostText.afterLast = NULL; /* Not a host, reset */
- state->uri->portText.first = NULL; /* Not a port, reset */
- return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory);
-
- case URI_SET_DIGIT:
- return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast, memory);
-
- case _UT('%'):
- state->uri->portText.first = NULL; /* Not a port, reset */
- {
- const URI_CHAR * const afterPct
- = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
- if (afterPct == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseOwnUserInfo)(state, afterPct, afterLast, memory);
- }
-
- case _UT('@'):
- state->uri->hostText.afterLast = NULL; /* Not a host, reset */
- state->uri->portText.first = NULL; /* Not a port, reset */
- state->uri->userInfo.afterLast = first; /* USERINFO END */
- state->uri->hostText.first = first + 1; /* HOST BEGIN */
- return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
-
- default:
- if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_SUB_DELIMS(_UT):
+ /* begin unreserved (except alpha and digit) */
+ case _UT('-'):
+ case _UT('.'):
+ case _UT('_'):
+ case _UT('~'):
+ /* end unreserved (except alpha and digit) */
+ case _UT(':'):
+ case URI_SET_ALPHA(_UT):
+ state->uri->hostText.afterLast = NULL; /* Not a host, reset */
+ state->uri->portText.first = NULL; /* Not a port, reset */
+ return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory);
+
+ case URI_SET_DIGIT(_UT):
+ first += 1;
+ goto tail_call;
+
+ case _UT('%'):
+ state->uri->portText.first = NULL; /* Not a port, reset */
+ const URI_CHAR * const afterPct =
+ URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+ if (afterPct == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseOwnUserInfo)(state, afterPct, afterLast, memory);
+
+ case _UT('@'):
+ state->uri->hostText.afterLast = NULL; /* Not a host, reset */
+ state->uri->portText.first = NULL; /* Not a port, reset */
+ state->uri->userInfo.afterLast = first; /* USERINFO END */
+ state->uri->hostText.first = first + 1; /* HOST BEGIN */
+ return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
+
+ default:
+ if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return first;
+ }
}
-
-
/*
* [ownUserInfo]->[pctSubUnres][ownUserInfo]
* [ownUserInfo]-><:>[ownUserInfo]
* [ownUserInfo]-><@>[ownHost]
*/
-static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(';'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterPctSubUnres
- = URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
- if (afterPctSubUnres == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseOwnUserInfo)(state, afterPctSubUnres, afterLast, memory);
- }
-
- case _UT(':'):
- return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast, memory);
-
- case _UT('@'):
- /* SURE */
- state->uri->userInfo.afterLast = first; /* USERINFO END */
- state->uri->hostText.first = first + 1; /* HOST BEGIN */
- return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
+static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (*first) {
+ case _UT('%'):
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT): {
+ const URI_CHAR * const afterPctSubUnres =
+ URI_FUNC(ParsePctSubUnres)(state, first, afterLast, memory);
+ if (afterPctSubUnres == NULL) {
+ return NULL;
+ }
+ first = afterPctSubUnres;
+ goto tail_call;
+ }
+
+ case _UT(':'):
+ first += 1;
+ goto tail_call;
+
+ case _UT('@'):
+ /* SURE */
+ state->uri->userInfo.afterLast = first; /* USERINFO END */
+ state->uri->hostText.first = first + 1; /* HOST BEGIN */
+ return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast, memory);
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
}
-
-
static URI_INLINE void URI_FUNC(OnExitPartHelperTwo)(URI_TYPE(ParserState) * state) {
- state->uri->absolutePath = URI_TRUE;
+ state->uri->absolutePath = URI_TRUE;
}
-
-
/*
* [partHelperTwo]->[pathAbsNoLeadSlash] // can take <NULL>
* [partHelperTwo]-></>[authority][pathAbsEmpty]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(OnExitPartHelperTwo)(state);
- return afterLast;
- }
-
- switch (*first) {
- case _UT('/'):
- {
- const URI_CHAR * const afterAuthority
- = URI_FUNC(ParseAuthority)(state, first + 1, afterLast, memory);
- const URI_CHAR * afterPathAbsEmpty;
- if (afterAuthority == NULL) {
- return NULL;
- }
- afterPathAbsEmpty = URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast, memory);
-
- URI_FUNC(FixEmptyTrailSegment)(state->uri, memory);
-
- return afterPathAbsEmpty;
- }
-
- default:
- URI_FUNC(OnExitPartHelperTwo)(state);
- return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast, memory);
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(OnExitPartHelperTwo)(state);
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('/'): {
+ const URI_CHAR * const afterAuthority =
+ URI_FUNC(ParseAuthority)(state, first + 1, afterLast, memory);
+ const URI_CHAR * afterPathAbsEmpty;
+ if (afterAuthority == NULL) {
+ return NULL;
+ }
+ afterPathAbsEmpty =
+ URI_FUNC(ParsePathAbsEmpty)(state, afterAuthority, afterLast, memory);
+
+ URI_FUNC(FixEmptyTrailSegment)(state->uri, memory);
+
+ return afterPathAbsEmpty;
+ }
+
+ default:
+ URI_FUNC(OnExitPartHelperTwo)(state);
+ return URI_FUNC(ParsePathAbsNoLeadSlash)(state, first, afterLast, memory);
+ }
}
-
-
/*
* [pathAbsEmpty]-></>[segment][pathAbsEmpty]
* [pathAbsEmpty]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('/'):
- {
- const URI_CHAR * const afterSegment
- = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
- if (afterSegment == NULL) {
- return NULL;
- }
- if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParsePathAbsEmpty)(state, afterSegment, afterLast, memory);
- }
-
- default:
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('/'): {
+ const URI_CHAR * const afterSegment =
+ URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
+ if (afterSegment == NULL) {
+ return NULL;
+ }
+ if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ first = afterSegment;
+ goto tail_call;
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [pathAbsNoLeadSlash]->[segmentNz][zeroMoreSlashSegs]
* [pathAbsNoLeadSlash]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathAbsNoLeadSlash)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterSegmentNz
- = URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory);
- if (afterSegmentNz == NULL) {
- return NULL;
- }
- if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory);
- }
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParsePathAbsNoLeadSlash)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_PCHAR(_UT): {
+ const URI_CHAR * const afterSegmentNz =
+ URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory);
+ if (afterSegmentNz == NULL) {
+ return NULL;
+ }
+ if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory);
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [pathRootless]->[segmentNz][zeroMoreSlashSegs]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- const URI_CHAR * const afterSegmentNz
- = URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory);
- if (afterSegmentNz == NULL) {
- return NULL;
- } else {
- if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- }
- return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory);
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ const URI_CHAR * const afterSegmentNz =
+ URI_FUNC(ParseSegmentNz)(state, first, afterLast, memory);
+ if (afterSegmentNz == NULL) {
+ return NULL;
+ } else {
+ if (!URI_FUNC(PushPathSegment)(state, first, afterSegmentNz,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ }
+ return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegmentNz, afterLast, memory);
}
-
-
/*
* [pchar]->[pctEncoded]
* [pchar]->[subDelims]
@@ -1524,166 +1321,129 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParsePathRootless)(
* [pchar]-><@>
*/
static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- case _UT('%'):
- return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
-
- case _UT(':'):
- case _UT('@'):
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT(','):
- case _UT(';'):
- case _UT('\''):
- case _UT('+'):
- case _UT('='):
- case _UT('-'):
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return first + 1;
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (*first) {
+ case _UT('%'):
+ return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+
+ case URI_SET_PCHAR_WITHOUT_PERCENT(_UT):
+ return first + 1;
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
}
-
-
/*
* [pctEncoded]-><%>[HEXDIG][HEXDIG]
*/
-static const URI_CHAR * URI_FUNC(ParsePctEncoded)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- /*
- First character has already been
- checked before entering this rule.
-
- switch (*first) {
- case _UT('%'):
- */
- if (first + 1 >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (first[1]) {
- case URI_SET_HEXDIG:
- if (first + 2 >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (first[2]) {
- case URI_SET_HEXDIG:
- return first + 3;
-
- default:
- URI_FUNC(StopSyntax)(state, first + 2, memory);
- return NULL;
- }
-
- default:
- URI_FUNC(StopSyntax)(state, first + 1, memory);
- return NULL;
- }
-
- /*
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
- */
+static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ /*
+ First character has already been
+ checked before entering this rule.
+
+ switch (*first) {
+ case _UT('%'):
+ */
+ if (afterLast - first < 2) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ if (afterLast - first < 3) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ return first + 3;
+
+ default:
+ URI_FUNC(StopSyntax)(state, first + 2, memory);
+ return NULL;
+ }
+
+ default:
+ URI_FUNC(StopSyntax)(state, first + 1, memory);
+ return NULL;
+ }
+
+ /*
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
+ */
}
-
-
/*
* [pctSubUnres]->[pctEncoded]
* [pctSubUnres]->[subDelims]
* [pctSubUnres]->[unreserved]
*/
-static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- return NULL;
- }
-
- switch (*first) {
- case _UT('%'):
- return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
-
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT(','):
- case _UT(';'):
- case _UT('\''):
- case _UT('+'):
- case _UT('='):
- case _UT('-'):
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- return first + 1;
-
- default:
- URI_FUNC(StopSyntax)(state, first, memory);
- return NULL;
- }
+static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ return NULL;
+ }
+
+ switch (*first) {
+ case _UT('%'):
+ return URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+
+ case URI_SET_SUB_DELIMS(_UT):
+ case URI_SET_UNRESERVED(_UT):
+ return first + 1;
+
+ default:
+ URI_FUNC(StopSyntax)(state, first, memory);
+ return NULL;
+ }
}
-
-
/*
* [port]->[DIGIT][port]
* [port]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case URI_SET_DIGIT:
- return URI_FUNC(ParsePort)(state, first + 1, afterLast);
-
- default:
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_DIGIT(_UT):
+ first += 1;
+ goto tail_call;
+
+ default:
+ return first;
+ }
}
-
-
/*
* [queryFrag]->[pchar][queryFrag]
* [queryFrag]-></>[queryFrag]
@@ -1691,130 +1451,89 @@ static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const
* [queryFrag]-><NULL>
*/
static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterPchar
- = URI_FUNC(ParsePchar)(state, first, afterLast, memory);
- if (afterPchar == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseQueryFrag)(state, afterPchar, afterLast, memory);
- }
-
- case _UT('/'):
- case _UT('?'):
- return URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
-
- default:
- return first;
- }
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_PCHAR(_UT): {
+ const URI_CHAR * const afterPchar =
+ URI_FUNC(ParsePchar)(state, first, afterLast, memory);
+ if (afterPchar == NULL) {
+ return NULL;
+ }
+ first = afterPchar;
+ goto tail_call;
+ }
+
+ case _UT('/'):
+ case _UT('?'):
+ first += 1;
+ goto tail_call;
+
+ default:
+ return first;
+ }
}
-
-
/*
* [segment]->[pchar][segment]
* [segment]-><NULL>
*/
static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('!'):
- case _UT('$'):
- case _UT('%'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('-'):
- case _UT('*'):
- case _UT(','):
- case _UT('.'):
- case _UT(':'):
- case _UT(';'):
- case _UT('@'):
- case _UT('\''):
- case _UT('_'):
- case _UT('~'):
- case _UT('+'):
- case _UT('='):
- case URI_SET_DIGIT:
- case URI_SET_ALPHA:
- {
- const URI_CHAR * const afterPchar
- = URI_FUNC(ParsePchar)(state, first, afterLast, memory);
- if (afterPchar == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory);
- }
-
- default:
- return first;
- }
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_PCHAR(_UT): {
+ const URI_CHAR * const afterPchar =
+ URI_FUNC(ParsePchar)(state, first, afterLast, memory);
+ if (afterPchar == NULL) {
+ return NULL;
+ }
+ first = afterPchar;
+ goto tail_call;
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [segmentNz]->[pchar][segment]
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- const URI_CHAR * const afterPchar
- = URI_FUNC(ParsePchar)(state, first, afterLast, memory);
- if (afterPchar == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory);
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ const URI_CHAR * const afterPchar =
+ URI_FUNC(ParsePchar)(state, first, afterLast, memory);
+ if (afterPchar == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseSegment)(state, afterPchar, afterLast, memory);
}
-
-
static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- UriMemoryManager * memory) {
- if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */
- return URI_FALSE; /* Raises malloc error*/
- }
- state->uri->scheme.first = NULL; /* Not a scheme, reset */
- return URI_TRUE; /* Success */
+ URI_TYPE(ParserState) * state, const URI_CHAR * first, UriMemoryManager * memory) {
+ if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first,
+ memory)) { /* SEGMENT BOTH */
+ return URI_FALSE; /* Raises malloc error*/
+ }
+ state->uri->scheme.first = NULL; /* Not a scheme, reset */
+ return URI_TRUE; /* Success */
}
-
-
/*
* [segmentNzNcOrScheme2]->[ALPHA][segmentNzNcOrScheme2]
* [segmentNzNcOrScheme2]->[DIGIT][segmentNzNcOrScheme2]
@@ -1839,97 +1558,98 @@ static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(
* [segmentNzNcOrScheme2]-><'>[mustBeSegmentNzNc]
* [segmentNzNcOrScheme2]-><->[segmentNzNcOrScheme2]
*/
-static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return afterLast;
- }
-
- switch (*first) {
- case _UT('.'):
- case _UT('+'):
- case _UT('-'):
- case URI_SET_ALPHA:
- case URI_SET_DIGIT:
- return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory);
-
- case _UT('%'):
- {
- const URI_CHAR * const afterPctEncoded
- = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
- if (afterPctEncoded == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory);
- }
-
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT(','):
- case _UT(';'):
- case _UT('@'):
- case _UT('_'):
- case _UT('~'):
- case _UT('='):
- case _UT('\''):
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory);
-
- case _UT('/'):
- {
- const URI_CHAR * afterZeroMoreSlashSegs;
- const URI_CHAR * const afterSegment
- = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
- if (afterSegment == NULL) {
- return NULL;
- }
- if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- state->uri->scheme.first = NULL; /* Not a scheme, reset */
- if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- afterZeroMoreSlashSegs
- = URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory);
- if (afterZeroMoreSlashSegs == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory);
- }
-
- case _UT(':'):
- {
- const URI_CHAR * const afterHierPart
- = URI_FUNC(ParseHierPart)(state, first + 1, afterLast, memory);
- state->uri->scheme.afterLast = first; /* SCHEME END */
- if (afterHierPart == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast, memory);
- }
-
- default:
- if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) {
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
- }
+static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('.'):
+ case _UT('+'):
+ case _UT('-'):
+ case URI_SET_ALPHA(_UT):
+ case URI_SET_DIGIT(_UT):
+ first += 1;
+ goto tail_call;
+
+ case _UT('%'): {
+ const URI_CHAR * const afterPctEncoded =
+ URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+ if (afterPctEncoded == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast,
+ memory);
+ }
+
+ case _UT('!'):
+ case _UT('$'):
+ case _UT('&'):
+ case _UT('('):
+ case _UT(')'):
+ case _UT('*'):
+ case _UT(','):
+ case _UT(';'):
+ case _UT('@'):
+ case _UT('_'):
+ case _UT('~'):
+ case _UT('='):
+ case _UT('\''):
+ return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory);
+
+ case _UT('/'): {
+ const URI_CHAR * afterZeroMoreSlashSegs;
+ const URI_CHAR * const afterSegment =
+ URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
+ if (afterSegment == NULL) {
+ return NULL;
+ }
+ if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ state->uri->scheme.first = NULL; /* Not a scheme, reset */
+ if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ afterZeroMoreSlashSegs =
+ URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory);
+ if (afterZeroMoreSlashSegs == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseUriTail)(state, afterZeroMoreSlashSegs, afterLast, memory);
+ }
+
+ case _UT(':'): {
+ const URI_CHAR * const afterHierPart =
+ URI_FUNC(ParseHierPart)(state, first + 1, afterLast, memory);
+ state->uri->scheme.afterLast = first; /* SCHEME END */
+ if (afterHierPart == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseUriTail)(state, afterHierPart, afterLast, memory);
+ }
+
+ default:
+ if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first, memory)) {
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
+ }
}
-
-
/*
* [uriReference]->[ALPHA][segmentNzNcOrScheme2]
* [uriReference]->[DIGIT][mustBeSegmentNzNc]
@@ -1943,467 +1663,410 @@ static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(
* [uriReference]-><~>[mustBeSegmentNzNc]
* [uriReference]-><->[mustBeSegmentNzNc]
*/
-static const URI_CHAR * URI_FUNC(ParseUriReference)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case URI_SET_ALPHA:
- state->uri->scheme.first = first; /* SCHEME BEGIN */
- return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory);
-
- case URI_SET_DIGIT:
- case _UT('!'):
- case _UT('$'):
- case _UT('&'):
- case _UT('('):
- case _UT(')'):
- case _UT('*'):
- case _UT(','):
- case _UT(';'):
- case _UT('\''):
- case _UT('+'):
- case _UT('='):
- case _UT('.'):
- case _UT('_'):
- case _UT('~'):
- case _UT('-'):
- case _UT('@'):
- state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory);
-
- case _UT('%'):
- {
- const URI_CHAR * const afterPctEncoded
- = URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
- if (afterPctEncoded == NULL) {
- return NULL;
- }
- state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
- return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast, memory);
- }
-
- case _UT('/'):
- {
- const URI_CHAR * const afterPartHelperTwo
- = URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory);
- if (afterPartHelperTwo == NULL) {
- return NULL;
- }
- return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast, memory);
- }
-
- default:
- return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
- }
+static const URI_CHAR * URI_FUNC(ParseUriReference)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case URI_SET_ALPHA(_UT):
+ state->uri->scheme.first = first; /* SCHEME BEGIN */
+ return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast, memory);
+
+ case URI_SET_DIGIT(_UT):
+ case URI_SET_SUB_DELIMS(_UT):
+ case _UT('.'):
+ case _UT('_'):
+ case _UT('~'):
+ case _UT('-'):
+ case _UT('@'):
+ state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
+ return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast, memory);
+
+ case _UT('%'): {
+ const URI_CHAR * const afterPctEncoded =
+ URI_FUNC(ParsePctEncoded)(state, first, afterLast, memory);
+ if (afterPctEncoded == NULL) {
+ return NULL;
+ }
+ state->uri->scheme.first = first; /* SEGMENT BEGIN, ABUSE SCHEME POINTER */
+ return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast,
+ memory);
+ }
+
+ case _UT('/'): {
+ const URI_CHAR * const afterPartHelperTwo =
+ URI_FUNC(ParsePartHelperTwo)(state, first + 1, afterLast, memory);
+ if (afterPartHelperTwo == NULL) {
+ return NULL;
+ }
+ return URI_FUNC(ParseUriTail)(state, afterPartHelperTwo, afterLast, memory);
+ }
+
+ default:
+ return URI_FUNC(ParseUriTail)(state, first, afterLast, memory);
+ }
}
-
-
/*
* [uriTail]-><#>[queryFrag]
* [uriTail]-><?>[queryFrag][uriTailTwo]
* [uriTail]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('#'):
- {
- const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
- if (afterQueryFrag == NULL) {
- return NULL;
- }
- state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
- state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
- return afterQueryFrag;
- }
-
- case _UT('?'):
- {
- const URI_CHAR * const afterQueryFrag
- = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
- if (afterQueryFrag == NULL) {
- return NULL;
- }
- state->uri->query.first = first + 1; /* QUERY BEGIN */
- state->uri->query.afterLast = afterQueryFrag; /* QUERY END */
- return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast, memory);
- }
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTail)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('#'): {
+ const URI_CHAR * const afterQueryFrag =
+ URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
+ if (afterQueryFrag == NULL) {
+ return NULL;
+ }
+ state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
+ state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
+ return afterQueryFrag;
+ }
+
+ case _UT('?'): {
+ const URI_CHAR * const afterQueryFrag =
+ URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
+ if (afterQueryFrag == NULL) {
+ return NULL;
+ }
+ state->uri->query.first = first + 1; /* QUERY BEGIN */
+ state->uri->query.afterLast = afterQueryFrag; /* QUERY END */
+ return URI_FUNC(ParseUriTailTwo)(state, afterQueryFrag, afterLast, memory);
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [uriTailTwo]-><#>[queryFrag]
* [uriTailTwo]-><NULL>
*/
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTailTwo)(
- URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('#'):
- {
- const URI_CHAR * const afterQueryFrag = URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
- if (afterQueryFrag == NULL) {
- return NULL;
- }
- state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
- state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
- return afterQueryFrag;
- }
-
- default:
- return first;
- }
+static URI_INLINE const URI_CHAR *
+URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('#'): {
+ const URI_CHAR * const afterQueryFrag =
+ URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast, memory);
+ if (afterQueryFrag == NULL) {
+ return NULL;
+ }
+ state->uri->fragment.first = first + 1; /* FRAGMENT BEGIN */
+ state->uri->fragment.afterLast = afterQueryFrag; /* FRAGMENT END */
+ return afterQueryFrag;
+ }
+
+ default:
+ return first;
+ }
}
-
-
/*
* [zeroMoreSlashSegs]-></>[segment][zeroMoreSlashSegs]
* [zeroMoreSlashSegs]-><NULL>
*/
-static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- if (first >= afterLast) {
- return afterLast;
- }
-
- switch (*first) {
- case _UT('/'):
- {
- const URI_CHAR * const afterSegment
- = URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
- if (afterSegment == NULL) {
- return NULL;
- }
- if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment, memory)) { /* SEGMENT BOTH */
- URI_FUNC(StopMalloc)(state, memory);
- return NULL;
- }
- return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast, memory);
- }
-
- default:
- return first;
- }
+static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+tail_call:
+ if (first >= afterLast) {
+ return afterLast;
+ }
+
+ switch (*first) {
+ case _UT('/'): {
+ const URI_CHAR * const afterSegment =
+ URI_FUNC(ParseSegment)(state, first + 1, afterLast, memory);
+ if (afterSegment == NULL) {
+ return NULL;
+ }
+ if (!URI_FUNC(PushPathSegment)(state, first + 1, afterSegment,
+ memory)) { /* SEGMENT BOTH */
+ URI_FUNC(StopMalloc)(state, memory);
+ return NULL;
+ }
+ first = afterSegment;
+ goto tail_call;
+ }
+
+ default:
+ return first;
+ }
}
-
-
-static URI_INLINE void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState) * state) {
- URI_TYPE(Uri) * const uriBackup = state->uri;
- memset(state, 0, sizeof(URI_TYPE(ParserState)));
- state->uri = uriBackup;
+static URI_INLINE void URI_FUNC(ResetParserStateExceptUri)(URI_TYPE(ParserState)
+ * state) {
+ URI_TYPE(Uri) * const uriBackup = state->uri;
+ memset(state, 0, sizeof(URI_TYPE(ParserState)));
+ state->uri = uriBackup;
}
-
-
-static URI_INLINE UriBool URI_FUNC(PushPathSegment)(
- URI_TYPE(ParserState) * state, const URI_CHAR * first,
- const URI_CHAR * afterLast, UriMemoryManager * memory) {
- URI_TYPE(PathSegment) * segment = memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment)));
- if (segment == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- if (first == afterLast) {
- segment->text.first = URI_FUNC(SafeToPointTo);
- segment->text.afterLast = URI_FUNC(SafeToPointTo);
- } else {
- segment->text.first = first;
- segment->text.afterLast = afterLast;
- }
-
- /* First segment ever? */
- if (state->uri->pathHead == NULL) {
- /* First segment ever, set head and tail */
- state->uri->pathHead = segment;
- state->uri->pathTail = segment;
- } else {
- /* Append, update tail */
- state->uri->pathTail->next = segment;
- state->uri->pathTail = segment;
- }
-
- return URI_TRUE; /* Success */
+static URI_INLINE UriBool URI_FUNC(PushPathSegment)(URI_TYPE(ParserState) * state,
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ URI_TYPE(PathSegment) * segment =
+ memory->calloc(memory, 1, sizeof(URI_TYPE(PathSegment)));
+ if (segment == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ if (first == afterLast) {
+ segment->text.first = URI_FUNC(SafeToPointTo);
+ segment->text.afterLast = URI_FUNC(SafeToPointTo);
+ } else {
+ segment->text.first = first;
+ segment->text.afterLast = afterLast;
+ }
+
+ /* First segment ever? */
+ if (state->uri->pathHead == NULL) {
+ /* First segment ever, set head and tail */
+ state->uri->pathHead = segment;
+ state->uri->pathTail = segment;
+ } else {
+ /* Append, update tail */
+ state->uri->pathTail->next = segment;
+ state->uri->pathTail = segment;
+ }
+
+ return URI_TRUE; /* Success */
}
-
-
-int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- return URI_FUNC(ParseUriExMm)(state, first, afterLast, NULL);
+int URI_FUNC(ParseUriEx)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(ParseUriExMm)(state, first, afterLast, NULL);
}
-
-
-static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- const URI_CHAR * afterUriReference;
- URI_TYPE(Uri) * uri;
-
- /* Check params */
- if ((state == NULL) || (first == NULL) || (afterLast == NULL)) {
- return URI_ERROR_NULL;
- }
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- uri = state->uri;
-
- /* Init parser */
- URI_FUNC(ResetParserStateExceptUri)(state);
- URI_FUNC(ResetUri)(uri);
-
- /* Parse */
- afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast, memory);
- if (afterUriReference == NULL) {
- /* Waterproof errorPos <= afterLast */
- if (state->errorPos && (state->errorPos > afterLast)) {
- state->errorPos = afterLast;
- }
- return state->errorCode;
- }
- if (afterUriReference != afterLast) {
- if (afterUriReference < afterLast) {
- URI_FUNC(StopSyntax)(state, afterUriReference, memory);
- } else {
- URI_FUNC(StopSyntax)(state, afterLast, memory);
- }
- return state->errorCode;
- }
- return URI_SUCCESS;
+static int URI_FUNC(ParseUriExMm)(URI_TYPE(ParserState) * state, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ const URI_CHAR * afterUriReference;
+ URI_TYPE(Uri) * uri;
+
+ /* Check params */
+ if ((state == NULL) || (first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ uri = state->uri;
+
+ /* Init parser */
+ URI_FUNC(ResetParserStateExceptUri)(state);
+ URI_FUNC(ResetUri)(uri);
+
+ /* Parse */
+ afterUriReference = URI_FUNC(ParseUriReference)(state, first, afterLast, memory);
+ if (afterUriReference == NULL) {
+ /* Waterproof errorPos <= afterLast */
+ if (state->errorPos && (state->errorPos > afterLast)) {
+ state->errorPos = afterLast;
+ }
+ return state->errorCode;
+ }
+ if (afterUriReference != afterLast) {
+ if (afterUriReference < afterLast) {
+ URI_FUNC(StopSyntax)(state, afterUriReference, memory);
+ } else {
+ URI_FUNC(StopSyntax)(state, afterLast, memory);
+ }
+ return state->errorCode;
+ }
+ return URI_SUCCESS;
}
-
-
int URI_FUNC(ParseUri)(URI_TYPE(ParserState) * state, const URI_CHAR * text) {
- if ((state == NULL) || (text == NULL)) {
- return URI_ERROR_NULL;
- }
- return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text));
+ if ((state == NULL) || (text == NULL)) {
+ return URI_ERROR_NULL;
+ }
+ return URI_FUNC(ParseUriEx)(state, text, text + URI_STRLEN(text));
}
-
-
int URI_FUNC(ParseSingleUri)(URI_TYPE(Uri) * uri, const URI_CHAR * text,
- const URI_CHAR ** errorPos) {
- return URI_FUNC(ParseSingleUriEx)(uri, text, NULL, errorPos);
+ const URI_CHAR ** errorPos) {
+ return URI_FUNC(ParseSingleUriEx)(uri, text, NULL, errorPos);
}
-
-
-int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- const URI_CHAR ** errorPos) {
+int URI_FUNC(ParseSingleUriEx)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, const URI_CHAR ** errorPos) {
if ((afterLast == NULL) && (first != NULL)) {
- afterLast = first + URI_STRLEN(first);
- }
- return URI_FUNC(ParseSingleUriExMm)(uri, first, afterLast, errorPos, NULL);
+ afterLast = first + URI_STRLEN(first);
+ }
+ return URI_FUNC(ParseSingleUriExMm)(uri, first, afterLast, errorPos, NULL);
}
+int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, const URI_CHAR ** errorPos,
+ UriMemoryManager * memory) {
+ URI_TYPE(ParserState) state;
+ int res;
+ /* Check params */
+ if ((uri == NULL) || (first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-int URI_FUNC(ParseSingleUriExMm)(URI_TYPE(Uri) * uri,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- const URI_CHAR ** errorPos, UriMemoryManager * memory) {
- URI_TYPE(ParserState) state;
- int res;
-
- /* Check params */
- if ((uri == NULL) || (first == NULL) || (afterLast == NULL)) {
- return URI_ERROR_NULL;
- }
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- state.uri = uri;
+ state.uri = uri;
- res = URI_FUNC(ParseUriExMm)(&state, first, afterLast, memory);
+ res = URI_FUNC(ParseUriExMm)(&state, first, afterLast, memory);
- if (res != URI_SUCCESS) {
- if (errorPos != NULL) {
- *errorPos = state.errorPos;
- }
- URI_FUNC(FreeUriMembersMm)(uri, memory);
- }
+ if (res != URI_SUCCESS) {
+ if (errorPos != NULL) {
+ *errorPos = state.errorPos;
+ }
+ URI_FUNC(FreeUriMembersMm)(uri, memory);
+ }
- return res;
+ return res;
}
-
-
void URI_FUNC(FreeUriMembers)(URI_TYPE(Uri) * uri) {
- URI_FUNC(FreeUriMembersMm)(uri, NULL);
+ URI_FUNC(FreeUriMembersMm)(uri, NULL);
}
-
-
int URI_FUNC(FreeUriMembersMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
- if (uri == NULL) {
- return URI_ERROR_NULL;
- }
-
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- if (uri->owner) {
- /* Scheme */
- if (uri->scheme.first != NULL) {
- if (uri->scheme.first != uri->scheme.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->scheme.first);
- }
- uri->scheme.first = NULL;
- uri->scheme.afterLast = NULL;
- }
-
- /* User info */
- if (uri->userInfo.first != NULL) {
- if (uri->userInfo.first != uri->userInfo.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->userInfo.first);
- }
- uri->userInfo.first = NULL;
- uri->userInfo.afterLast = NULL;
- }
-
- /* Host data - IPvFuture (may affect host text) */
- if (uri->hostData.ipFuture.first != NULL) {
- /* NOTE: .hostData.ipFuture may hold the very same range pointers
- * as .hostText; then we need to prevent freeing memory twice. */
- if (uri->hostText.first == uri->hostData.ipFuture.first) {
- uri->hostText.first = NULL;
- uri->hostText.afterLast = NULL;
- }
-
- if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
- }
- uri->hostData.ipFuture.first = NULL;
- uri->hostData.ipFuture.afterLast = NULL;
- }
-
- /* Host text (after IPvFuture, see above) */
- if (uri->hostText.first != NULL) {
- if (uri->hostText.first != uri->hostText.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->hostText.first);
- }
- uri->hostText.first = NULL;
- uri->hostText.afterLast = NULL;
- }
- }
-
- /* Host data - IPv4 */
- if (uri->hostData.ip4 != NULL) {
- memory->free(memory, uri->hostData.ip4);
- uri->hostData.ip4 = NULL;
- }
-
- /* Host data - IPv6 */
- if (uri->hostData.ip6 != NULL) {
- memory->free(memory, uri->hostData.ip6);
- uri->hostData.ip6 = NULL;
- }
-
- /* Port text */
- if (uri->owner && (uri->portText.first != NULL)) {
- if (uri->portText.first != uri->portText.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->portText.first);
- }
- uri->portText.first = NULL;
- uri->portText.afterLast = NULL;
- }
-
- /* Path */
- if (uri->pathHead != NULL) {
- URI_TYPE(PathSegment) * segWalk = uri->pathHead;
- while (segWalk != NULL) {
- URI_TYPE(PathSegment) * const next = segWalk->next;
- if (uri->owner && (segWalk->text.first != NULL)
- && (segWalk->text.first < segWalk->text.afterLast)) {
- memory->free(memory, (URI_CHAR *)segWalk->text.first);
- }
- memory->free(memory, segWalk);
- segWalk = next;
- }
- uri->pathHead = NULL;
- uri->pathTail = NULL;
- }
-
- if (uri->owner) {
- /* Query */
- if (uri->query.first != NULL) {
- if (uri->query.first != uri->query.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->query.first);
- }
- uri->query.first = NULL;
- uri->query.afterLast = NULL;
- }
-
- /* Fragment */
- if (uri->fragment.first != NULL) {
- if (uri->fragment.first != uri->fragment.afterLast) {
- memory->free(memory, (URI_CHAR *)uri->fragment.first);
- }
- uri->fragment.first = NULL;
- uri->fragment.afterLast = NULL;
- }
- }
-
- return URI_SUCCESS;
+ if (uri == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if (uri->owner) {
+ /* Scheme */
+ if (uri->scheme.first != NULL) {
+ if (uri->scheme.first != uri->scheme.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->scheme.first);
+ }
+ uri->scheme.first = NULL;
+ uri->scheme.afterLast = NULL;
+ }
+
+ /* User info */
+ if (uri->userInfo.first != NULL) {
+ if (uri->userInfo.first != uri->userInfo.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->userInfo.first);
+ }
+ uri->userInfo.first = NULL;
+ uri->userInfo.afterLast = NULL;
+ }
+
+ /* Host data - IPvFuture (may affect host text) */
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* NOTE: .hostData.ipFuture holds the very same range pointers
+ * as .hostText; we must not free memory twice. */
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+
+ if (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
+ }
+ uri->hostData.ipFuture.first = NULL;
+ uri->hostData.ipFuture.afterLast = NULL;
+ }
+
+ /* Host text (after IPvFuture, see above) */
+ if (uri->hostText.first != NULL) {
+ if (uri->hostText.first != uri->hostText.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->hostText.first);
+ }
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+ }
+ }
+
+ /* Host data - IPv4 */
+ if (uri->hostData.ip4 != NULL) {
+ memory->free(memory, uri->hostData.ip4);
+ uri->hostData.ip4 = NULL;
+ }
+
+ /* Host data - IPv6 */
+ if (uri->hostData.ip6 != NULL) {
+ memory->free(memory, uri->hostData.ip6);
+ uri->hostData.ip6 = NULL;
+ }
+
+ /* Port text */
+ if (uri->owner && (uri->portText.first != NULL)) {
+ if (uri->portText.first != uri->portText.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->portText.first);
+ }
+ uri->portText.first = NULL;
+ uri->portText.afterLast = NULL;
+ }
+
+ /* Path */
+ URI_FUNC(FreeUriPath)(uri, memory);
+
+ if (uri->owner) {
+ /* Query */
+ if (uri->query.first != NULL) {
+ if (uri->query.first != uri->query.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->query.first);
+ }
+ uri->query.first = NULL;
+ uri->query.afterLast = NULL;
+ }
+
+ /* Fragment */
+ if (uri->fragment.first != NULL) {
+ if (uri->fragment.first != uri->fragment.afterLast) {
+ memory->free(memory, (URI_CHAR *)uri->fragment.first);
+ }
+ uri->fragment.first = NULL;
+ uri->fragment.afterLast = NULL;
+ }
+ }
+
+ return URI_SUCCESS;
}
-
-
UriBool URI_FUNC(_TESTING_ONLY_ParseIpSix)(const URI_CHAR * text) {
- UriMemoryManager * const memory = &defaultMemoryManager;
- URI_TYPE(Uri) uri;
- URI_TYPE(ParserState) parser;
- const URI_CHAR * const afterIpSix = text + URI_STRLEN(text);
- const URI_CHAR * res;
-
- URI_FUNC(ResetUri)(&uri);
- parser.uri = &uri;
- URI_FUNC(ResetParserStateExceptUri)(&parser);
- parser.uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6));
- res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix, memory);
- URI_FUNC(FreeUriMembersMm)(&uri, memory);
- return res == afterIpSix ? URI_TRUE : URI_FALSE;
+ UriMemoryManager * const memory = &defaultMemoryManager;
+ URI_TYPE(Uri) uri;
+ URI_TYPE(ParserState) parser;
+ const URI_CHAR * const afterIpSix = text + URI_STRLEN(text);
+ const URI_CHAR * res;
+
+ URI_FUNC(ResetUri)(&uri);
+ parser.uri = &uri;
+ URI_FUNC(ResetParserStateExceptUri)(&parser);
+ parser.uri->hostData.ip6 = memory->malloc(memory, 1 * sizeof(UriIp6));
+ res = URI_FUNC(ParseIPv6address2)(&parser, text, afterIpSix, memory);
+ URI_FUNC(FreeUriMembersMm)(&uri, memory);
+ return res == afterIpSix ? URI_TRUE : URI_FALSE;
}
-
-
UriBool URI_FUNC(_TESTING_ONLY_ParseIpFour)(const URI_CHAR * text) {
- unsigned char octets[4];
- int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text));
- return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE;
+ unsigned char octets[4];
+ int res = URI_FUNC(ParseIpFourAddress)(octets, text, text + URI_STRLEN(text));
+ return (res == URI_SUCCESS) ? URI_TRUE : URI_FALSE;
}
-
-
-#undef URI_SET_DIGIT
-#undef URI_SET_HEX_LETTER_UPPER
-#undef URI_SET_HEX_LETTER_LOWER
-#undef URI_SET_HEXDIG
-#undef URI_SET_ALPHA
-
-
+# undef URI_SET_DIGIT
+# undef URI_SET_HEX_LETTER_UPPER
+# undef URI_SET_HEX_LETTER_LOWER
+# undef URI_SET_HEXDIG
+# undef URI_SET_ALPHA
#endif
diff --git a/src/UriParseBase.c b/src/UriParseBase.c
index 3a4aa08..0ee66d4 100644
--- a/src/UriParseBase.c
+++ b/src/UriParseBase.c
@@ -38,53 +38,48 @@
*/
#ifndef URI_DOXYGEN
-# include "UriParseBase.h"
+# include "UriParseBase.h"
#endif
+void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount,
+ unsigned char * output) {
+ switch (digitCount) {
+ case 1:
+ /* 0x___? -> \x00 \x0? */
+ output[0] = 0;
+ output[1] = hexDigits[0];
+ break;
+ case 2:
+ /* 0x__?? -> \0xx \x?? */
+ output[0] = 0;
+ output[1] = 16 * hexDigits[0] + hexDigits[1];
+ break;
-void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount, unsigned char * output) {
- switch (digitCount) {
- case 1:
- /* 0x___? -> \x00 \x0? */
- output[0] = 0;
- output[1] = hexDigits[0];
- break;
+ case 3:
+ /* 0x_??? -> \0x? \x?? */
+ output[0] = hexDigits[0];
+ output[1] = 16 * hexDigits[1] + hexDigits[2];
+ break;
- case 2:
- /* 0x__?? -> \0xx \x?? */
- output[0] = 0;
- output[1] = 16 * hexDigits[0] + hexDigits[1];
- break;
-
- case 3:
- /* 0x_??? -> \0x? \x?? */
- output[0] = hexDigits[0];
- output[1] = 16 * hexDigits[1] + hexDigits[2];
- break;
-
- case 4:
- /* 0x???? -> \0?? \x?? */
- output[0] = 16 * hexDigits[0] + hexDigits[1];
- output[1] = 16 * hexDigits[2] + hexDigits[3];
- break;
-
- }
+ case 4:
+ /* 0x???? -> \0?? \x?? */
+ output[0] = 16 * hexDigits[0] + hexDigits[1];
+ output[1] = 16 * hexDigits[2] + hexDigits[3];
+ break;
+ }
}
-
-
unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount) {
- switch (digitCount) {
- case 1:
- return digits[0];
-
- case 2:
- return 10 * digits[0] + digits[1];
+ switch (digitCount) {
+ case 1:
+ return digits[0];
- case 3:
- default:
- return 100 * digits[0] + 10 * digits[1] + digits[2];
+ case 2:
+ return 10 * digits[0] + digits[1];
- }
+ case 3:
+ default:
+ return 100 * digits[0] + 10 * digits[1] + digits[2];
+ }
}
diff --git a/src/UriParseBase.h b/src/UriParseBase.h
index 6d7379d..cdb2c6f 100644
--- a/src/UriParseBase.h
+++ b/src/UriParseBase.h
@@ -38,18 +38,12 @@
*/
#ifndef URI_PARSE_BASE_H
-#define URI_PARSE_BASE_H 1
-
-
-
-#include <uriparser/UriBase.h>
-
+# define URI_PARSE_BASE_H 1
+# include <uriparser/UriBase.h>
void uriWriteQuadToDoubleByte(const unsigned char * hexDigits, int digitCount,
- unsigned char * output);
+ unsigned char * output);
unsigned char uriGetOctetValue(const unsigned char * digits, int digitCount);
-
-
#endif /* URI_PARSE_BASE_H */
diff --git a/src/UriQuery.c b/src/UriQuery.c
index bbc1548..801a237 100644
--- a/src/UriQuery.c
+++ b/src/UriQuery.c
@@ -41,465 +41,427 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriQuery.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriQuery.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriQuery.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriQuery.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-# include "UriMemory.h"
-#endif
-
-
-
-#include <limits.h>
-#include <stddef.h> /* size_t */
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# endif
+
+# include <limits.h>
+# include <stddef.h> /* size_t */
static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList,
- int maxChars, int * charsWritten, int * charsRequired,
- UriBool spaceToPlus, UriBool normalizeBreaks);
-
-static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
- int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
- const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
- UriBool plusToSpace, UriBreakConversion breakConversion,
- UriMemoryManager * memory);
-
+ const URI_TYPE(QueryList) * queryList,
+ int maxChars, int * charsWritten,
+ int * charsRequired, UriBool spaceToPlus,
+ UriBool normalizeBreaks);
+static UriBool URI_FUNC(AppendQueryItem)(
+ URI_TYPE(QueryList) * *prevNext, int * itemCount, const URI_CHAR * keyFirst,
+ const URI_CHAR * keyAfter, const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
+ UriBool plusToSpace, UriBreakConversion breakConversion, UriMemoryManager * memory);
int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
- int * charsRequired) {
- const UriBool spaceToPlus = URI_TRUE;
- const UriBool normalizeBreaks = URI_TRUE;
+ int * charsRequired) {
+ const UriBool spaceToPlus = URI_TRUE;
+ const UriBool normalizeBreaks = URI_TRUE;
- return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired,
- spaceToPlus, normalizeBreaks);
+ return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, spaceToPlus,
+ normalizeBreaks);
}
-
-
int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
- int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) {
- if ((queryList == NULL) || (charsRequired == NULL)) {
- return URI_ERROR_NULL;
- }
-
- return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL,
- charsRequired, spaceToPlus, normalizeBreaks);
+ int * charsRequired, UriBool spaceToPlus,
+ UriBool normalizeBreaks) {
+ if ((queryList == NULL) || (charsRequired == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, charsRequired,
+ spaceToPlus, normalizeBreaks);
}
+int URI_FUNC(ComposeQuery)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList,
+ int maxChars, int * charsWritten) {
+ const UriBool spaceToPlus = URI_TRUE;
+ const UriBool normalizeBreaks = URI_TRUE;
-
-int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) {
- const UriBool spaceToPlus = URI_TRUE;
- const UriBool normalizeBreaks = URI_TRUE;
-
- return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten,
- spaceToPlus, normalizeBreaks);
+ return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, spaceToPlus,
+ normalizeBreaks);
}
+int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList,
+ int maxChars, int * charsWritten, UriBool spaceToPlus,
+ UriBool normalizeBreaks) {
+ if ((dest == NULL) || (queryList == NULL)) {
+ return URI_ERROR_NULL;
+ }
+ if (maxChars < 1) {
+ return URI_ERROR_OUTPUT_TOO_LARGE;
+ }
-int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
- UriBool spaceToPlus, UriBool normalizeBreaks) {
- if ((dest == NULL) || (queryList == NULL)) {
- return URI_ERROR_NULL;
- }
-
- if (maxChars < 1) {
- return URI_ERROR_OUTPUT_TOO_LARGE;
- }
-
- return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars,
- charsWritten, NULL, spaceToPlus, normalizeBreaks);
+ return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, charsWritten, NULL,
+ spaceToPlus, normalizeBreaks);
}
-
-
int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList) {
- const UriBool spaceToPlus = URI_TRUE;
- const UriBool normalizeBreaks = URI_TRUE;
+ const URI_TYPE(QueryList) * queryList) {
+ const UriBool spaceToPlus = URI_TRUE;
+ const UriBool normalizeBreaks = URI_TRUE;
- return URI_FUNC(ComposeQueryMallocEx)(dest, queryList,
- spaceToPlus, normalizeBreaks);
+ return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, spaceToPlus, normalizeBreaks);
}
-
-
int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList,
- UriBool spaceToPlus, UriBool normalizeBreaks) {
- return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus,
- normalizeBreaks, NULL);
+ const URI_TYPE(QueryList) * queryList,
+ UriBool spaceToPlus, UriBool normalizeBreaks) {
+ return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus, normalizeBreaks,
+ NULL);
}
-
-
int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest,
- const URI_TYPE(QueryList) * queryList,
- UriBool spaceToPlus, UriBool normalizeBreaks,
- UriMemoryManager * memory) {
- int charsRequired;
- int res;
- URI_CHAR * queryString;
-
- if (dest == NULL) {
- return URI_ERROR_NULL;
- }
-
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- /* Calculate space */
- res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired,
- spaceToPlus, normalizeBreaks);
- if (res != URI_SUCCESS) {
- return res;
- }
- if (charsRequired == INT_MAX) {
- return URI_ERROR_MALLOC;
- }
- charsRequired++;
-
- /* Allocate space */
- queryString = memory->calloc(memory, charsRequired, sizeof(URI_CHAR));
- if (queryString == NULL) {
- return URI_ERROR_MALLOC;
- }
-
- /* Put query in */
- res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired,
- NULL, spaceToPlus, normalizeBreaks);
- if (res != URI_SUCCESS) {
- memory->free(memory, queryString);
- return res;
- }
-
- *dest = queryString;
- return URI_SUCCESS;
+ const URI_TYPE(QueryList) * queryList,
+ UriBool spaceToPlus, UriBool normalizeBreaks,
+ UriMemoryManager * memory) {
+ int charsRequired;
+ int res;
+ URI_CHAR * queryString;
+
+ if (dest == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* Calculate space */
+ res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, spaceToPlus,
+ normalizeBreaks);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ if (charsRequired == INT_MAX) {
+ return URI_ERROR_MALLOC;
+ }
+ charsRequired++;
+
+ /* Allocate space */
+ queryString = memory->calloc(memory, charsRequired, sizeof(URI_CHAR));
+ if (queryString == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ /* Put query in */
+ res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, NULL,
+ spaceToPlus, normalizeBreaks);
+ if (res != URI_SUCCESS) {
+ memory->free(memory, queryString);
+ return res;
+ }
+
+ *dest = queryString;
+ return URI_SUCCESS;
}
-
-
-int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
- const URI_TYPE(QueryList) * queryList,
- int maxChars, int * charsWritten, int * charsRequired,
- UriBool spaceToPlus, UriBool normalizeBreaks) {
- UriBool firstItem = URI_TRUE;
- int ampersandLen = 0; /* increased to 1 from second item on */
- URI_CHAR * write = dest;
-
- /* Subtract terminator */
- if (dest == NULL) {
- *charsRequired = 0;
- } else {
- maxChars--;
- }
-
- while (queryList != NULL) {
- const URI_CHAR * const key = queryList->key;
- const URI_CHAR * const value = queryList->value;
- const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3);
- const size_t keyLen = (key == NULL) ? 0 : URI_STRLEN(key);
- int keyRequiredChars;
- const size_t valueLen = (value == NULL) ? 0 : URI_STRLEN(value);
- int valueRequiredChars;
-
- if ((keyLen >= (size_t)INT_MAX / worstCase) || (valueLen >= (size_t)INT_MAX / worstCase)) {
- return URI_ERROR_OUTPUT_TOO_LARGE;
- }
- keyRequiredChars = worstCase * (int)keyLen;
- valueRequiredChars = worstCase * (int)valueLen;
-
- if (dest == NULL) {
- (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL)
- ? 0
- : 1 + valueRequiredChars);
-
- if (firstItem == URI_TRUE) {
- ampersandLen = 1;
- firstItem = URI_FALSE;
- }
- } else {
- if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) {
- return URI_ERROR_OUTPUT_TOO_LARGE;
- }
-
- /* Copy key */
- if (firstItem == URI_TRUE) {
- ampersandLen = 1;
- firstItem = URI_FALSE;
- } else {
- write[0] = _UT('&');
- write++;
- }
- write = URI_FUNC(EscapeEx)(key, key + keyLen,
- write, spaceToPlus, normalizeBreaks);
-
- if (value != NULL) {
- if ((write - dest) + 1 + valueRequiredChars > maxChars) {
- return URI_ERROR_OUTPUT_TOO_LARGE;
- }
-
- /* Copy value */
- write[0] = _UT('=');
- write++;
- write = URI_FUNC(EscapeEx)(value, value + valueLen,
- write, spaceToPlus, normalizeBreaks);
- }
- }
-
- queryList = queryList->next;
- }
-
- if (dest != NULL) {
- write[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = (int)(write - dest) + 1; /* .. for terminator */
- }
- }
-
- return URI_SUCCESS;
+int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * queryList,
+ int maxChars, int * charsWritten, int * charsRequired,
+ UriBool spaceToPlus, UriBool normalizeBreaks) {
+ UriBool firstItem = URI_TRUE;
+ int ampersandLen = 0; /* increased to 1 from second item on */
+ URI_CHAR * write = dest;
+
+ /* Subtract terminator */
+ if (dest == NULL) {
+ *charsRequired = 0;
+ } else {
+ maxChars--;
+ }
+
+ while (queryList != NULL) {
+ const URI_CHAR * const key = queryList->key;
+ const URI_CHAR * const value = queryList->value;
+ const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3);
+ const size_t keyLen = (key == NULL) ? 0 : URI_STRLEN(key);
+ int keyRequiredChars;
+ const size_t valueLen = (value == NULL) ? 0 : URI_STRLEN(value);
+ int valueRequiredChars;
+
+ if ((keyLen >= (size_t)INT_MAX / worstCase)
+ || (valueLen >= (size_t)INT_MAX / worstCase)) {
+ return URI_ERROR_OUTPUT_TOO_LARGE;
+ }
+ keyRequiredChars = worstCase * (int)keyLen;
+ valueRequiredChars = worstCase * (int)valueLen;
+
+ if (dest == NULL) {
+ (*charsRequired) += ampersandLen + keyRequiredChars
+ + ((value == NULL) ? 0 : 1 + valueRequiredChars);
+
+ if (firstItem == URI_TRUE) {
+ ampersandLen = 1;
+ firstItem = URI_FALSE;
+ }
+ } else {
+ if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) {
+ return URI_ERROR_OUTPUT_TOO_LARGE;
+ }
+
+ /* Copy key */
+ if (firstItem == URI_TRUE) {
+ ampersandLen = 1;
+ firstItem = URI_FALSE;
+ } else {
+ write[0] = _UT('&');
+ write++;
+ }
+ write = URI_FUNC(EscapeEx)(key, key + keyLen, write, spaceToPlus,
+ normalizeBreaks);
+
+ if (value != NULL) {
+ if ((write - dest) + 1 + valueRequiredChars > maxChars) {
+ return URI_ERROR_OUTPUT_TOO_LARGE;
+ }
+
+ /* Copy value */
+ write[0] = _UT('=');
+ write++;
+ write = URI_FUNC(EscapeEx)(value, value + valueLen, write, spaceToPlus,
+ normalizeBreaks);
+ }
+ }
+
+ queryList = queryList->next;
+ }
+
+ if (dest != NULL) {
+ write[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = (int)(write - dest) + 1; /* .. for terminator */
+ }
+ }
+
+ return URI_SUCCESS;
}
-
-
-UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
- int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
- const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
- UriBool plusToSpace, UriBreakConversion breakConversion,
- UriMemoryManager * memory) {
- const int keyLen = (int)(keyAfter - keyFirst);
- const int valueLen = (int)(valueAfter - valueFirst);
- URI_CHAR * key;
- URI_CHAR * value;
-
- if ((prevNext == NULL) || (itemCount == NULL)
- || (keyFirst == NULL) || (keyAfter == NULL)
- || (keyFirst > keyAfter) || (valueFirst > valueAfter)
- || ((keyFirst == keyAfter)
- && (valueFirst == NULL) && (valueAfter == NULL))) {
- return URI_TRUE;
- }
-
- /* Append new empty item */
- *prevNext = memory->malloc(memory, 1 * sizeof(URI_TYPE(QueryList)));
- if (*prevNext == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- (*prevNext)->next = NULL;
-
-
- /* Fill key */
- key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR));
- if (key == NULL) {
- memory->free(memory, *prevNext);
- *prevNext = NULL;
- return URI_FALSE; /* Raises malloc error */
- }
-
- key[keyLen] = _UT('\0');
- if (keyLen > 0) {
- /* Copy 1:1 */
- memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR));
-
- /* Unescape */
- URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion);
- }
- (*prevNext)->key = key;
-
-
- /* Fill value */
- if (valueFirst != NULL) {
- value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR));
- if (value == NULL) {
- memory->free(memory, key);
- memory->free(memory, *prevNext);
- *prevNext = NULL;
- return URI_FALSE; /* Raises malloc error */
- }
-
- value[valueLen] = _UT('\0');
- if (valueLen > 0) {
- /* Copy 1:1 */
- memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR));
-
- /* Unescape */
- URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion);
- }
- (*prevNext)->value = value;
- } else {
- value = NULL;
- }
- (*prevNext)->value = value;
-
- (*itemCount)++;
- return URI_TRUE;
+UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCount,
+ const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
+ const URI_CHAR * valueFirst,
+ const URI_CHAR * valueAfter, UriBool plusToSpace,
+ UriBreakConversion breakConversion,
+ UriMemoryManager * memory) {
+ const int keyLen = (int)(keyAfter - keyFirst);
+ const int valueLen = (int)(valueAfter - valueFirst);
+ URI_CHAR * key;
+ URI_CHAR * value;
+
+ if ((prevNext == NULL) || (itemCount == NULL) || (keyFirst == NULL)
+ || (keyAfter == NULL) || (keyFirst > keyAfter) || (valueFirst > valueAfter)
+ || ((keyFirst == keyAfter) && (valueFirst == NULL) && (valueAfter == NULL))) {
+ return URI_TRUE;
+ }
+
+ /* Append new empty item */
+ *prevNext = memory->malloc(memory, 1 * sizeof(URI_TYPE(QueryList)));
+ if (*prevNext == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ (*prevNext)->next = NULL;
+
+ /* Fill key */
+ key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR));
+ if (key == NULL) {
+ memory->free(memory, *prevNext);
+ *prevNext = NULL;
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ key[keyLen] = _UT('\0');
+ if (keyLen > 0) {
+ /* Copy 1:1 */
+ memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR));
+
+ /* Unescape */
+ URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion);
+ }
+ (*prevNext)->key = key;
+
+ /* Fill value */
+ if (valueFirst != NULL) {
+ value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR));
+ if (value == NULL) {
+ memory->free(memory, key);
+ memory->free(memory, *prevNext);
+ *prevNext = NULL;
+ return URI_FALSE; /* Raises malloc error */
+ }
+
+ value[valueLen] = _UT('\0');
+ if (valueLen > 0) {
+ /* Copy 1:1 */
+ memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR));
+
+ /* Unescape */
+ URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion);
+ }
+ (*prevNext)->value = value;
+ } else {
+ value = NULL;
+ }
+ (*prevNext)->value = value;
+
+ (*itemCount)++;
+ return URI_TRUE;
}
-
-
void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) {
- URI_FUNC(FreeQueryListMm)(queryList, NULL);
+ URI_FUNC(FreeQueryListMm)(queryList, NULL);
}
-
-
int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList,
- UriMemoryManager * memory) {
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
- while (queryList != NULL) {
- URI_TYPE(QueryList) * nextBackup = queryList->next;
- memory->free(memory, (URI_CHAR *)queryList->key); /* const cast */
- memory->free(memory, (URI_CHAR *)queryList->value); /* const cast */
- memory->free(memory, queryList);
- queryList = nextBackup;
- }
- return URI_SUCCESS;
+ UriMemoryManager * memory) {
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+ while (queryList != NULL) {
+ URI_TYPE(QueryList) * nextBackup = queryList->next;
+ memory->free(memory, (URI_CHAR *)queryList->key); /* const cast */
+ memory->free(memory, (URI_CHAR *)queryList->value); /* const cast */
+ memory->free(memory, queryList);
+ queryList = nextBackup;
+ }
+ return URI_SUCCESS;
}
+int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) * *dest, int * itemCount,
+ const URI_CHAR * first, const URI_CHAR * afterLast) {
+ const UriBool plusToSpace = URI_TRUE;
+ const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
-
-int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount,
- const URI_CHAR * first, const URI_CHAR * afterLast) {
- const UriBool plusToSpace = URI_TRUE;
- const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
-
- return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast,
- plusToSpace, breakConversion);
+ return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, plusToSpace,
+ breakConversion);
}
-
-
-int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriBool plusToSpace, UriBreakConversion breakConversion) {
- return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast,
- plusToSpace, breakConversion, NULL);
+int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) * *dest, int * itemCount,
+ const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriBool plusToSpace,
+ UriBreakConversion breakConversion) {
+ return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast,
+ plusToSpace, breakConversion, NULL);
}
-
-
-int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCount,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriBool plusToSpace, UriBreakConversion breakConversion,
- UriMemoryManager * memory) {
- const URI_CHAR * walk = first;
- const URI_CHAR * keyFirst = first;
- const URI_CHAR * keyAfter = NULL;
- const URI_CHAR * valueFirst = NULL;
- const URI_CHAR * valueAfter = NULL;
- URI_TYPE(QueryList) ** prevNext = dest;
- int nullCounter;
- int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount;
-
- if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) {
- return URI_ERROR_NULL;
- }
-
- if (first > afterLast) {
- return URI_ERROR_RANGE_INVALID;
- }
-
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- *dest = NULL;
- *itemsAppended = 0;
-
- /* Parse query string */
- for (; walk < afterLast; walk++) {
- switch (*walk) {
- case _UT('&'):
- if (valueFirst != NULL) {
- valueAfter = walk;
- } else {
- keyAfter = walk;
- }
-
- if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended,
- keyFirst, keyAfter, valueFirst, valueAfter,
- plusToSpace, breakConversion, memory)
- == URI_FALSE) {
- /* Free list we built */
- *itemsAppended = 0;
- URI_FUNC(FreeQueryListMm)(*dest, memory);
- return URI_ERROR_MALLOC;
- }
-
- /* Make future items children of the current */
- if ((prevNext != NULL) && (*prevNext != NULL)) {
- prevNext = &((*prevNext)->next);
- }
-
- if (walk + 1 < afterLast) {
- keyFirst = walk + 1;
- } else {
- keyFirst = NULL;
- }
- keyAfter = NULL;
- valueFirst = NULL;
- valueAfter = NULL;
- break;
-
- case _UT('='):
- /* NOTE: WE treat the first '=' as a separator, */
- /* all following go into the value part */
- if (keyAfter == NULL) {
- keyAfter = walk;
- if (walk + 1 <= afterLast) {
- valueFirst = walk + 1;
- valueAfter = walk + 1;
- }
- }
- break;
-
- default:
- break;
- }
- }
-
- if (valueFirst != NULL) {
- /* Must be key/value pair */
- valueAfter = walk;
- } else {
- /* Must be key only */
- keyAfter = walk;
- }
-
- if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter,
- valueFirst, valueAfter, plusToSpace, breakConversion, memory)
- == URI_FALSE) {
- /* Free list we built */
- *itemsAppended = 0;
- URI_FUNC(FreeQueryListMm)(*dest, memory);
- return URI_ERROR_MALLOC;
- }
-
- return URI_SUCCESS;
+int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) * *dest, int * itemCount,
+ const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriBool plusToSpace,
+ UriBreakConversion breakConversion,
+ UriMemoryManager * memory) {
+ const URI_CHAR * walk = first;
+ const URI_CHAR * keyFirst = first;
+ const URI_CHAR * keyAfter = NULL;
+ const URI_CHAR * valueFirst = NULL;
+ const URI_CHAR * valueAfter = NULL;
+ URI_TYPE(QueryList) ** prevNext = dest;
+ int nullCounter;
+ int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount;
+
+ if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ if (first > afterLast) {
+ return URI_ERROR_RANGE_INVALID;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ *dest = NULL;
+ *itemsAppended = 0;
+
+ /* Parse query string */
+ for (; walk < afterLast; walk++) {
+ switch (*walk) {
+ case _UT('&'):
+ if (valueFirst != NULL) {
+ valueAfter = walk;
+ } else {
+ keyAfter = walk;
+ }
+
+ if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter,
+ valueFirst, valueAfter, plusToSpace,
+ breakConversion, memory)
+ == URI_FALSE) {
+ /* Free list we built */
+ *itemsAppended = 0;
+ URI_FUNC(FreeQueryListMm)(*dest, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ /* Make future items children of the current */
+ if ((prevNext != NULL) && (*prevNext != NULL)) {
+ prevNext = &((*prevNext)->next);
+ }
+
+ if (walk + 1 < afterLast) {
+ keyFirst = walk + 1;
+ } else {
+ keyFirst = NULL;
+ }
+ keyAfter = NULL;
+ valueFirst = NULL;
+ valueAfter = NULL;
+ break;
+
+ case _UT('='):
+ /* NOTE: WE treat the first '=' as a separator, */
+ /* all following go into the value part */
+ if (keyAfter == NULL) {
+ keyAfter = walk;
+ if (walk + 1 <= afterLast) {
+ valueFirst = walk + 1;
+ valueAfter = walk + 1;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (valueFirst != NULL) {
+ /* Must be key/value pair */
+ valueAfter = walk;
+ } else {
+ /* Must be key only */
+ keyAfter = walk;
+ }
+
+ if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, valueFirst,
+ valueAfter, plusToSpace, breakConversion, memory)
+ == URI_FALSE) {
+ /* Free list we built */
+ *itemsAppended = 0;
+ URI_FUNC(FreeQueryListMm)(*dest, memory);
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
}
-
-
#endif
diff --git a/src/UriRecompose.c b/src/UriRecompose.c
index 5027eca..61ffee7 100644
--- a/src/UriRecompose.c
+++ b/src/UriRecompose.c
@@ -41,537 +41,564 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriRecompose.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriRecompose.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriRecompose.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriRecompose.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-#endif
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# endif
static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
- int maxChars, int * charsWritten, int * charsRequired);
-
+ int maxChars, int * charsWritten,
+ int * charsRequired);
-
-int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri,
- int * charsRequired) {
- const int MAX_CHARS = ((unsigned int)-1) >> 1;
- return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired);
+int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, int * charsRequired) {
+ const int MAX_CHARS = ((unsigned int)-1) >> 1;
+ return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired);
}
-
-
-int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
- int maxChars, int * charsWritten) {
- return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL);
+int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars,
+ int * charsWritten) {
+ return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL);
}
-
-
-static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest,
- const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten,
- int * charsRequired) {
- int written = 0;
- if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) {
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_NULL;
- }
-
- if (maxChars < 1) {
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- maxChars--; /* So we don't have to subtract 1 for '\0' all the time */
-
- /* [01/19] result = "" */
- if (dest != NULL) {
- dest[0] = _UT('\0');
- } else {
- (*charsRequired) = 0;
- }
- /* [02/19] if defined(scheme) then */
- if (uri->scheme.first != NULL) {
- /* [03/19] append scheme to result; */
- const int charsToWrite
- = (int)(uri->scheme.afterLast - uri->scheme.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->scheme.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite;
- }
- /* [04/19] append ":" to result; */
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT(":"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- /* [05/19] endif; */
- }
- /* [06/19] if defined(authority) then */
- if (URI_FUNC(IsHostSet)(uri)) {
- /* [07/19] append "//" to result; */
- if (dest != NULL) {
- if (written + 2 <= maxChars) {
- memcpy(dest + written, _UT("//"),
- 2 * sizeof(URI_CHAR));
- written += 2;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 2;
- }
- /* [08/19] append authority to result; */
- /* UserInfo */
- if (uri->userInfo.first != NULL) {
- const int charsToWrite = (int)(uri->userInfo.afterLast - uri->userInfo.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->userInfo.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
-
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("@"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite + 1;
- }
- }
-
- /* Host */
- if (uri->hostData.ip4 != NULL) {
- /* IPv4 */
- int i = 0;
- for (; i < 4; i++) {
- const unsigned char value = uri->hostData.ip4->data[i];
- const int charsToWrite = (value > 99) ? 3 : ((value > 9) ? 2 : 1);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- URI_CHAR text[4];
- if (value > 99) {
- text[0] = _UT('0') + (value / 100);
- text[1] = _UT('0') + ((value % 100) / 10);
- text[2] = _UT('0') + (value % 10);
- } else if (value > 9) {
- text[0] = _UT('0') + (value / 10);
- text[1] = _UT('0') + (value % 10);
- } else {
- text[0] = _UT('0') + value;
- }
- text[charsToWrite] = _UT('\0');
- memcpy(dest + written, text, charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- if (i < 3) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("."),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- }
- } else {
- (*charsRequired) += charsToWrite + ((i == 3) ? 0 : 1);
- }
- }
- } else if (uri->hostData.ip6 != NULL) {
- /* IPv6 */
- int i = 0;
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("["),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
-
- for (; i < 16; i++) {
- const unsigned char value = uri->hostData.ip6->data[i];
- if (dest != NULL) {
- if (written + 2 <= maxChars) {
- URI_CHAR text[3];
- text[0] = URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE);
- text[1] = URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE);
- text[2] = _UT('\0');
- memcpy(dest + written, text, 2 * sizeof(URI_CHAR));
- written += 2;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 2;
- }
- if (((i & 1) == 1) && (i < 15)) {
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT(":"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- }
- }
-
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("]"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- } else if (uri->hostData.ipFuture.first != NULL) {
- /* IPvFuture */
- const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast
- - uri->hostData.ipFuture.first);
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("["),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
-
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->hostData.ipFuture.first, charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
-
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("]"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1 + charsToWrite + 1;
- }
- } else if (uri->hostText.first != NULL) {
- /* Regname */
- const int charsToWrite = (int)(uri->hostText.afterLast - uri->hostText.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->hostText.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite;
- }
- }
-
- /* Port */
- if (uri->portText.first != NULL) {
- const int charsToWrite = (int)(uri->portText.afterLast - uri->portText.first);
- if (dest != NULL) {
- /* Leading ':' */
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT(":"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
-
- /* Port number */
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->portText.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1 + charsToWrite;
- }
- }
- /* [09/19] endif; */
- }
- /* [10/19] append path to result; */
- /* Slash needed here? */
- if (uri->absolutePath || ((uri->pathHead != NULL)
- && URI_FUNC(IsHostSet)(uri))) {
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("/"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- }
-
- if (uri->pathHead != NULL) {
- URI_TYPE(PathSegment) * walker = uri->pathHead;
- do {
- const int charsToWrite = (int)(walker->text.afterLast - walker->text.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, walker->text.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite;
- }
-
- /* Not last segment -> append slash */
- if (walker->next != NULL) {
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("/"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- }
-
- walker = walker->next;
- } while (walker != NULL);
- }
- /* [11/19] if defined(query) then */
- if (uri->query.first != NULL) {
- /* [12/19] append "?" to result; */
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("?"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- /* [13/19] append query to result; */
- {
- const int charsToWrite
- = (int)(uri->query.afterLast - uri->query.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->query.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite;
- }
- }
- /* [14/19] endif; */
- }
- /* [15/19] if defined(fragment) then */
- if (uri->fragment.first != NULL) {
- /* [16/19] append "#" to result; */
- if (dest != NULL) {
- if (written + 1 <= maxChars) {
- memcpy(dest + written, _UT("#"),
- 1 * sizeof(URI_CHAR));
- written += 1;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += 1;
- }
- /* [17/19] append fragment to result; */
- {
- const int charsToWrite
- = (int)(uri->fragment.afterLast - uri->fragment.first);
- if (dest != NULL) {
- if (written + charsToWrite <= maxChars) {
- memcpy(dest + written, uri->fragment.first,
- charsToWrite * sizeof(URI_CHAR));
- written += charsToWrite;
- } else {
- dest[0] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = 0;
- }
- return URI_ERROR_TOSTRING_TOO_LONG;
- }
- } else {
- (*charsRequired) += charsToWrite;
- }
- }
- /* [18/19] endif; */
- }
- /* [19/19] return result; */
- if (dest != NULL) {
- dest[written++] = _UT('\0');
- if (charsWritten != NULL) {
- *charsWritten = written;
- }
- }
- return URI_SUCCESS;
+static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
+ int maxChars, int * charsWritten,
+ int * charsRequired) {
+ int written = 0;
+ if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) {
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_NULL;
+ }
+
+ if (maxChars < 1) {
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ maxChars--; /* So we don't have to subtract 1 for '\0' all the time */
+
+ /* NOTE: The curly brackets here force deeper indent (and that's all) */
+ {
+ {
+ {
+ /* clang-format off */
+ /* [01/19] result = "" */
+ /* clang-format on */
+ if (dest != NULL) {
+ dest[0] = _UT('\0');
+ } else {
+ (*charsRequired) = 0;
+ }
+ /* clang-format off */
+ /* [02/19] if defined(scheme) then */
+ /* clang-format on */
+ if (uri->scheme.first != NULL) {
+ /* clang-format off */
+ /* [03/19] append scheme to result; */
+ /* clang-format on */
+ const int charsToWrite =
+ (int)(uri->scheme.afterLast - uri->scheme.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->scheme.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite;
+ }
+ /* clang-format off */
+ /* [04/19] append ":" to result; */
+ /* clang-format on */
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ /* clang-format off */
+ /* [05/19] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [06/19] if defined(authority) then */
+ /* clang-format on */
+ if (URI_FUNC(HasHost)(uri)) {
+ /* clang-format off */
+ /* [07/19] append "//" to result; */
+ /* clang-format on */
+ if (dest != NULL) {
+ if (written + 2 <= maxChars) {
+ memcpy(dest + written, _UT("//"), 2 * sizeof(URI_CHAR));
+ written += 2;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 2;
+ }
+ /* clang-format off */
+ /* [08/19] append authority to result; */
+ /* clang-format on */
+ /* UserInfo */
+ if (uri->userInfo.first != NULL) {
+ const int charsToWrite =
+ (int)(uri->userInfo.afterLast - uri->userInfo.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->userInfo.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("@"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite + 1;
+ }
+ }
+
+ /* Host */
+ if (uri->hostData.ip4 != NULL) {
+ /* IPv4 */
+ int i = 0;
+ for (; i < 4; i++) {
+ const unsigned char value = uri->hostData.ip4->data[i];
+ const int charsToWrite =
+ (value > 99) ? 3 : ((value > 9) ? 2 : 1);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ URI_CHAR text[4];
+ if (value > 99) {
+ text[0] = _UT('0') + (value / 100);
+ text[1] = _UT('0') + ((value % 100) / 10);
+ text[2] = _UT('0') + (value % 10);
+ } else if (value > 9) {
+ text[0] = _UT('0') + (value / 10);
+ text[1] = _UT('0') + (value % 10);
+ } else {
+ text[0] = _UT('0') + value;
+ }
+ text[charsToWrite] = _UT('\0');
+ memcpy(dest + written, text,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ if (i < 3) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("."),
+ 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ }
+ } else {
+ (*charsRequired) += charsToWrite + ((i == 3) ? 0 : 1);
+ }
+ }
+ } else if (uri->hostData.ip6 != NULL) {
+ /* IPv6 */
+ int i = 0;
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+
+ for (; i < 16; i++) {
+ const unsigned char value = uri->hostData.ip6->data[i];
+ if (dest != NULL) {
+ if (written + 2 <= maxChars) {
+ URI_CHAR text[3];
+ text[0] =
+ URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE);
+ text[1] =
+ URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE);
+ text[2] = _UT('\0');
+ memcpy(dest + written, text, 2 * sizeof(URI_CHAR));
+ written += 2;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 2;
+ }
+ if (((i & 1) == 1) && (i < 15)) {
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT(":"),
+ 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ }
+ }
+
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ } else if (uri->hostData.ipFuture.first != NULL) {
+ /* IPvFuture */
+ const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast
+ - uri->hostData.ipFuture.first);
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->hostData.ipFuture.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1 + charsToWrite + 1;
+ }
+ } else if (uri->hostText.first != NULL) {
+ /* Regname */
+ const int charsToWrite =
+ (int)(uri->hostText.afterLast - uri->hostText.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->hostText.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite;
+ }
+ }
+
+ /* Port */
+ if (uri->portText.first != NULL) {
+ const int charsToWrite =
+ (int)(uri->portText.afterLast - uri->portText.first);
+ if (dest != NULL) {
+ /* Leading ':' */
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+
+ /* Port number */
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->portText.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1 + charsToWrite;
+ }
+ }
+ /* clang-format off */
+ /* [09/19] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [10/19] append path to result; */
+ /* clang-format on */
+ /* Slash needed here? */
+ if (uri->absolutePath
+ || ((uri->pathHead != NULL) && URI_FUNC(HasHost)(uri))) {
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("/"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ }
+
+ if (uri->pathHead != NULL) {
+ URI_TYPE(PathSegment) * walker = uri->pathHead;
+ do {
+ const int charsToWrite =
+ (int)(walker->text.afterLast - walker->text.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, walker->text.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite;
+ }
+
+ /* Not last segment -> append slash */
+ if (walker->next != NULL) {
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("/"),
+ 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ }
+
+ walker = walker->next;
+ } while (walker != NULL);
+ }
+ /* clang-format off */
+ /* [11/19] if defined(query) then */
+ /* clang-format on */
+ if (uri->query.first != NULL) {
+ /* clang-format off */
+ /* [12/19] append "?" to result; */
+ /* clang-format on */
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("?"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ /* clang-format off */
+ /* [13/19] append query to result; */
+ /* clang-format on */
+ const int charsToWrite =
+ (int)(uri->query.afterLast - uri->query.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->query.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite;
+ }
+ /* clang-format off */
+ /* [14/19] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [15/19] if defined(fragment) then */
+ /* clang-format on */
+ if (uri->fragment.first != NULL) {
+ /* clang-format off */
+ /* [16/19] append "#" to result; */
+ /* clang-format on */
+ if (dest != NULL) {
+ if (written + 1 <= maxChars) {
+ memcpy(dest + written, _UT("#"), 1 * sizeof(URI_CHAR));
+ written += 1;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += 1;
+ }
+ /* clang-format off */
+ /* [17/19] append fragment to result; */
+ /* clang-format on */
+ const int charsToWrite =
+ (int)(uri->fragment.afterLast - uri->fragment.first);
+ if (dest != NULL) {
+ if (written + charsToWrite <= maxChars) {
+ memcpy(dest + written, uri->fragment.first,
+ charsToWrite * sizeof(URI_CHAR));
+ written += charsToWrite;
+ } else {
+ dest[0] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = 0;
+ }
+ return URI_ERROR_TOSTRING_TOO_LONG;
+ }
+ } else {
+ (*charsRequired) += charsToWrite;
+ }
+ /* clang-format off */
+ /* [18/19] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [19/19] return result; */
+ /* clang-format on */
+ if (dest != NULL) {
+ dest[written++] = _UT('\0');
+ if (charsWritten != NULL) {
+ *charsWritten = written;
+ }
+ }
+ return URI_SUCCESS;
+ }
+ }
+ }
}
-
-
#endif
diff --git a/src/UriResolve.c b/src/UriResolve.c
index 80031a8..302665d 100644
--- a/src/UriResolve.c
+++ b/src/UriResolve.c
@@ -41,289 +41,358 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriResolve.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriResolve.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriResolve.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriResolve.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-# include "UriMemory.h"
-#endif
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# endif
/* Appends a relative URI to an absolute. The last path segment of
* the absolute URI is replaced. */
static URI_INLINE UriBool URI_FUNC(MergePath)(URI_TYPE(Uri) * absWork,
- const URI_TYPE(Uri) * relAppend, UriMemoryManager * memory) {
- URI_TYPE(PathSegment) * sourceWalker;
- URI_TYPE(PathSegment) * destPrev;
- if (relAppend->pathHead == NULL) {
- return URI_TRUE;
- }
-
- /* Replace last segment ("" if trailing slash) with first of append chain */
- if (absWork->pathHead == NULL) {
- URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
- if (dup == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- dup->next = NULL;
- absWork->pathHead = dup;
- absWork->pathTail = dup;
- }
- absWork->pathTail->text.first = relAppend->pathHead->text.first;
- absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast;
-
- /* Append all the others */
- sourceWalker = relAppend->pathHead->next;
- if (sourceWalker == NULL) {
- return URI_TRUE;
- }
- destPrev = absWork->pathTail;
-
- for (;;) {
- URI_TYPE(PathSegment) * const dup = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
- if (dup == NULL) {
- destPrev->next = NULL;
- absWork->pathTail = destPrev;
- return URI_FALSE; /* Raises malloc error */
- }
- dup->text = sourceWalker->text;
- destPrev->next = dup;
-
- if (sourceWalker->next == NULL) {
- absWork->pathTail = dup;
- absWork->pathTail->next = NULL;
- break;
- }
- destPrev = dup;
- sourceWalker = sourceWalker->next;
- }
-
- return URI_TRUE;
+ const URI_TYPE(Uri) * relAppend,
+ UriMemoryManager * memory) {
+ URI_TYPE(PathSegment) * sourceWalker;
+ URI_TYPE(PathSegment) * destPrev;
+ if (relAppend->pathHead == NULL) {
+ return URI_TRUE;
+ }
+
+ /* Replace last segment ("" if trailing slash) with first of append chain */
+ if (absWork->pathHead == NULL) {
+ URI_TYPE(PathSegment) * const dup =
+ memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
+ if (dup == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ dup->next = NULL;
+ absWork->pathHead = dup;
+ absWork->pathTail = dup;
+ }
+ absWork->pathTail->text.first = relAppend->pathHead->text.first;
+ absWork->pathTail->text.afterLast = relAppend->pathHead->text.afterLast;
+
+ /* Append all the others */
+ sourceWalker = relAppend->pathHead->next;
+ if (sourceWalker == NULL) {
+ return URI_TRUE;
+ }
+ destPrev = absWork->pathTail;
+
+ for (;;) {
+ URI_TYPE(PathSegment) * const dup =
+ memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
+ if (dup == NULL) {
+ destPrev->next = NULL;
+ absWork->pathTail = destPrev;
+ return URI_FALSE; /* Raises malloc error */
+ }
+ dup->text = sourceWalker->text;
+ destPrev->next = dup;
+
+ if (sourceWalker->next == NULL) {
+ absWork->pathTail = dup;
+ absWork->pathTail->next = NULL;
+ break;
+ }
+ destPrev = dup;
+ sourceWalker = sourceWalker->next;
+ }
+
+ return URI_TRUE;
}
-
static int URI_FUNC(ResolveAbsolutePathFlag)(URI_TYPE(Uri) * absWork,
- UriMemoryManager * memory) {
- if (absWork == NULL) {
- return URI_ERROR_NULL;
- }
-
- if (URI_FUNC(IsHostSet)(absWork) && absWork->absolutePath) {
- /* Empty segment needed, instead? */
- if (absWork->pathHead == NULL) {
- URI_TYPE(PathSegment) * const segment = memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
- if (segment == NULL) {
- return URI_ERROR_MALLOC;
- }
- segment->text.first = URI_FUNC(SafeToPointTo);
- segment->text.afterLast = URI_FUNC(SafeToPointTo);
- segment->next = NULL;
-
- absWork->pathHead = segment;
- absWork->pathTail = segment;
- }
-
- absWork->absolutePath = URI_FALSE;
- }
-
- return URI_SUCCESS;
+ UriMemoryManager * memory) {
+ if (absWork == NULL) {
+ return URI_ERROR_NULL;
+ }
+
+ if (URI_FUNC(HasHost)(absWork) && absWork->absolutePath) {
+ /* Empty segment needed, instead? */
+ if (absWork->pathHead == NULL) {
+ URI_TYPE(PathSegment) * const segment =
+ memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
+ if (segment == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+ segment->text.first = URI_FUNC(SafeToPointTo);
+ segment->text.afterLast = URI_FUNC(SafeToPointTo);
+ segment->next = NULL;
+
+ absWork->pathHead = segment;
+ absWork->pathTail = segment;
+ }
+
+ absWork->absolutePath = URI_FALSE;
+ }
+
+ return URI_SUCCESS;
}
-
static int URI_FUNC(AddBaseUriImpl)(URI_TYPE(Uri) * absDest,
- const URI_TYPE(Uri) * relSource,
- const URI_TYPE(Uri) * absBase,
- UriResolutionOptions options, UriMemoryManager * memory) {
- UriBool relSourceHasScheme;
-
- if (absDest == NULL) {
- return URI_ERROR_NULL;
- }
- URI_FUNC(ResetUri)(absDest);
-
- if ((relSource == NULL) || (absBase == NULL)) {
- return URI_ERROR_NULL;
- }
-
- /* absBase absolute? */
- if (absBase->scheme.first == NULL) {
- return URI_ERROR_ADDBASE_REL_BASE;
- }
-
- /* [00/32] -- A non-strict parser may ignore a scheme in the reference */
- /* [00/32] -- if it is identical to the base URI's scheme. */
- /* [00/32] if ((not strict) and (R.scheme == Base.scheme)) then */
- relSourceHasScheme = (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE;
- if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT)
- && (absBase->scheme.first != NULL)
- && (relSource->scheme.first != NULL)
- && (0 == URI_FUNC(CompareRange)(&(absBase->scheme), &(relSource->scheme)))) {
- /* [00/32] undefine(R.scheme); */
- relSourceHasScheme = URI_FALSE;
- /* [00/32] endif; */
- }
-
- /* [01/32] if defined(R.scheme) then */
- if (relSourceHasScheme) {
- /* [02/32] T.scheme = R.scheme; */
- absDest->scheme = relSource->scheme;
- /* [03/32] T.authority = R.authority; */
- if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [04/32] T.path = remove_dot_segments(R.path); */
- if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [05/32] T.query = R.query; */
- absDest->query = relSource->query;
- /* [06/32] else */
- } else {
- /* [07/32] if defined(R.authority) then */
- if (URI_FUNC(IsHostSet)(relSource)) {
- /* [08/32] T.authority = R.authority; */
- if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [09/32] T.path = remove_dot_segments(R.path); */
- if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [10/32] T.query = R.query; */
- absDest->query = relSource->query;
- /* [11/32] else */
- } else {
- /* [28/32] T.authority = Base.authority; */
- if (!URI_FUNC(CopyAuthority)(absDest, absBase, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [12/32] if (R.path == "") then */
- if (relSource->pathHead == NULL && !relSource->absolutePath) {
- /* [13/32] T.path = Base.path; */
- if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [14/32] if defined(R.query) then */
- if (relSource->query.first != NULL) {
- /* [15/32] T.query = R.query; */
- absDest->query = relSource->query;
- /* [16/32] else */
- } else {
- /* [17/32] T.query = Base.query; */
- absDest->query = absBase->query;
- /* [18/32] endif; */
- }
- /* [19/32] else */
- } else {
- /* [20/32] if (R.path starts-with "/") then */
- if (relSource->absolutePath) {
- int res;
- /* [21/32] T.path = remove_dot_segments(R.path); */
- if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- res = URI_FUNC(ResolveAbsolutePathFlag)(absDest, memory);
- if (res != URI_SUCCESS) {
- return res;
- }
- if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [22/32] else */
- } else {
- /* [23/32] T.path = merge(Base.path, R.path); */
- if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
- return URI_ERROR_MALLOC;
- }
- if (!URI_FUNC(MergePath)(absDest, relSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [24/32] T.path = remove_dot_segments(T.path); */
- if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
- return URI_ERROR_MALLOC;
- }
-
- if (!URI_FUNC(FixAmbiguity)(absDest, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [25/32] endif; */
- }
- /* [26/32] T.query = R.query; */
- absDest->query = relSource->query;
- /* [27/32] endif; */
- }
- URI_FUNC(FixEmptyTrailSegment)(absDest, memory);
- /* [29/32] endif; */
- }
- /* [30/32] T.scheme = Base.scheme; */
- absDest->scheme = absBase->scheme;
- /* [31/32] endif; */
- }
- /* [32/32] T.fragment = R.fragment; */
- absDest->fragment = relSource->fragment;
-
- return URI_SUCCESS;
-
+ const URI_TYPE(Uri) * relSource,
+ const URI_TYPE(Uri) * absBase,
+ UriResolutionOptions options,
+ UriMemoryManager * memory) {
+ UriBool relSourceHasScheme;
+
+ if (absDest == NULL) {
+ return URI_ERROR_NULL;
+ }
+ URI_FUNC(ResetUri)(absDest);
+
+ if ((relSource == NULL) || (absBase == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ /* absBase absolute? */
+ if (absBase->scheme.first == NULL) {
+ return URI_ERROR_ADDBASE_REL_BASE;
+ }
+
+ /* NOTE: The curly brackets here force deeper indent (and that's all) */
+ {
+ {
+ {
+ /* clang-format off */
+ /* [00/32] -- A non-strict parser may ignore a scheme in the reference */
+ /* [00/32] -- if it is identical to the base URI's scheme. */
+ /* [00/32] if ((not strict) and (R.scheme == Base.scheme)) then */
+ /* clang-format on */
+ relSourceHasScheme =
+ (relSource->scheme.first != NULL) ? URI_TRUE : URI_FALSE;
+ if ((options & URI_RESOLVE_IDENTICAL_SCHEME_COMPAT)
+ && (absBase->scheme.first != NULL)
+ && (relSource->scheme.first != NULL)
+ && (0
+ == URI_FUNC(CompareRange)(&(absBase->scheme),
+ &(relSource->scheme)))) {
+ /* clang-format off */
+ /* [00/32] undefine(R.scheme); */
+ /* clang-format on */
+ relSourceHasScheme = URI_FALSE;
+ /* clang-format off */
+ /* [00/32] endif; */
+ /* clang-format on */
+ }
+
+ /* clang-format off */
+ /* [01/32] if defined(R.scheme) then */
+ /* clang-format on */
+ if (relSourceHasScheme) {
+ /* clang-format off */
+ /* [02/32] T.scheme = R.scheme; */
+ /* clang-format on */
+ absDest->scheme = relSource->scheme;
+ /* clang-format off */
+ /* [03/32] T.authority = R.authority; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [04/32] T.path = remove_dot_segments(R.path); */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [05/32] T.query = R.query; */
+ /* clang-format on */
+ absDest->query = relSource->query;
+ /* clang-format off */
+ /* [06/32] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [07/32] if defined(R.authority) then */
+ /* clang-format on */
+ if (URI_FUNC(HasHost)(relSource)) {
+ /* clang-format off */
+ /* [08/32] T.authority = R.authority; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyAuthority)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [09/32] T.path = remove_dot_segments(R.path); */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [10/32] T.query = R.query; */
+ /* clang-format on */
+ absDest->query = relSource->query;
+ /* clang-format off */
+ /* [11/32] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [28/32] T.authority = Base.authority; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyAuthority)(absDest, absBase, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [12/32] if (R.path == "") then */
+ /* clang-format on */
+ if (relSource->pathHead == NULL && !relSource->absolutePath) {
+ /* clang-format off */
+ /* [13/32] T.path = Base.path; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [14/32] if defined(R.query) then */
+ /* clang-format on */
+ if (relSource->query.first != NULL) {
+ /* clang-format off */
+ /* [15/32] T.query = R.query; */
+ /* clang-format on */
+ absDest->query = relSource->query;
+ /* clang-format off */
+ /* [16/32] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [17/32] T.query = Base.query; */
+ /* clang-format on */
+ absDest->query = absBase->query;
+ /* clang-format off */
+ /* [18/32] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [19/32] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [20/32] if (R.path starts-with "/") then */
+ /* clang-format on */
+ if (relSource->absolutePath) {
+ int res;
+ /* clang-format off */
+ /* [21/32] T.path = remove_dot_segments(R.path); */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ res = URI_FUNC(ResolveAbsolutePathFlag)(absDest, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest,
+ memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [22/32] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [23/32] T.path = merge(Base.path, R.path); */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(absDest, absBase, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ if (!URI_FUNC(MergePath)(absDest, relSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [24/32] T.path = remove_dot_segments(T.path); */
+ /* clang-format on */
+ if (!URI_FUNC(RemoveDotSegmentsAbsolute)(absDest,
+ memory)) {
+ return URI_ERROR_MALLOC;
+ }
+
+ if (!URI_FUNC(FixAmbiguity)(absDest, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [25/32] endif; */
+ }
+ /* clang-format off */
+ /* [26/32] T.query = R.query; */
+ /* clang-format on */
+ absDest->query = relSource->query;
+ /* clang-format off */
+ /* [27/32] endif; */
+ /* clang-format on */
+ }
+ URI_FUNC(FixEmptyTrailSegment)(absDest, memory);
+ /* clang-format off */
+ /* [29/32] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [30/32] T.scheme = Base.scheme; */
+ /* clang-format on */
+ absDest->scheme = absBase->scheme;
+ /* clang-format off */
+ /* [31/32] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [32/32] T.fragment = R.fragment; */
+ /* clang-format on */
+ absDest->fragment = relSource->fragment;
+ }
+ }
+ }
+ return URI_SUCCESS;
}
-
-
-int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest,
- const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase) {
- const UriResolutionOptions options = URI_RESOLVE_STRICTLY;
- return URI_FUNC(AddBaseUriEx)(absDest, relSource, absBase, options);
+int URI_FUNC(AddBaseUri)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource,
+ const URI_TYPE(Uri) * absBase) {
+ const UriResolutionOptions options = URI_RESOLVE_STRICTLY;
+ return URI_FUNC(AddBaseUriEx)(absDest, relSource, absBase, options);
}
-
-
-int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest,
- const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase,
- UriResolutionOptions options) {
- return URI_FUNC(AddBaseUriExMm)(absDest, relSource, absBase, options, NULL);
+int URI_FUNC(AddBaseUriEx)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource,
+ const URI_TYPE(Uri) * absBase, UriResolutionOptions options) {
+ return URI_FUNC(AddBaseUriExMm)(absDest, relSource, absBase, options, NULL);
}
+int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absDest, const URI_TYPE(Uri) * relSource,
+ const URI_TYPE(Uri) * absBase, UriResolutionOptions options,
+ UriMemoryManager * memory) {
+ int res;
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-int URI_FUNC(AddBaseUriExMm)(URI_TYPE(Uri) * absDest,
- const URI_TYPE(Uri) * relSource, const URI_TYPE(Uri) * absBase,
- UriResolutionOptions options, UriMemoryManager * memory) {
- int res;
-
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options, memory);
- if ((res != URI_SUCCESS) && (absDest != NULL)) {
- URI_FUNC(FreeUriMembersMm)(absDest, memory);
- }
- return res;
+ res = URI_FUNC(AddBaseUriImpl)(absDest, relSource, absBase, options, memory);
+ if ((res != URI_SUCCESS) && (absDest != NULL)) {
+ URI_FUNC(FreeUriMembersMm)(absDest, memory);
+ }
+ return res;
}
-
-
#endif
diff --git a/src/UriSetFragment.c b/src/UriSetFragment.c
new file mode 100644
index 0000000..4479391
--- /dev/null
+++ b/src/UriSetFragment.c
@@ -0,0 +1,174 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetFragment.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetFragment.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedFragment)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * fragment = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_PCHAR_WITHOUT_PERCENT(_UT):
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case _UT('/'):
+ case _UT('?'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetFragmentMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL)
+ && (URI_FUNC(IsWellFormedFragment)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->fragment.first != uri->fragment.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->fragment.first);
+ }
+ uri->fragment.first = NULL;
+ uri->fragment.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->fragment, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetFragment)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetFragmentMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetHostAuto.c b/src/UriSetHostAuto.c
new file mode 100644
index 0000000..df01588
--- /dev/null
+++ b/src/UriSetHostAuto.c
@@ -0,0 +1,124 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostAuto.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostAuto.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# include "UriMemory.h"
+# endif
+
+# include <assert.h>
+
+int URI_FUNC(SetHostAutoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first == NULL) || (first >= afterLast)) {
+ return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, memory);
+ }
+
+ /* Auto-detect type and then apply */
+ UriHostType hostType;
+
+ /* IPv6 or IPvFuture? */
+ if (first[0] == _UT('[')) {
+ if ((afterLast - first < 2) || (afterLast[-1] != _UT(']'))) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Drop the bracket wrap (for InternalSetHostMm call below) */
+ first++;
+ afterLast--;
+
+ if (first >= afterLast) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ hostType = URI_HOST_TYPE_IPFUTURE;
+ break;
+ default:
+ hostType = URI_HOST_TYPE_IP6;
+ break;
+ }
+ /* IPv4? */
+ } else if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast)) {
+ hostType = URI_HOST_TYPE_IP4;
+ } else {
+ /* RegName! */
+ hostType = URI_HOST_TYPE_REGNAME;
+ }
+
+ return URI_FUNC(InternalSetHostMm)(uri, hostType, first, afterLast, memory);
+}
+
+int URI_FUNC(SetHostAuto)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostAutoMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetHostBase.h b/src/UriSetHostBase.h
new file mode 100644
index 0000000..081db36
--- /dev/null
+++ b/src/UriSetHostBase.h
@@ -0,0 +1,49 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef URI_SET_HOST_BASE_H
+# define URI_SET_HOST_BASE_H 1
+
+typedef enum UriHostTypeEnum {
+ URI_HOST_TYPE_IP4,
+ URI_HOST_TYPE_IP6,
+ URI_HOST_TYPE_IPFUTURE,
+ URI_HOST_TYPE_REGNAME
+} UriHostType;
+
+#endif /* URI_SET_HOST_BASE_H */
diff --git a/src/UriSetHostCommon.c b/src/UriSetHostCommon.c
new file mode 100644
index 0000000..bd8095a
--- /dev/null
+++ b/src/UriSetHostCommon.c
@@ -0,0 +1,248 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriSetHostCommon.c
+ * Holds code used by multiple SetHost* functions.
+ * NOTE: This source file includes itself twice.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostCommon.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostCommon.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include <uriparser/UriIp4.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# endif
+
+# include <assert.h>
+
+int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, UriHostType hostType,
+ const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Superficial input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no user info or port without a host. */
+ if (first == NULL) {
+ if (uri->userInfo.first != NULL) {
+ return URI_ERROR_SETHOST_USERINFO_SET;
+ } else if (uri->portText.first != NULL) {
+ return URI_ERROR_SETHOST_PORT_SET;
+ }
+ }
+
+ /* Syntax-check the new value */
+ if (first != NULL) {
+ switch (hostType) {
+ case URI_HOST_TYPE_IP4:
+ if (URI_FUNC(IsWellFormedHostIp4)(first, afterLast) == URI_FALSE) {
+ return URI_ERROR_SYNTAX;
+ }
+ break;
+ case URI_HOST_TYPE_IP6: {
+ const int res = URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ } break;
+ case URI_HOST_TYPE_IPFUTURE: {
+ const int res =
+ URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ } break;
+ case URI_HOST_TYPE_REGNAME:
+ if (URI_FUNC(IsWellFormedHostRegName)(first, afterLast) == URI_FALSE) {
+ return URI_ERROR_SYNTAX;
+ }
+ break;
+ default:
+ assert(0 && "Unsupported URI host type");
+ }
+ }
+
+ /* Clear old value */
+ const UriBool hadHostBefore = URI_FUNC(HasHost)(uri);
+ if (uri->hostData.ipFuture.first != NULL) {
+ /* NOTE: .hostData.ipFuture holds the very same range pointers
+ * as .hostText; we must not free memory twice. */
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+
+ if ((uri->owner == URI_TRUE)
+ && (uri->hostData.ipFuture.first != uri->hostData.ipFuture.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
+ }
+ uri->hostData.ipFuture.first = NULL;
+ uri->hostData.ipFuture.afterLast = NULL;
+ } else if (uri->hostText.first != NULL) {
+ if ((uri->owner == URI_TRUE)
+ && (uri->hostText.first != uri->hostText.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->hostText.first);
+ }
+ uri->hostText.first = NULL;
+ uri->hostText.afterLast = NULL;
+ }
+
+ if (uri->hostData.ip4 != NULL) {
+ memory->free(memory, uri->hostData.ip4);
+ uri->hostData.ip4 = NULL;
+ } else if (uri->hostData.ip6 != NULL) {
+ memory->free(memory, uri->hostData.ip6);
+ uri->hostData.ip6 = NULL;
+ }
+
+ /* Already done setting? */
+ if (first == NULL) {
+ /* Yes, but disambiguate as needed */
+ if (hadHostBefore == URI_TRUE) {
+ if (uri->pathHead != NULL) {
+ uri->absolutePath = URI_TRUE;
+ }
+
+ const UriBool success =
+ URI_FUNC(EnsureThatPathIsNotMistakenForHost)(uri, memory);
+ return (success == URI_TRUE) ? URI_SUCCESS : URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value; NOTE that .hostText is set for all four host types */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->hostText, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ uri->absolutePath = URI_FALSE; /* always URI_FALSE for URIs with host */
+
+ /* Fill .hostData as needed */
+ switch (hostType) {
+ case URI_HOST_TYPE_IP4: {
+ uri->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
+ if (uri->hostData.ip4 == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ const int res =
+ URI_FUNC(ParseIpFourAddress)(uri->hostData.ip4->data, first, afterLast);
+# if defined(NDEBUG)
+ (void)res; /* i.e. mark as unused */
+# else
+ assert(res == URI_SUCCESS); /* because checked for well-formedness earlier */
+# endif
+ } break;
+ case URI_HOST_TYPE_IP6: {
+ uri->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
+ if (uri->hostData.ip6 == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ const int res =
+ URI_FUNC(ParseIpSixAddressMm)(uri->hostData.ip6, first, afterLast, memory);
+ assert((res == URI_SUCCESS)
+ || (res == URI_ERROR_MALLOC)); /* because checked for
+ well-formedness earlier */
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ } break;
+ case URI_HOST_TYPE_IPFUTURE:
+ uri->hostData.ipFuture.first = uri->hostText.first;
+ uri->hostData.ipFuture.afterLast = uri->hostText.afterLast;
+ break;
+ case URI_HOST_TYPE_REGNAME:
+ break;
+ default:
+ assert(0 && "Unsupported URI host type");
+ }
+
+ return URI_SUCCESS;
+}
+
+#endif
diff --git a/src/UriSetHostCommon.h b/src/UriSetHostCommon.h
new file mode 100644
index 0000000..6627767
--- /dev/null
+++ b/src/UriSetHostCommon.h
@@ -0,0 +1,74 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE)) \
+ || (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* What encodings are enabled? */
+# include <uriparser/UriDefsConfig.h>
+# if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostCommon.h"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostCommon.h"
+# undef URI_PASS_UNICODE
+# endif
+/* Only one pass for each encoding */
+# elif (defined(URI_PASS_ANSI) && !defined(URI_SET_HOST_COMMON_H_ANSI) \
+ && defined(URI_ENABLE_ANSI)) \
+ || (defined(URI_PASS_UNICODE) && !defined(URI_SET_HOST_COMMON_H_UNICODE) \
+ && defined(URI_ENABLE_UNICODE))
+# ifdef URI_PASS_ANSI
+# define URI_SET_HOST_COMMON_H_ANSI 1
+# include <uriparser/UriDefsAnsi.h>
+# else
+# define URI_SET_HOST_COMMON_H_UNICODE 1
+# include <uriparser/UriDefsUnicode.h>
+# endif
+
+int URI_FUNC(InternalSetHostMm)(URI_TYPE(Uri) * uri, UriHostType hostType,
+ const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriMemoryManager * memory);
+
+# endif
+#endif
diff --git a/src/UriSetHostIp4.c b/src/UriSetHostIp4.c
new file mode 100644
index 0000000..e52880b
--- /dev/null
+++ b/src/UriSetHostIp4.c
@@ -0,0 +1,91 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIp4.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIp4.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include <uriparser/UriIp4.h>
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# endif
+
+UriBool URI_FUNC(IsWellFormedHostIp4)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ unsigned char octetOutput[4];
+ return (URI_FUNC(ParseIpFourAddress)(octetOutput, first, afterLast) == URI_SUCCESS)
+ ? URI_TRUE
+ : URI_FALSE;
+}
+
+int URI_FUNC(SetHostIp4Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP4, first, afterLast, memory);
+}
+
+int URI_FUNC(SetHostIp4)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIp4Mm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetHostIp6.c b/src/UriSetHostIp6.c
new file mode 100644
index 0000000..9637a43
--- /dev/null
+++ b/src/UriSetHostIp6.c
@@ -0,0 +1,158 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIp6.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIp6.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# endif
+
+# include <assert.h>
+# include <string.h> /* for memcpy */
+
+# define URI_MAX_IP6_LEN \
+ (8 * 4 + 7 * 1) /* i.e. 8 full quads plus 7 colon separators \
+ */
+
+int URI_FUNC(ParseIpSixAddressMm)(UriIp6 * output, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* NOTE: output is allowed to be NULL */
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* Are we dealing with potential IPvFuture input? */
+ if (first < afterLast) {
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ return URI_ERROR_SYNTAX;
+ default:
+ break;
+ }
+ }
+
+ /* Are we dealing with IPv6 input? */
+ /* Assemble "//[..]" input wrap for upcoming parse as a URI
+ * NOTE: If the input contains closing "]" on its own, the resulting
+ * string will not be valid URI syntax, and hence there is
+ * no risk of false positives from "bracket injection". */
+ URI_CHAR candidate[3 + URI_MAX_IP6_LEN + 1 + 1] = _UT("//[");
+ const size_t inputLenChars = (afterLast - first);
+
+ /* Detect overflow */
+ if (inputLenChars > URI_MAX_IP6_LEN) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ memcpy(candidate + 3 + inputLenChars, _UT("]"),
+ 2 * sizeof(URI_CHAR)); /* includes zero terminator */
+
+ /* Parse as an RFC 3986 URI */
+ const size_t candidateLenChars = 3 + inputLenChars + 1;
+ URI_TYPE(Uri) uri;
+ const int res = URI_FUNC(ParseSingleUriExMm)(
+ &uri, candidate, candidate + candidateLenChars, NULL, memory);
+
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+
+ if (res == URI_SUCCESS) {
+ assert(uri.hostData.ip6 != NULL);
+
+ if (output != NULL) {
+ memcpy(output->data, uri.hostData.ip6->data, sizeof(output->data));
+ }
+
+ URI_FUNC(FreeUriMembersMm)(&uri, memory);
+ }
+
+ return res;
+}
+
+int URI_FUNC(ParseIpSixAddress)(UriIp6 * output, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(ParseIpSixAddressMm)(output, first, afterLast, NULL);
+}
+
+int URI_FUNC(IsWellFormedHostIp6Mm)(const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ return URI_FUNC(ParseIpSixAddressMm)(NULL, first, afterLast, memory);
+}
+
+int URI_FUNC(IsWellFormedHostIp6)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ return URI_FUNC(IsWellFormedHostIp6Mm)(first, afterLast, NULL);
+}
+
+int URI_FUNC(SetHostIp6Mm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IP6, first, afterLast, memory);
+}
+
+int URI_FUNC(SetHostIp6)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIp6Mm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetHostIpFuture.c b/src/UriSetHostIpFuture.c
new file mode 100644
index 0000000..c5044c4
--- /dev/null
+++ b/src/UriSetHostIpFuture.c
@@ -0,0 +1,157 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostIpFuture.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostIpFuture.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# endif
+
+# include <assert.h>
+# include <string.h> /* for memcpy */
+
+int URI_FUNC(IsWellFormedHostIpFutureMm)(const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* Are we dealing with potential IPv6 input? */
+ if (first < afterLast) {
+ switch (first[0]) {
+ case _UT('v'):
+ case _UT('V'):
+ break;
+ default:
+ return URI_ERROR_SYNTAX;
+ }
+ }
+
+ /* Are we dealing with IPvFuture input? */
+ /* Assemble "//[..]" input wrap for upcoming parse as a URI
+ * NOTE: If the input contains closing "]" on its own, the resulting
+ * string will not be valid URI syntax, and hence there is
+ * no risk of false positives from "bracket injection". */
+ const size_t inputLenChars = (afterLast - first);
+ const size_t MAX_SIZE_T = (size_t)-1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T - inputLenChars < 3 + 1 + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ const size_t candidateLenChars = 3 + inputLenChars + 1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ URI_CHAR * const candidate =
+ memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR));
+
+ if (candidate == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ memcpy(candidate, _UT("//["), 3 * sizeof(URI_CHAR));
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ memcpy(candidate + 3 + inputLenChars, _UT("]"),
+ 2 * sizeof(URI_CHAR)); /* includes zero terminator */
+
+ /* Parse as an RFC 3986 URI */
+ URI_TYPE(Uri) uri;
+ const int res = URI_FUNC(ParseSingleUriExMm)(
+ &uri, candidate, candidate + candidateLenChars, NULL, memory);
+
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+
+ if (res == URI_SUCCESS) {
+ assert(uri.hostData.ipFuture.first != NULL);
+ URI_FUNC(FreeUriMembersMm)(&uri, memory);
+ }
+
+ memory->free(memory, candidate);
+
+ return res;
+}
+
+int URI_FUNC(IsWellFormedHostIpFuture)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(IsWellFormedHostIpFutureMm)(first, afterLast, NULL);
+}
+
+int URI_FUNC(SetHostIpFutureMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_IPFUTURE, first, afterLast,
+ memory);
+}
+
+int URI_FUNC(SetHostIpFuture)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostIpFutureMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetHostRegName.c b/src/UriSetHostRegName.c
new file mode 100644
index 0000000..01bc4e4
--- /dev/null
+++ b/src/UriSetHostRegName.c
@@ -0,0 +1,124 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetHostRegName.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetHostRegName.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriMemory.h"
+# include "UriSetHostBase.h"
+# include "UriSetHostCommon.h"
+# include "UriSets.h"
+# endif
+
+UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* reg-name = *( unreserved / pct-encoded / sub-delims ) */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED(_UT):
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS(_UT):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetHostRegNameMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ return URI_FUNC(InternalSetHostMm)(uri, URI_HOST_TYPE_REGNAME, first, afterLast,
+ memory);
+}
+
+int URI_FUNC(SetHostRegName)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetHostRegNameMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetPath.c b/src/UriSetPath.c
new file mode 100644
index 0000000..17aef0f
--- /dev/null
+++ b/src/UriSetPath.c
@@ -0,0 +1,343 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetPath.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetPath.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedPath)(const URI_CHAR * first, const URI_CHAR * afterLast,
+ UriBool hasHost) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ if ((hasHost == URI_TRUE) && ((first >= afterLast) || (first[0] != _UT('/')))) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 (section 3.3) reads:
+ *
+ * path = path-abempty ; begins with "/" or is empty
+ * / path-absolute ; begins with "/" but not "//"
+ * / path-noscheme ; begins with a non-colon segment
+ * / path-rootless ; begins with a segment
+ * / path-empty ; zero characters
+ *
+ * path-abempty = *( "/" segment )
+ * path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ * path-noscheme = segment-nz-nc *( "/" segment )
+ * path-rootless = segment-nz *( "/" segment )
+ * path-empty = 0<pchar>
+ *
+ * segment = *pchar
+ * segment-nz = 1*pchar
+ * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ * ; non-zero-length segment without any colon ":"
+ *
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ *
+ * The check below simplifies this to ..
+ *
+ * path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" )
+ *
+ * .. and leaves the rest to pre-return removal of ambiguity
+ * from cases like "path1:/path2" and "//path1/path2" inside SetPath.
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_PCHAR_WITHOUT_PERCENT(_UT):
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case _UT('/'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+static void URI_FUNC(DropEmptyFirstPathSegment)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+ assert(uri->pathHead != NULL);
+ assert(uri->pathHead->text.first == uri->pathHead->text.afterLast);
+
+ URI_TYPE(PathSegment) * const originalHead = uri->pathHead;
+
+ uri->pathHead = uri->pathHead->next;
+
+ originalHead->text.first = NULL;
+ originalHead->text.afterLast = NULL;
+ memory->free(memory, originalHead);
+}
+
+/* URIs without a host encode a leading slash in the path as .absolutePath == URI_TRUE.
+ * This function checks for a leading empty path segment (that would have the "visual
+ * effect" of a leading slash during stringification) and transforms it into .absolutePath
+ * == URI_TRUE instead, if present. */
+static void URI_FUNC(TransformEmptyLeadPathSegments)(URI_TYPE(Uri) * uri,
+ UriMemoryManager * memory) {
+ assert(uri != NULL);
+ assert(memory != NULL);
+
+ if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->pathHead == NULL)
+ || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
+ return; /* i.e. nothing to do */
+ }
+
+ assert(uri->absolutePath == URI_FALSE);
+
+ URI_FUNC(DropEmptyFirstPathSegment)(uri, memory);
+
+ uri->absolutePath = URI_TRUE;
+}
+
+static int URI_FUNC(InternalSetPath)(URI_TYPE(Uri) * destUri, const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ assert(destUri != NULL);
+ assert(first != NULL);
+ assert(afterLast != NULL);
+ assert(memory != NULL);
+ assert(destUri->pathHead == NULL); /* set by SetPathMm right before */
+ assert(destUri->pathTail == NULL); /* set by SetPathMm right before */
+ assert(destUri->absolutePath == URI_FALSE); /* set by SetPathMm right before */
+
+ /* Skip the leading slash from target URIs with a host (so that we can
+ * transfer the path 1:1 further down) */
+ if (URI_FUNC(HasHost)(destUri) == URI_TRUE) {
+ /* NOTE: This is because SetPathMm called IsWellFormedPath earlier: */
+ assert((afterLast - first >= 1) && (first[0] == _UT('/')));
+ first++;
+ } else if (first == afterLast) {
+ /* This avoids (1) all the expensive but unnecessary work below
+ * and also (2) mis-encoding as single empty path segment
+ * that would need (detection and) repair further down otherwise */
+ return URI_SUCCESS;
+ }
+
+ /* Assemble "///.." input wrap for upcoming parse as a URI */
+ const size_t inputLenChars = (afterLast - first);
+ const size_t MAX_SIZE_T = (size_t)-1;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T - inputLenChars < 3 + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ const size_t candidateLenChars = 3 + inputLenChars;
+
+ /* Detect overflow */
+ if (MAX_SIZE_T / sizeof(URI_CHAR) < candidateLenChars + 1) {
+ return URI_ERROR_MALLOC;
+ }
+
+ URI_CHAR * const candidate =
+ memory->malloc(memory, (candidateLenChars + 1) * sizeof(URI_CHAR));
+
+ if (candidate == NULL) {
+ return URI_ERROR_MALLOC;
+ }
+
+ memcpy(candidate, _UT("///"), 3 * sizeof(URI_CHAR));
+ memcpy(candidate + 3, first, inputLenChars * sizeof(URI_CHAR));
+ candidate[3 + inputLenChars] = _UT('\0');
+
+ /* Parse as an RFC 3986 URI */
+ URI_TYPE(Uri) tempUri;
+ int res = URI_FUNC(ParseSingleUriExMm)(&tempUri, candidate,
+ candidate + candidateLenChars, NULL, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ memory->free(memory, candidate);
+ return res;
+ }
+
+ /* Nothing but path and host is supposed to be set by the parse, in
+ * particular not: */
+ assert(tempUri.query.first == NULL);
+ assert(tempUri.fragment.first == NULL);
+
+ /* Ensure that the strings in the path segments are all owned by
+ * `tempUri` because we want to (1) rip out and keep the full path
+ * list further down and (2) be able to free the parsed string
+ * (`candidate`) also. */
+ res = URI_FUNC(MakeOwnerMm)(&tempUri, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_MALLOC));
+ if (res != URI_SUCCESS) {
+ URI_FUNC(FreeUriMembersMm)(&tempUri, memory);
+ memory->free(memory, candidate);
+ return res;
+ }
+ assert(tempUri.owner == URI_TRUE);
+
+ /* Move path to destination URI */
+ assert(tempUri.absolutePath == URI_FALSE); /* always URI_FALSE for URIs with host */
+ destUri->pathHead = tempUri.pathHead;
+ destUri->pathTail = tempUri.pathTail;
+ destUri->absolutePath = URI_FALSE;
+
+ tempUri.pathHead = NULL;
+ tempUri.pathTail = NULL;
+
+ /* Free the rest of the temp URI */
+ URI_FUNC(FreeUriMembersMm)(&tempUri, memory);
+ memory->free(memory, candidate);
+
+ /* Restore use of .absolutePath as needed */
+ URI_FUNC(TransformEmptyLeadPathSegments)(destUri, memory);
+
+ /* Disambiguate as needed */
+ UriBool success = URI_FUNC(FixPathNoScheme)(destUri, memory);
+ if (success == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ success = URI_FUNC(EnsureThatPathIsNotMistakenForHost)(destUri, memory);
+ if (success == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetPathMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL)
+ && (URI_FUNC(IsWellFormedPath)(first, afterLast, URI_FUNC(HasHost)(uri))
+ == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ int res = URI_FUNC(FreeUriPath)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ uri->absolutePath = URI_FALSE;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ res = URI_FUNC(InternalSetPath)(uri, first, afterLast, memory);
+ assert((res == URI_SUCCESS) || (res == URI_ERROR_SYNTAX)
+ || (res == URI_ERROR_MALLOC));
+ return res;
+}
+
+int URI_FUNC(SetPath)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetPathMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetPort.c b/src/UriSetPort.c
new file mode 100644
index 0000000..5e2160e
--- /dev/null
+++ b/src/UriSetPort.c
@@ -0,0 +1,149 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetPort.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetPort.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedPort)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* NOTE: Grammar reads "port = *DIGIT" which includes the empty string. */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_DIGIT(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetPortTextMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no port without a host. */
+ if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
+ return URI_ERROR_SETPORT_HOST_NOT_SET;
+ }
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedPort)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->portText.first != uri->portText.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->portText.first);
+ }
+ uri->portText.first = NULL;
+ uri->portText.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->portText, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetPortText)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetPortTextMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetQuery.c b/src/UriSetQuery.c
new file mode 100644
index 0000000..4f58c82
--- /dev/null
+++ b/src/UriSetQuery.c
@@ -0,0 +1,172 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetQuery.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetQuery.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedQuery)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * query = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_PCHAR_WITHOUT_PERCENT(_UT):
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case _UT('/'):
+ case _UT('?'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetQueryMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL) && (URI_FUNC(IsWellFormedQuery)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->query.first != uri->query.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->query.first);
+ }
+ uri->query.first = NULL;
+ uri->query.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->query, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetQuery)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetQueryMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetScheme.c b/src/UriSetScheme.c
new file mode 100644
index 0000000..3dfaf1e
--- /dev/null
+++ b/src/UriSetScheme.c
@@ -0,0 +1,168 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetScheme.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetScheme.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedScheme)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* The related part of the grammar in RFC 3986 reads:
+ *
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+ if (first >= afterLast) {
+ return URI_FALSE;
+ }
+
+ switch (first[0]) {
+ case URI_SET_ALPHA(_UT):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_ALPHA(_UT):
+ case URI_SET_DIGIT(_UT):
+ case _UT('+'):
+ case _UT('-'):
+ case _UT('.'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetSchemeMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ if ((first != NULL)
+ && (URI_FUNC(IsWellFormedScheme)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->scheme.first != uri->scheme.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->scheme.first);
+ }
+ uri->scheme.first = NULL;
+ uri->scheme.afterLast = NULL;
+
+ /* Already done setting? */
+ if (first == NULL) {
+ /* Yes, but disambiguate as needed */
+ const UriBool success = URI_FUNC(FixPathNoScheme)(uri, memory);
+ return (success == URI_TRUE) ? URI_SUCCESS : URI_ERROR_MALLOC;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->scheme, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetScheme)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetSchemeMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSetUserInfo.c b/src/UriSetUserInfo.c
new file mode 100644
index 0000000..7865e83
--- /dev/null
+++ b/src/UriSetUserInfo.c
@@ -0,0 +1,180 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriSetUserInfo.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriSetUserInfo.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# include "UriSets.h"
+# endif
+
+# include <assert.h>
+
+UriBool URI_FUNC(IsWellFormedUserInfo)(const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ if ((first == NULL) || (afterLast == NULL)) {
+ return URI_FALSE;
+ }
+
+ /* userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) */
+ while (first < afterLast) {
+ switch (first[0]) {
+ case URI_SET_UNRESERVED(_UT):
+ break;
+
+ /* pct-encoded */
+ case _UT('%'):
+ if (afterLast - first < 3) {
+ return URI_FALSE;
+ }
+ switch (first[1]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ switch (first[2]) {
+ case URI_SET_HEXDIG(_UT):
+ break;
+ default:
+ return URI_FALSE;
+ }
+ first += 2;
+ break;
+
+ case URI_SET_SUB_DELIMS(_UT):
+ break;
+
+ /* ":" */
+ case _UT(':'):
+ break;
+
+ default:
+ return URI_FALSE;
+ }
+
+ first++;
+ }
+ return URI_TRUE;
+}
+
+int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast, UriMemoryManager * memory) {
+ /* Input validation (before making any changes) */
+ if ((uri == NULL) || ((first == NULL) != (afterLast == NULL))) {
+ return URI_ERROR_NULL;
+ }
+
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
+
+ /* The RFC 3986 grammar reads:
+ * authority = [ userinfo "@" ] host [ ":" port ]
+ * So no user info without a host. */
+ if ((first != NULL) && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
+ return URI_ERROR_SETUSERINFO_HOST_NOT_SET;
+ }
+
+ if ((first != NULL)
+ && (URI_FUNC(IsWellFormedUserInfo)(first, afterLast) == URI_FALSE)) {
+ return URI_ERROR_SYNTAX;
+ }
+
+ /* Clear old value */
+ if ((uri->owner == URI_TRUE) && (uri->userInfo.first != uri->userInfo.afterLast)) {
+ memory->free(memory, (URI_CHAR *)uri->userInfo.first);
+ }
+ uri->userInfo.first = NULL;
+ uri->userInfo.afterLast = NULL;
+
+ /* Already done? */
+ if (first == NULL) {
+ return URI_SUCCESS;
+ }
+
+ assert(first != NULL);
+
+ /* Ensure owned */
+ if (uri->owner == URI_FALSE) {
+ const int res = URI_FUNC(MakeOwnerMm)(uri, memory);
+ if (res != URI_SUCCESS) {
+ return res;
+ }
+ }
+
+ assert(uri->owner == URI_TRUE);
+
+ /* Apply new value */
+ URI_TYPE(TextRange) sourceRange;
+ sourceRange.first = first;
+ sourceRange.afterLast = afterLast;
+
+ if (URI_FUNC(CopyRangeAsNeeded)(&uri->userInfo, &sourceRange, memory) == URI_FALSE) {
+ return URI_ERROR_MALLOC;
+ }
+
+ return URI_SUCCESS;
+}
+
+int URI_FUNC(SetUserInfo)(URI_TYPE(Uri) * uri, const URI_CHAR * first,
+ const URI_CHAR * afterLast) {
+ return URI_FUNC(SetUserInfoMm)(uri, first, afterLast, NULL);
+}
+
+#endif
diff --git a/src/UriSets.h b/src/UriSets.h
new file mode 100644
index 0000000..a6a2c46
--- /dev/null
+++ b/src/UriSets.h
@@ -0,0 +1,174 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriSets.h
+ * Holds character set definitions.
+ */
+
+// NOTE: We cannot use a regular include-once guard here because the
+// file must support being included twice, e.g. from file UriParse.c.
+#if !defined(URI_SET_DIGIT)
+
+// clang-format off
+# define URI_SET_DIGIT(ut) \
+ ut('0'): \
+ case ut('1'): \
+ /* clang-format on */ \
+ case ut('2'): \
+ case ut('3'): \
+ case ut('4'): \
+ case ut('5'): \
+ case ut('6'): \
+ case ut('7'): \
+ case ut('8'): \
+ case ut('9')
+
+// clang-format off
+# define URI_SET_HEX_LETTER_LOWER(ut) \
+ ut('a'): \
+ case ut('b'): \
+ /* clang-format on */ \
+ case ut('c'): \
+ case ut('d'): \
+ case ut('e'): \
+ case ut('f')
+
+// clang-format off
+# define URI_SET_HEX_LETTER_UPPER(ut) \
+ ut('A'): \
+ case ut('B'): \
+ /* clang-format on */ \
+ case ut('C'): \
+ case ut('D'): \
+ case ut('E'): \
+ case ut('F')
+
+// clang-format off
+# define URI_SET_HEXDIG(ut) \
+ URI_SET_DIGIT(ut): \
+ case URI_SET_HEX_LETTER_LOWER(ut): \
+ /* clang-format on */ \
+ case URI_SET_HEX_LETTER_UPPER(ut)
+
+// clang-format off
+# define URI_SET_ALPHA(ut) \
+ URI_SET_HEX_LETTER_UPPER(ut): \
+ case URI_SET_HEX_LETTER_LOWER(ut): \
+ /* clang-format on */ \
+ case ut('g'): \
+ case ut('G'): \
+ case ut('h'): \
+ case ut('H'): \
+ case ut('i'): \
+ case ut('I'): \
+ case ut('j'): \
+ case ut('J'): \
+ case ut('k'): \
+ case ut('K'): \
+ case ut('l'): \
+ case ut('L'): \
+ case ut('m'): \
+ case ut('M'): \
+ case ut('n'): \
+ case ut('N'): \
+ case ut('o'): \
+ case ut('O'): \
+ case ut('p'): \
+ case ut('P'): \
+ case ut('q'): \
+ case ut('Q'): \
+ case ut('r'): \
+ case ut('R'): \
+ case ut('s'): \
+ case ut('S'): \
+ case ut('t'): \
+ case ut('T'): \
+ case ut('u'): \
+ case ut('U'): \
+ case ut('v'): \
+ case ut('V'): \
+ case ut('w'): \
+ case ut('W'): \
+ case ut('x'): \
+ case ut('X'): \
+ case ut('y'): \
+ case ut('Y'): \
+ case ut('z'): \
+ case ut('Z')
+
+// clang-format off
+# define URI_SET_SUB_DELIMS(ut) \
+ ut('!'): \
+ case ut('$'): \
+ /* clang-format on */ \
+ case ut('&'): \
+ case ut('\''): \
+ case ut('('): \
+ case ut(')'): \
+ case ut('*'): \
+ case ut('+'): \
+ case ut(','): \
+ case ut(';'): \
+ case ut('=')
+
+// clang-format off
+# define URI_SET_UNRESERVED(ut) \
+ URI_SET_ALPHA(ut): \
+ case URI_SET_DIGIT(ut): \
+ /* clang-format on */ \
+ case ut('-'): \
+ case ut('.'): \
+ case ut('_'): \
+ case ut('~')
+
+// clang-format off
+# define URI_SET_PCHAR_WITHOUT_PERCENT(ut) \
+ URI_SET_UNRESERVED(ut): \
+ case URI_SET_SUB_DELIMS(ut): \
+ /* clang-format on */ \
+ case ut(':'): \
+ case ut('@')
+
+// clang-format off
+# define URI_SET_PCHAR(ut) \
+ URI_SET_PCHAR_WITHOUT_PERCENT(ut): \
+ case ut('%')
+/* clang-format on */
+
+#endif // ! defined(URI_SET_DIGIT)
diff --git a/src/UriShorten.c b/src/UriShorten.c
index d2f8935..548b0b4 100644
--- a/src/UriShorten.c
+++ b/src/UriShorten.c
@@ -41,284 +41,386 @@
#include <uriparser/UriDefsConfig.h>
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
/* Include SELF twice */
-# ifdef URI_ENABLE_ANSI
-# define URI_PASS_ANSI 1
-# include "UriShorten.c"
-# undef URI_PASS_ANSI
-# endif
-# ifdef URI_ENABLE_UNICODE
-# define URI_PASS_UNICODE 1
-# include "UriShorten.c"
-# undef URI_PASS_UNICODE
-# endif
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriShorten.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriShorten.c"
+# undef URI_PASS_UNICODE
+# endif
#else
-# ifdef URI_PASS_ANSI
-# include <uriparser/UriDefsAnsi.h>
-# else
-# include <uriparser/UriDefsUnicode.h>
-# include <wchar.h>
-# endif
-
-
-
-#ifndef URI_DOXYGEN
-# include <uriparser/Uri.h>
-# include "UriCommon.h"
-# include "UriMemory.h"
-#endif
-
-
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# include "UriCommon.h"
+# include "UriMemory.h"
+# endif
static URI_INLINE UriBool URI_FUNC(AppendSegment)(URI_TYPE(Uri) * uri,
- const URI_CHAR * first, const URI_CHAR * afterLast,
- UriMemoryManager * memory) {
- /* Create segment */
- URI_TYPE(PathSegment) * segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
- if (segment == NULL) {
- return URI_FALSE; /* Raises malloc error */
- }
- segment->next = NULL;
- segment->text.first = first;
- segment->text.afterLast = afterLast;
-
- /* Put into chain */
- if (uri->pathTail == NULL) {
- uri->pathHead = segment;
- } else {
- uri->pathTail->next = segment;
- }
- uri->pathTail = segment;
-
- return URI_TRUE;
+ const URI_CHAR * first,
+ const URI_CHAR * afterLast,
+ UriMemoryManager * memory) {
+ /* Create segment */
+ URI_TYPE(PathSegment) * segment =
+ memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
+ if (segment == NULL) {
+ return URI_FALSE; /* Raises malloc error */
+ }
+ segment->next = NULL;
+ segment->text.first = first;
+ segment->text.afterLast = afterLast;
+
+ /* Put into chain */
+ if (uri->pathTail == NULL) {
+ uri->pathHead = segment;
+ } else {
+ uri->pathTail->next = segment;
+ }
+ uri->pathTail = segment;
+
+ return URI_TRUE;
}
-
-
static URI_INLINE UriBool URI_FUNC(EqualsAuthority)(const URI_TYPE(Uri) * first,
- const URI_TYPE(Uri) * second) {
- /* IPv4 */
- if (first->hostData.ip4 != NULL) {
- return ((second->hostData.ip4 != NULL)
- && !memcmp(first->hostData.ip4->data,
- second->hostData.ip4->data, 4)) ? URI_TRUE : URI_FALSE;
- }
-
- /* IPv6 */
- if (first->hostData.ip6 != NULL) {
- return ((second->hostData.ip6 != NULL)
- && !memcmp(first->hostData.ip6->data,
- second->hostData.ip6->data, 16)) ? URI_TRUE : URI_FALSE;
- }
-
- /* IPvFuture */
- if (first->hostData.ipFuture.first != NULL) {
- return ((second->hostData.ipFuture.first != NULL)
- && !URI_FUNC(CompareRange)(&first->hostData.ipFuture,
- &second->hostData.ipFuture)) ? URI_TRUE : URI_FALSE;
- }
-
- return !URI_FUNC(CompareRange)(&first->hostText, &second->hostText)
- ? URI_TRUE : URI_FALSE;
+ const URI_TYPE(Uri) * second) {
+ /* IPv4 */
+ if (first->hostData.ip4 != NULL) {
+ return ((second->hostData.ip4 != NULL)
+ && !memcmp(first->hostData.ip4->data, second->hostData.ip4->data, 4))
+ ? URI_TRUE
+ : URI_FALSE;
+ }
+
+ /* IPv6 */
+ if (first->hostData.ip6 != NULL) {
+ return ((second->hostData.ip6 != NULL)
+ && !memcmp(first->hostData.ip6->data, second->hostData.ip6->data, 16))
+ ? URI_TRUE
+ : URI_FALSE;
+ }
+
+ /* IPvFuture */
+ if (first->hostData.ipFuture.first != NULL) {
+ return ((second->hostData.ipFuture.first != NULL)
+ && !URI_FUNC(CompareRange)(&first->hostData.ipFuture,
+ &second->hostData.ipFuture))
+ ? URI_TRUE
+ : URI_FALSE;
+ }
+
+ return !URI_FUNC(CompareRange)(&first->hostText, &second->hostText) ? URI_TRUE
+ : URI_FALSE;
}
-
-
static int URI_FUNC(RemoveBaseUriImpl)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * absSource,
- const URI_TYPE(Uri) * absBase,
- UriBool domainRootMode, UriMemoryManager * memory) {
- if (dest == NULL) {
- return URI_ERROR_NULL;
- }
- URI_FUNC(ResetUri)(dest);
-
- if ((absSource == NULL) || (absBase == NULL)) {
- return URI_ERROR_NULL;
- }
-
- /* absBase absolute? */
- if (absBase->scheme.first == NULL) {
- return URI_ERROR_REMOVEBASE_REL_BASE;
- }
-
- /* absSource absolute? */
- if (absSource->scheme.first == NULL) {
- return URI_ERROR_REMOVEBASE_REL_SOURCE;
- }
-
- /* [01/50] if (A.scheme != Base.scheme) then */
- if (URI_FUNC(CompareRange)(&absSource->scheme, &absBase->scheme)) {
- /* [02/50] T.scheme = A.scheme; */
- dest->scheme = absSource->scheme;
- /* [03/50] T.authority = A.authority; */
- if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [04/50] T.path = A.path; */
- if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [05/50] else */
- } else {
- /* [06/50] undef(T.scheme); */
- /* NOOP */
- /* [07/50] if (A.authority != Base.authority) then */
- if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) {
- /* [08/50] T.authority = A.authority; */
- if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [09/50] T.path = A.path; */
- if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [10/50] else */
- } else {
- /* [11/50] if domainRootMode then */
- if (domainRootMode == URI_TRUE) {
- /* [12/50] undef(T.authority); */
- /* NOOP */
- /* [13/50] if (first(A.path) == "") then */
- /* GROUPED */
- /* [14/50] T.path = "/." + A.path; */
- /* GROUPED */
- /* [15/50] else */
- /* GROUPED */
- /* [16/50] T.path = A.path; */
- /* GROUPED */
- /* [17/50] endif; */
- if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
- return URI_ERROR_MALLOC;
- }
- dest->absolutePath = URI_TRUE;
-
- if (!URI_FUNC(FixAmbiguity)(dest, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [18/50] else */
- } else {
- const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead;
- const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead;
- /* [19/50] bool pathNaked = true; */
- UriBool pathNaked = URI_TRUE;
- /* [20/50] undef(last(Base.path)); */
- /* NOOP */
- /* [21/50] T.path = ""; */
- dest->absolutePath = URI_FALSE;
- /* [22/50] while (first(A.path) == first(Base.path)) do */
- while ((sourceSeg != NULL) && (baseSeg != NULL)
- && !URI_FUNC(CompareRange)(&sourceSeg->text, &baseSeg->text)
- && !((sourceSeg->text.first == sourceSeg->text.afterLast)
- && ((sourceSeg->next == NULL) != (baseSeg->next == NULL)))) {
- /* [23/50] A.path++; */
- sourceSeg = sourceSeg->next;
- /* [24/50] Base.path++; */
- baseSeg = baseSeg->next;
- /* [25/50] endwhile; */
- }
- /* [26/50] while defined(first(Base.path)) do */
- while ((baseSeg != NULL) && (baseSeg->next != NULL)) {
- /* [27/50] Base.path++; */
- baseSeg = baseSeg->next;
- /* [28/50] T.path += "../"; */
- if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent),
- URI_FUNC(ConstParent) + 2, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [29/50] pathNaked = false; */
- pathNaked = URI_FALSE;
- /* [30/50] endwhile; */
- }
- /* [31/50] while defined(first(A.path)) do */
- while (sourceSeg != NULL) {
- /* [32/50] if pathNaked then */
- if (pathNaked == URI_TRUE) {
- /* [33/50] if (first(A.path) contains ":") then */
- UriBool containsColon = URI_FALSE;
- const URI_CHAR * ch = sourceSeg->text.first;
- for (; ch < sourceSeg->text.afterLast; ch++) {
- if (*ch == _UT(':')) {
- containsColon = URI_TRUE;
- break;
- }
- }
-
- if (containsColon) {
- /* [34/50] T.path += "./"; */
- if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd),
- URI_FUNC(ConstPwd) + 1, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [35/50] elseif (first(A.path) == "") then */
- } else if (sourceSeg->text.first == sourceSeg->text.afterLast) {
- /* [36/50] T.path += "/."; */
- if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstPwd),
- URI_FUNC(ConstPwd) + 1, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [37/50] endif; */
- }
- /* [38/50] endif; */
- }
- /* [39/50] T.path += first(A.path); */
- if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first,
- sourceSeg->text.afterLast, memory)) {
- return URI_ERROR_MALLOC;
- }
- /* [40/50] pathNaked = false; */
- pathNaked = URI_FALSE;
- /* [41/50] A.path++; */
- sourceSeg = sourceSeg->next;
- /* [42/50] if defined(first(A.path)) then */
- /* NOOP */
- /* [43/50] T.path += + "/"; */
- /* NOOP */
- /* [44/50] endif; */
- /* NOOP */
- /* [45/50] endwhile; */
- }
- /* [46/50] endif; */
- }
- /* [47/50] endif; */
- }
- /* [48/50] endif; */
- }
- /* [49/50] T.query = A.query; */
- dest->query = absSource->query;
- /* [50/50] T.fragment = A.fragment; */
- dest->fragment = absSource->fragment;
-
- return URI_SUCCESS;
+ const URI_TYPE(Uri) * absSource,
+ const URI_TYPE(Uri) * absBase,
+ UriBool domainRootMode,
+ UriMemoryManager * memory) {
+ if (dest == NULL) {
+ return URI_ERROR_NULL;
+ }
+ URI_FUNC(ResetUri)(dest);
+
+ if ((absSource == NULL) || (absBase == NULL)) {
+ return URI_ERROR_NULL;
+ }
+
+ /* absBase absolute? */
+ if (absBase->scheme.first == NULL) {
+ return URI_ERROR_REMOVEBASE_REL_BASE;
+ }
+
+ /* absSource absolute? */
+ if (absSource->scheme.first == NULL) {
+ return URI_ERROR_REMOVEBASE_REL_SOURCE;
+ }
+
+ /* NOTE: The curly brackets here force deeper indent (and that's all) */
+ {
+ {
+ {
+ /* clang-format off */
+ /* [01/50] if (A.scheme != Base.scheme) then */
+ /* clang-format on */
+ if (URI_FUNC(CompareRange)(&absSource->scheme, &absBase->scheme)) {
+ /* clang-format off */
+ /* [02/50] T.scheme = A.scheme; */
+ /* clang-format on */
+ dest->scheme = absSource->scheme;
+ /* clang-format off */
+ /* [03/50] T.authority = A.authority; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [04/50] T.path = A.path; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [05/50] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [06/50] undef(T.scheme); */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [07/50] if (A.authority != Base.authority) then */
+ /* clang-format on */
+ if (!URI_FUNC(EqualsAuthority)(absSource, absBase)) {
+ /* clang-format off */
+ /* [08/50] T.authority = A.authority; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyAuthority)(dest, absSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [09/50] T.path = A.path; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [10/50] else */
+ /* clang-format on */
+ } else {
+ /* clang-format off */
+ /* [11/50] if domainRootMode then */
+ /* clang-format on */
+ if (domainRootMode == URI_TRUE) {
+ /* clang-format off */
+ /* [12/50] undef(T.authority); */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [13/50] if (first(A.path) == "") then */
+ /* clang-format on */
+ /* GROUPED */
+ /* clang-format off */
+ /* [14/50] T.path = "/." + A.path; */
+ /* clang-format on */
+ /* GROUPED */
+ /* clang-format off */
+ /* [15/50] else */
+ /* clang-format on */
+ /* GROUPED */
+ /* clang-format off */
+ /* [16/50] T.path = A.path; */
+ /* clang-format on */
+ /* GROUPED */
+ /* clang-format off */
+ /* [17/50] endif; */
+ /* clang-format on */
+ if (!URI_FUNC(CopyPath)(dest, absSource, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ dest->absolutePath = URI_TRUE;
+
+ if (!URI_FUNC(FixAmbiguity)(dest, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [18/50] else */
+ /* clang-format on */
+ } else {
+ const URI_TYPE(PathSegment) * sourceSeg = absSource->pathHead;
+ const URI_TYPE(PathSegment) * baseSeg = absBase->pathHead;
+ /* clang-format off */
+ /* [19/50] bool pathNaked = true; */
+ /* clang-format on */
+ UriBool pathNaked = URI_TRUE;
+ /* clang-format off */
+ /* [20/50] undef(last(Base.path)); */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [21/50] T.path = ""; */
+ /* clang-format on */
+ dest->absolutePath = URI_FALSE;
+ /* clang-format off */
+ /* [22/50] while (first(A.path) == first(Base.path)) do */
+ /* clang-format on */
+ while (
+ (sourceSeg != NULL) && (baseSeg != NULL)
+ && !URI_FUNC(CompareRange)(&sourceSeg->text,
+ &baseSeg->text)
+ && !((sourceSeg->text.first == sourceSeg->text.afterLast)
+ && ((sourceSeg->next == NULL)
+ != (baseSeg->next == NULL)))) {
+ /* clang-format off */
+ /* [23/50] A.path++; */
+ /* clang-format on */
+ sourceSeg = sourceSeg->next;
+ /* clang-format off */
+ /* [24/50] Base.path++; */
+ /* clang-format on */
+ baseSeg = baseSeg->next;
+ /* clang-format off */
+ /* [25/50] endwhile; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [26/50] while defined(first(Base.path)) do */
+ /* clang-format on */
+ while ((baseSeg != NULL) && (baseSeg->next != NULL)) {
+ /* clang-format off */
+ /* [27/50] Base.path++; */
+ /* clang-format on */
+ baseSeg = baseSeg->next;
+ /* clang-format off */
+ /* [28/50] T.path += "../"; */
+ /* clang-format on */
+ if (!URI_FUNC(AppendSegment)(dest, URI_FUNC(ConstParent),
+ URI_FUNC(ConstParent) + 2,
+ memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [29/50] pathNaked = false; */
+ /* clang-format on */
+ pathNaked = URI_FALSE;
+ /* clang-format off */
+ /* [30/50] endwhile; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [31/50] while defined(first(A.path)) do */
+ /* clang-format on */
+ while (sourceSeg != NULL) {
+ /* clang-format off */
+ /* [32/50] if pathNaked then */
+ /* clang-format on */
+ if (pathNaked == URI_TRUE) {
+ /* clang-format off */
+ /* [33/50] if (first(A.path) contains ":") then */
+ /* clang-format on */
+ UriBool containsColon = URI_FALSE;
+ const URI_CHAR * ch = sourceSeg->text.first;
+ for (; ch < sourceSeg->text.afterLast; ch++) {
+ if (*ch == _UT(':')) {
+ containsColon = URI_TRUE;
+ break;
+ }
+ }
+
+ if (containsColon) {
+ /* clang-format off */
+ /* [34/50] T.path += "./"; */
+ /* clang-format on */
+ if (!URI_FUNC(AppendSegment)(
+ dest, URI_FUNC(ConstPwd),
+ URI_FUNC(ConstPwd) + 1, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [35/50] elseif (first(A.path) == "") then */
+ /* clang-format on */
+ } else if (sourceSeg->text.first
+ == sourceSeg->text.afterLast) {
+ /* clang-format off */
+ /* [36/50] T.path += "/."; */
+ /* clang-format on */
+ if (!URI_FUNC(AppendSegment)(
+ dest, URI_FUNC(ConstPwd),
+ URI_FUNC(ConstPwd) + 1, memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [37/50] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [38/50] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [39/50] T.path += first(A.path); */
+ /* clang-format on */
+ if (!URI_FUNC(AppendSegment)(dest, sourceSeg->text.first,
+ sourceSeg->text.afterLast,
+ memory)) {
+ return URI_ERROR_MALLOC;
+ }
+ /* clang-format off */
+ /* [40/50] pathNaked = false; */
+ /* clang-format on */
+ pathNaked = URI_FALSE;
+ /* clang-format off */
+ /* [41/50] A.path++; */
+ /* clang-format on */
+ sourceSeg = sourceSeg->next;
+ /* clang-format off */
+ /* [42/50] if defined(first(A.path)) then */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [43/50] T.path += + "/"; */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [44/50] endif; */
+ /* clang-format on */
+ /* NOOP */
+ /* clang-format off */
+ /* [45/50] endwhile; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [46/50] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [47/50] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [48/50] endif; */
+ /* clang-format on */
+ }
+ /* clang-format off */
+ /* [49/50] T.query = A.query; */
+ /* clang-format on */
+ dest->query = absSource->query;
+ /* clang-format off */
+ /* [50/50] T.fragment = A.fragment; */
+ /* clang-format on */
+ dest->fragment = absSource->fragment;
+ }
+ }
+ }
+ return URI_SUCCESS;
}
-
-
-int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * absSource,
- const URI_TYPE(Uri) * absBase,
- UriBool domainRootMode) {
- return URI_FUNC(RemoveBaseUriMm)(dest, absSource, absBase,
- domainRootMode, NULL);
+int URI_FUNC(RemoveBaseUri)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * absSource,
+ const URI_TYPE(Uri) * absBase, UriBool domainRootMode) {
+ return URI_FUNC(RemoveBaseUriMm)(dest, absSource, absBase, domainRootMode, NULL);
}
+int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * absSource,
+ const URI_TYPE(Uri) * absBase, UriBool domainRootMode,
+ UriMemoryManager * memory) {
+ int res;
+ URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-int URI_FUNC(RemoveBaseUriMm)(URI_TYPE(Uri) * dest,
- const URI_TYPE(Uri) * absSource,
- const URI_TYPE(Uri) * absBase,
- UriBool domainRootMode, UriMemoryManager * memory) {
- int res;
-
- URI_CHECK_MEMORY_MANAGER(memory); /* may return */
-
- res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource,
- absBase, domainRootMode, memory);
- if ((res != URI_SUCCESS) && (dest != NULL)) {
- URI_FUNC(FreeUriMembersMm)(dest, memory);
- }
- return res;
+ res = URI_FUNC(RemoveBaseUriImpl)(dest, absSource, absBase, domainRootMode, memory);
+ if ((res != URI_SUCCESS) && (dest != NULL)) {
+ URI_FUNC(FreeUriMembersMm)(dest, memory);
+ }
+ return res;
}
-
-
#endif
diff --git a/src/UriVersion.c b/src/UriVersion.c
new file mode 100644
index 0000000..5c9a3e3
--- /dev/null
+++ b/src/UriVersion.c
@@ -0,0 +1,81 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of
+ * its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file UriVersion.c
+ * Implements a runtime version getter.
+ * NOTE: This source file includes itself twice.
+ */
+
+/* What encodings are enabled? */
+#include <uriparser/UriDefsConfig.h>
+#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
+/* Include SELF twice */
+# ifdef URI_ENABLE_ANSI
+# define URI_PASS_ANSI 1
+# include "UriVersion.c"
+# undef URI_PASS_ANSI
+# endif
+# ifdef URI_ENABLE_UNICODE
+# define URI_PASS_UNICODE 1
+# include "UriVersion.c"
+# undef URI_PASS_UNICODE
+# endif
+#else
+# ifdef URI_PASS_ANSI
+# include <uriparser/UriDefsAnsi.h>
+# else
+# include <uriparser/UriDefsUnicode.h>
+# include <wchar.h>
+# endif
+
+# ifndef URI_DOXYGEN
+# include <uriparser/Uri.h>
+# endif
+
+const URI_CHAR * URI_FUNC(BaseRuntimeVersion)(void) {
+# if defined(URI_PASS_ANSI)
+ return URI_VER_ANSI;
+# elif defined(URI_PASS_UNICODE)
+ return URI_VER_UNICODE;
+# else
+# error Either URI_PASS_ANSI or URI_PASS_UNICODE must be defined
+# endif
+}
+
+#endif
diff --git a/test/CompareRangeLengthWrap.cpp b/test/CompareRangeLengthWrap.cpp
new file mode 100644
index 0000000..43215bf
--- /dev/null
+++ b/test/CompareRangeLengthWrap.cpp
@@ -0,0 +1,97 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2026, Joshua W. Windle <joshua.w.windle@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <uriparser/Uri.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <cstring>
+
+#if !defined(_WIN32)
+# include <sys/mman.h> // mmap, mprotect, munmap
+# include <unistd.h> // sysconf
+#endif
+
+extern "C" {
+int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b);
+}
+
+#if !defined(_WIN32) && (UINTPTR_MAX > UINT32_MAX)
+namespace {
+static size_t roundUpToPageSize(size_t value, size_t pageSize) {
+ const size_t remainder = value % pageSize;
+ if (remainder == 0U) {
+ return value;
+ }
+
+ const size_t padding = pageSize - remainder;
+ EXPECT_LE(padding, SIZE_MAX - value);
+ return value + padding;
+}
+
+static size_t queryPageSize() {
+ const long pageSize = sysconf(_SC_PAGESIZE);
+ EXPECT_GT(pageSize, 0);
+ return static_cast<size_t>(pageSize);
+}
+} // namespace
+
+TEST(UriSuite, TestRangeComparisonDoesNotWrapLengthChecksOn64Bit) {
+ const size_t hugeLen = (static_cast<size_t>(1) << 32) + 10U;
+ const size_t shortLen = 10U;
+ const size_t pageSize = queryPageSize();
+ const size_t hugeMapLen = roundUpToPageSize(hugeLen, pageSize);
+ const size_t shortMapLen = pageSize * 2U;
+
+ // Reserve a huge virtual range, with access disabled by default.
+ char * const hugeBase = static_cast<char *>(
+ mmap(NULL, hugeMapLen, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ ASSERT_NE(hugeBase, MAP_FAILED);
+ // Allow access to the first page (and that only).
+ ASSERT_EQ(0, mprotect(hugeBase, pageSize, PROT_READ | PROT_WRITE));
+ // Fill the readable prefix so the vulnerable implementation reaches
+ // content comparison after truncating the large length.
+ memset(hugeBase, 'a', pageSize);
+
+ char * const shortBase = static_cast<char *>(mmap(
+ NULL, shortMapLen, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ ASSERT_NE(shortBase, MAP_FAILED);
+ // Guard the following page so any over-read beyond shortLen faults.
+ ASSERT_EQ(0, mprotect(shortBase + pageSize, pageSize, PROT_NONE));
+
+ char * const shortStart = shortBase + pageSize - shortLen;
+ memset(shortStart, 'a', shortLen);
+
+ UriTextRangeA hugeRange;
+ hugeRange.first = hugeBase;
+ hugeRange.afterLast = hugeBase + hugeLen;
+
+ UriTextRangeA shortRange;
+ shortRange.first = shortStart;
+ shortRange.afterLast = shortStart + shortLen;
+
+ const int comparison = uriCompareRangeA(&hugeRange, &shortRange);
+
+ EXPECT_EQ(1, comparison);
+
+ EXPECT_EQ(0, munmap(hugeBase, hugeMapLen));
+ EXPECT_EQ(0, munmap(shortBase, shortMapLen));
+}
+#endif
diff --git a/test/FourSuite.cpp b/test/FourSuite.cpp
index 466a94c..87c671b 100644
--- a/test/FourSuite.cpp
+++ b/test/FourSuite.cpp
@@ -23,610 +23,688 @@
#include <uriparser/Uri.h>
-
-
// All testcases in this file are coming from
// http://cvs.4suite.org/viewcvs/4Suite/test/Lib/test_uri.py
-
namespace {
-bool testAddOrRemoveBaseHelper(const char * ref, const char * base,
- const char * expected, bool add = true, bool domainRootMode = false) {
- UriParserStateA stateA;
-
- // Base
- UriUriA baseUri;
- stateA.uri = &baseUri;
- int res = uriParseUriA(&stateA, base);
- if (res != 0) {
- return false;
- }
-
- // Rel
- UriUriA relUri;
- stateA.uri = &relUri;
- res = uriParseUriA(&stateA, ref);
- if (res != 0) {
- uriFreeUriMembersA(&baseUri);
- return false;
- }
-
- // Expected result
- UriUriA expectedUri;
- stateA.uri = &expectedUri;
- res = uriParseUriA(&stateA, expected);
- if (res != 0) {
- uriFreeUriMembersA(&baseUri);
- uriFreeUriMembersA(&relUri);
- uriFreeUriMembersA(&expectedUri);
- return false;
- }
-
- // Transform
- UriUriA transformedUri;
- if (add) {
- res = uriAddBaseUriA(&transformedUri, &relUri, &baseUri);
- } else {
- res = uriRemoveBaseUriA(&transformedUri, &relUri, &baseUri,
- domainRootMode ? URI_TRUE : URI_FALSE);
- }
- if (res != 0) {
- uriFreeUriMembersA(&baseUri);
- uriFreeUriMembersA(&relUri);
- uriFreeUriMembersA(&expectedUri);
- uriFreeUriMembersA(&transformedUri);
- return false;
- }
-
- const bool equal = (URI_TRUE == uriEqualsUriA(&transformedUri, &expectedUri));
- if (!equal) {
- char transformedUriText[1024 * 8];
- char expectedUriText[1024 * 8];
- uriToStringA(transformedUriText, &transformedUri, 1024 * 8, NULL);
- uriToStringA(expectedUriText, &expectedUri, 1024 * 8, NULL);
- printf("\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, transformedUriText);
- }
-
- uriFreeUriMembersA(&baseUri);
- uriFreeUriMembersA(&relUri);
- uriFreeUriMembersA(&expectedUri);
- uriFreeUriMembersA(&transformedUri);
- return equal;
+bool testAddOrRemoveBaseHelper(const char * ref, const char * base, const char * expected,
+ bool add = true, bool domainRootMode = false) {
+ UriParserStateA stateA;
+
+ // Base
+ UriUriA baseUri;
+ stateA.uri = &baseUri;
+ int res = uriParseUriA(&stateA, base);
+ if (res != 0) {
+ return false;
+ }
+
+ // Rel
+ UriUriA relUri;
+ stateA.uri = &relUri;
+ res = uriParseUriA(&stateA, ref);
+ if (res != 0) {
+ uriFreeUriMembersA(&baseUri);
+ return false;
+ }
+
+ // Expected result
+ UriUriA expectedUri;
+ stateA.uri = &expectedUri;
+ res = uriParseUriA(&stateA, expected);
+ if (res != 0) {
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&relUri);
+ uriFreeUriMembersA(&expectedUri);
+ return false;
+ }
+
+ // Transform
+ UriUriA transformedUri;
+ if (add) {
+ res = uriAddBaseUriA(&transformedUri, &relUri, &baseUri);
+ } else {
+ res = uriRemoveBaseUriA(&transformedUri, &relUri, &baseUri,
+ domainRootMode ? URI_TRUE : URI_FALSE);
+ }
+ if (res != 0) {
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&relUri);
+ uriFreeUriMembersA(&expectedUri);
+ uriFreeUriMembersA(&transformedUri);
+ return false;
+ }
+
+ const bool equal = (URI_TRUE == uriEqualsUriA(&transformedUri, &expectedUri));
+ if (!equal) {
+ char transformedUriText[1024 * 8];
+ char expectedUriText[1024 * 8];
+ uriToStringA(transformedUriText, &transformedUri, 1024 * 8, NULL);
+ uriToStringA(expectedUriText, &expectedUri, 1024 * 8, NULL);
+ printf("\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText,
+ transformedUriText);
+ }
+
+ uriFreeUriMembersA(&baseUri);
+ uriFreeUriMembersA(&relUri);
+ uriFreeUriMembersA(&expectedUri);
+ uriFreeUriMembersA(&transformedUri);
+ return equal;
}
} // namespace
-
TEST(FourSuite, AbsolutizeTestCases) {
- const char * const BASE_URI[] = {
- "http://a/b/c/d;p?q",
- "http://a/b/c/d;p?q=1/2",
- "http://a/b/c/d;p=1/2?q",
- "fred:///s//a/b/c",
- "http:///s//a/b/c"};
-
- // ref, base, exptected
-
- // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../c", "foo:a/b", "foo:c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("foo:.", "foo:a", "foo:"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../../../bar", "zz:abc", "zz:/bar"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../bar", "zz:abc", "zz:/bar"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../../../bar", "zz:abc", "zz:bar"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../bar", "zz:abc", "zz:bar"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("zz:.", "zz:abc", "zz:"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/.", BASE_URI[0], "http://a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/.foo", BASE_URI[0], "http://a/.foo"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(".foo", BASE_URI[0], "http://a/b/c/.foo"));
-
- // http://gbiv.com/protocols/uri/test/rel_examples1.html
- // examples from RFC 2396
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[0], "g:h"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[0], "http://a/b/c/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[0], "http://a/b/c/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[0], "http://a/b/c/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[0], "http://a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[0], "http://g"));
-
- // changed with RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[0], "http://a/b/c/d;p?y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[0], "http://a/b/c/g?y"));
-
- // changed with RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("#s", BASE_URI[0], "http://a/b/c/d;p?q#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[0], "http://a/b/c/g#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y#s", BASE_URI[0], "http://a/b/c/g?y#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[0], "http://a/b/c/;x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[0], "http://a/b/c/g;x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x?y#s", BASE_URI[0], "http://a/b/c/g;x?y#s"));
-
- // changed with RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", BASE_URI[0], "http://a/b/c/d;p?q"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(".", BASE_URI[0], "http://a/b/c/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[0], "http://a/b/c/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("..", BASE_URI[0], "http://a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[0], "http://a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[0], "http://a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../..", BASE_URI[0], "http://a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[0], "http://a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[0], "http://a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[0], "http://a/g")); // http://a/../g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[0], "http://a/g")); // http://a/../../g
-
- // changed with RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/./g", BASE_URI[0], "http://a/g"));
-
- // changed with RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/../g", BASE_URI[0], "http://a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g.", BASE_URI[0], "http://a/b/c/g."));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(".g", BASE_URI[0], "http://a/b/c/.g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g..", BASE_URI[0], "http://a/b/c/g.."));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("..g", BASE_URI[0], "http://a/b/c/..g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./../g", BASE_URI[0], "http://a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g/.", BASE_URI[0], "http://a/b/c/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/./h", BASE_URI[0], "http://a/b/c/g/h"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/../h", BASE_URI[0], "http://a/b/c/h"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[0], "http://a/b/c/g;x=1/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[0], "http://a/b/c/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[0], "http://a/b/c/g?y/./x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[0], "http://a/b/c/g?y/../x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[0], "http://a/b/c/g#s/./x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[0], "http://a/b/c/g#s/../x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http:g", BASE_URI[0], "http:g")); // http://a/b/c/g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http:", BASE_URI[0], "http:")); // BASE_URI[0]
-
- // not sure where this one originated
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/a/b/c/./../../g", BASE_URI[0], "http://a/a/g"));
-
- // http://gbiv.com/protocols/uri/test/rel_examples2.html
- // slashes in base URI's query args
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[1], "http://a/b/c/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[1], "http://a/b/c/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[1], "http://a/b/c/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[1], "http://a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[1], "http://g"));
-
- // changed in RFC 2396bis
- // ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/?y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/d;p?y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[1], "http://a/b/c/g?y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[1], "http://a/b/c/g?y/./x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[1], "http://a/b/c/g?y/../x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[1], "http://a/b/c/g#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[1], "http://a/b/c/g#s/./x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[1], "http://a/b/c/g#s/../x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[1], "http://a/b/c/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[1], "http://a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[1], "http://a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[1], "http://a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[1], "http://a/g"));
-
- // http://gbiv.com/protocols/uri/test/rel_examples3.html
- // slashes in path params
- // all of these changed in RFC 2396bis
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[2], "http://a/b/c/d;p=1/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[2], "http://a/b/c/d;p=1/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[2], "http://a/b/c/d;p=1/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[2], "http://a/b/c/d;p=1/g?y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[2], "http://a/b/c/d;p=1/;x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[2], "http://a/b/c/d;p=1/g;x"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[2], "http://a/b/c/d;p=1/g;x=1/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[2], "http://a/b/c/d;p=1/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[2], "http://a/b/c/d;p=1/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[2], "http://a/b/c/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[2], "http://a/b/c/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[2], "http://a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[2], "http://a/b/g"));
-
- // http://gbiv.com/protocols/uri/test/rel_examples4.html
- // double and triple slash, unknown scheme
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[3], "g:h"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[3], "fred:///s//a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[3], "fred:///s//a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[3], "fred:///s//a/b/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[3], "fred:///g")); // may change to fred:///s//a/g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[3], "fred://g")); // may change to fred:///s//g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[3], "fred://g/x")); // may change to fred:///s//g/x
- ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[3], "fred:///g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[3], "fred:///s//a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[3], "fred:///s//a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[3], "fred:///s//a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[3], "fred:///s//")); // may change to fred:///s//a/../
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[3], "fred:///s//g")); // may change to fred:///s//a/../g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[3], "fred:///s/g")); // may change to fred:///s//a/../../g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[3], "fred:///g")); // may change to fred:///s//a/../../../g
-
- // http://gbiv.com/protocols/uri/test/rel_examples5.html
- // double and triple slash, well-known scheme
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[4], "g:h"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[4], "http:///s//a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[4], "http:///s//a/b/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[4], "http:///s//a/b/g/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[4], "http:///g")); // may change to http:///s//a/g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[4], "http://g")); // may change to http:///s//g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[4], "http://g/x")); // may change to http:///s//g/x
- ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[4], "http:///g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[4], "http:///s//a/b/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[4], "http:///s//a/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[4], "http:///s//a/g"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[4], "http:///s//")); // may change to http:///s//a/../
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[4], "http:///s//g")); // may change to http:///s//a/../g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[4], "http:///s/g")); // may change to http:///s//a/../../g
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[4], "http:///g")); // may change to http:///s//a/../../../g
-
- // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py
- ASSERT_TRUE(testAddOrRemoveBaseHelper("bar:abc", "foo:xyz", "bar:abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "http://example/x/y/z", "http://example/x/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/x/abc", "http://example2/x/y/z", "http://example/x/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "http://ex/x/y/z", "http://ex/x/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "http://ex/x/y", "http://ex/x/q/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "http://ex/x/y", "http://ex/x/q/r#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y", "http://ex/x/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/", "http://ex/x/y/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/pdq", "http://ex/x/y/pdq"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "http://ex/x/y/", "http://ex/x/y/z/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("#Animal", "file:/swap/test/animal.rdf", "file:/swap/test/animal.rdf#Animal"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "file:/e/x/y/z", "file:/e/x/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/example/x/abc", "file:/example2/x/y/z", "file:/example/x/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "file:/ex/x/y/z", "file:/ex/x/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/r", "file:/ex/x/y/z", "file:/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "file:/ex/x/y", "file:/ex/x/q/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#", "file:/ex/x/y", "file:/ex/x/q/r#"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y", "file:/ex/x/y"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/", "file:/ex/x/y/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "file:/ex/x/y/", "file:/ex/x/y/z/"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", "file:/devel/WWW/2000/10/swap/test/reluri-1.n3", "file://meetings.example.com/cal#m1"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1", "file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3", "file://meetings.example.com/cal#m1"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./#blort", "file:/some/dir/foo", "file:/some/dir/#blort"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./#", "file:/some/dir/foo", "file:/some/dir/#"));
-
- // Ryan Lee
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./", "http://example/x/abc.efg", "http://example/x/"));
-
- // Graham Klyne's tests
- // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls
- // 01-31 are from Connelly's cases
-
- // 32-49
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./q:r", "http://ex/x/y", "http://ex/x/q:r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("?pp/rr", "http://ex/x/y?pp/qq", "http://ex/x/y?pp/rr"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("local/qual@domain.org#frag", "mailto:local", "mailto:local/qual@domain.org#frag"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("more/qual2@domain2.org#frag", "mailto:local/qual1@domain1.org", "mailto:local/more/qual2@domain2.org#frag"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("y?q", "http://ex/x/y?q", "http://ex/x/y?q"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/x/y?q", "http://ex?p", "http://ex/x/y?q"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("c/d", "foo:a/b", "foo:a/c/d"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/c/d", "foo:a/b", "foo:/c/d"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("", "foo:a/b?c#d", "foo:a/b?c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c", "foo:a", "foo:b/c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:/a/y/z", "foo:/a/b/c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("./b/c", "foo:a", "foo:b/c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/./b/c", "foo:a", "foo:/b/c"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../d", "foo://a//b/c", "foo://a/d"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper(".", "foo:a", "foo:"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("..", "foo:a", "foo:"));
-
- // 50-57 (cf. TimBL comments --
- // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html,
- // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html)
- ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x/y%2Fz", "http://example/x/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../../x%2Fabc", "http://example/a/x/y/z", "http://example/a/x%2Fabc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../x%2Fabc", "http://example/a/x/y%2Fz", "http://example/a/x%2Fabc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x%2Fy/z", "http://example/x%2Fy/abc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y/z", "http://example/x%2Fabc"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz", "http://example/x%2Fabc"));
-
- // 70-77
- ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1", "mailto:local2@domain2?query2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2", "mailto:local1@domain1?query1", "mailto:local2@domain2?query2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("local@domain?query2", "mailto:?query1", "mailto:local@domain?query2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1", "mailto:local@domain?query2"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b?c/../d", "foo:bar", "http://example/a/b?c/../d"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b#c/../d", "foo:bar", "http://example/a/b#c/../d"));
-
- // 82-88
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http://example.org/base/uri", "http:this"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http:base", "http:this"));
- // Whole in the URI spec, see http://lists.w3.org/Archives/Public/uri/2007Aug/0003.html
- // ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f://g")); // ORIGINAL
- ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f:/.//g")); // FIXED ONE
- ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c//d/e", "f://example.org/base/a", "f://example.org/base/b/c//d/e"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("m2@example.ord/c2@example.org", "mid:m@example.ord/c@example.org", "mid:m@example.ord/m2@example.ord/c2@example.org"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("mini1.xml", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml"));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:a/y/z", "foo:a/b/c"));
+ const char * const BASE_URI[] = {"http://a/b/c/d;p?q", "http://a/b/c/d;p?q=1/2",
+ "http://a/b/c/d;p=1/2?q", "fred:///s//a/b/c",
+ "http:///s//a/b/c"};
+
+ // ref, base, expected
+
+ // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../c", "foo:a/b", "foo:c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("foo:.", "foo:a", "foo:"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../../../bar", "zz:abc", "zz:/bar"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/foo/../bar", "zz:abc", "zz:/bar"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../../../bar", "zz:abc", "zz:bar"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("foo/../bar", "zz:abc", "zz:bar"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("zz:.", "zz:abc", "zz:"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/.", BASE_URI[0], "http://a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/.foo", BASE_URI[0], "http://a/.foo"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(".foo", BASE_URI[0], "http://a/b/c/.foo"));
+
+ // http://gbiv.com/protocols/uri/test/rel_examples1.html
+ // examples from RFC 2396
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[0], "g:h"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[0], "http://a/b/c/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[0], "http://a/b/c/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[0], "http://a/b/c/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[0], "http://a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[0], "http://g"));
+
+ // changed with RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[0], "http://a/b/c/d;p?y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[0], "http://a/b/c/g?y"));
+
+ // changed with RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("#s", BASE_URI[0], "http://a/b/c/d;p?q#s"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[0], "http://a/b/c/g#s"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y#s", BASE_URI[0], "http://a/b/c/g?y#s"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[0], "http://a/b/c/;x"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[0], "http://a/b/c/g;x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g;x?y#s", BASE_URI[0], "http://a/b/c/g;x?y#s"));
+
+ // changed with RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", BASE_URI[0], "http://a/b/c/d;p?q"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(".", BASE_URI[0], "http://a/b/c/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[0], "http://a/b/c/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("..", BASE_URI[0], "http://a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[0], "http://a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[0], "http://a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../..", BASE_URI[0], "http://a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[0], "http://a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[0], "http://a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../g", BASE_URI[0],
+ "http://a/g")); // http://a/../g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../../../g", BASE_URI[0],
+ "http://a/g")); // http://a/../../g
+
+ // changed with RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/./g", BASE_URI[0], "http://a/g"));
+
+ // changed with RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/../g", BASE_URI[0], "http://a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g.", BASE_URI[0], "http://a/b/c/g."));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(".g", BASE_URI[0], "http://a/b/c/.g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g..", BASE_URI[0], "http://a/b/c/g.."));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("..g", BASE_URI[0], "http://a/b/c/..g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./../g", BASE_URI[0], "http://a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g/.", BASE_URI[0], "http://a/b/c/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/./h", BASE_URI[0], "http://a/b/c/g/h"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/../h", BASE_URI[0], "http://a/b/c/h"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[0], "http://a/b/c/g;x=1/y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[0], "http://a/b/c/y"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[0], "http://a/b/c/g?y/./x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[0], "http://a/b/c/g?y/../x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[0], "http://a/b/c/g#s/./x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[0], "http://a/b/c/g#s/../x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("http:g", BASE_URI[0], "http:g")); // http://a/b/c/g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http:", BASE_URI[0], "http:")); // BASE_URI[0]
+
+ // not sure where this one originated
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("/a/b/c/./../../g", BASE_URI[0], "http://a/a/g"));
+
+ // http://gbiv.com/protocols/uri/test/rel_examples2.html
+ // slashes in base URI's query args
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[1], "http://a/b/c/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[1], "http://a/b/c/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[1], "http://a/b/c/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[1], "http://a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[1], "http://g"));
+
+ // changed in RFC 2396bis
+ // ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/?y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("?y", BASE_URI[1], "http://a/b/c/d;p?y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[1], "http://a/b/c/g?y"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g?y/./x", BASE_URI[1], "http://a/b/c/g?y/./x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g?y/../x", BASE_URI[1], "http://a/b/c/g?y/../x"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g#s", BASE_URI[1], "http://a/b/c/g#s"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g#s/./x", BASE_URI[1], "http://a/b/c/g#s/./x"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g#s/../x", BASE_URI[1], "http://a/b/c/g#s/../x"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[1], "http://a/b/c/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[1], "http://a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[1], "http://a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[1], "http://a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[1], "http://a/g"));
+
+ // http://gbiv.com/protocols/uri/test/rel_examples3.html
+ // slashes in path params
+ // all of these changed in RFC 2396bis
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[2], "http://a/b/c/d;p=1/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[2], "http://a/b/c/d;p=1/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[2], "http://a/b/c/d;p=1/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g?y", BASE_URI[2], "http://a/b/c/d;p=1/g?y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(";x", BASE_URI[2], "http://a/b/c/d;p=1/;x"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x", BASE_URI[2], "http://a/b/c/d;p=1/g;x"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g;x=1/./y", BASE_URI[2],
+ "http://a/b/c/d;p=1/g;x=1/y"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("g;x=1/../y", BASE_URI[2], "http://a/b/c/d;p=1/y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[2], "http://a/b/c/d;p=1/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[2], "http://a/b/c/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[2], "http://a/b/c/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../", BASE_URI[2], "http://a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../g", BASE_URI[2], "http://a/b/g"));
+
+ // http://gbiv.com/protocols/uri/test/rel_examples4.html
+ // double and triple slash, unknown scheme
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[3], "g:h"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[3], "fred:///s//a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[3], "fred:///s//a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[3], "fred:///s//a/b/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[3],
+ "fred:///g")); // may change to fred:///s//a/g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[3],
+ "fred://g")); // may change to fred:///s//g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[3],
+ "fred://g/x")); // may change to fred:///s//g/x
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[3], "fred:///g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[3], "fred:///s//a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[3], "fred:///s//a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[3], "fred:///s//a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../", BASE_URI[3], "fred:///s//")); // may change to fred:///s//a/../
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../g", BASE_URI[3], "fred:///s//g")); // may change to fred:///s//a/../g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../../g", BASE_URI[3], "fred:///s/g")); // may change to fred:///s//a/../../g
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("../../../../g", BASE_URI[3],
+ "fred:///g")); // may change to fred:///s//a/../../../g
+
+ // http://gbiv.com/protocols/uri/test/rel_examples5.html
+ // double and triple slash, well-known scheme
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g:h", BASE_URI[4], "g:h"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g", BASE_URI[4], "http:///s//a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./g", BASE_URI[4], "http:///s//a/b/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("g/", BASE_URI[4], "http:///s//a/b/g/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/g", BASE_URI[4],
+ "http:///g")); // may change to http:///s//a/g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g", BASE_URI[4],
+ "http://g")); // may change to http:///s//g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("//g/x", BASE_URI[4],
+ "http://g/x")); // may change to http:///s//g/x
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("///g", BASE_URI[4], "http:///g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./", BASE_URI[4], "http:///s//a/b/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../", BASE_URI[4], "http:///s//a/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../g", BASE_URI[4], "http:///s//a/g"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../", BASE_URI[4], "http:///s//")); // may change to http:///s//a/../
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../g", BASE_URI[4], "http:///s//g")); // may change to http:///s//a/../g
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "../../../g", BASE_URI[4], "http:///s/g")); // may change to http:///s//a/../../g
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("../../../../g", BASE_URI[4],
+ "http:///g")); // may change to http:///s//a/../../../g
+
+ // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("bar:abc", "foo:xyz", "bar:abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "http://example/x/y/z",
+ "http://example/x/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/x/abc", "http://example2/x/y/z",
+ "http://example/x/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "http://ex/x/y/z", "http://ex/x/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "http://ex/x/y", "http://ex/x/q/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "http://ex/x/y", "http://ex/x/q/r#s"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("q/r#s/t", "http://ex/x/y", "http://ex/x/q/r#s/t"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "http://ex/x/y", "ftp://ex/x/q/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y", "http://ex/x/y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/", "http://ex/x/y/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "http://ex/x/y/pdq", "http://ex/x/y/pdq"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "http://ex/x/y/", "http://ex/x/y/z/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("#Animal", "file:/swap/test/animal.rdf",
+ "file:/swap/test/animal.rdf#Animal"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../abc", "file:/e/x/y/z", "file:/e/x/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/example/x/abc", "file:/example2/x/y/z",
+ "file:/example/x/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../r", "file:/ex/x/y/z", "file:/ex/x/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/r", "file:/ex/x/y/z", "file:/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r", "file:/ex/x/y", "file:/ex/x/q/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#s", "file:/ex/x/y", "file:/ex/x/q/r#s"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q/r#", "file:/ex/x/y", "file:/ex/x/q/r#"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("q/r#s/t", "file:/ex/x/y", "file:/ex/x/q/r#s/t"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("ftp://ex/x/q/r", "file:/ex/x/y", "ftp://ex/x/q/r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y", "file:/ex/x/y"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/", "file:/ex/x/y/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "file:/ex/x/y/pdq", "file:/ex/x/y/pdq"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("z/", "file:/ex/x/y/", "file:/ex/x/y/z/"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("file://meetings.example.com/cal#m1",
+ "file:/devel/WWW/2000/10/swap/test/reluri-1.n3",
+ "file://meetings.example.com/cal#m1"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "file://meetings.example.com/cal#m1",
+ "file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3",
+ "file://meetings.example.com/cal#m1"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./#blort", "file:/some/dir/foo",
+ "file:/some/dir/#blort"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("./#", "file:/some/dir/foo", "file:/some/dir/#"));
+
+ // Ryan Lee
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("./", "http://example/x/abc.efg", "http://example/x/"));
+
+ // Graham Klyne's tests
+ // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls
+ // 01-31 are from Connelly's cases
+
+ // 32-49
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./q:r", "http://ex/x/y", "http://ex/x/q:r"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("./p=q:r", "http://ex/x/y", "http://ex/x/p=q:r"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("?pp/rr", "http://ex/x/y?pp/qq",
+ "http://ex/x/y?pp/rr"));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("y/z", "http://ex/x/y?pp/qq", "http://ex/x/y/z"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("local/qual@domain.org#frag", "mailto:local",
+ "mailto:local/qual@domain.org#frag"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("more/qual2@domain2.org#frag",
+ "mailto:local/qual1@domain1.org",
+ "mailto:local/more/qual2@domain2.org#frag"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("y?q", "http://ex/x/y?q", "http://ex/x/y?q"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/x/y?q", "http://ex?p", "http://ex/x/y?q"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("c/d", "foo:a/b", "foo:a/c/d"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/c/d", "foo:a/b", "foo:/c/d"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("", "foo:a/b?c#d", "foo:a/b?c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c", "foo:a", "foo:b/c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:/a/y/z", "foo:/a/b/c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("./b/c", "foo:a", "foo:b/c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/./b/c", "foo:a", "foo:/b/c"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../d", "foo://a//b/c", "foo://a/d"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(".", "foo:a", "foo:"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("..", "foo:a", "foo:"));
+
+ // 50-57 (cf. TimBL comments --
+ // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html,
+ // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html)
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x/y%2Fz",
+ "http://example/x/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../../x%2Fabc", "http://example/a/x/y/z",
+ "http://example/a/x%2Fabc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../x%2Fabc", "http://example/a/x/y%2Fz",
+ "http://example/a/x%2Fabc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("abc", "http://example/x%2Fy/z",
+ "http://example/x%2Fy/abc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("q%3Ar", "http://ex/x/y", "http://ex/x/q%3Ar"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz",
+ "http://example/x%2Fabc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y/z",
+ "http://example/x%2Fabc"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("/x%2Fabc", "http://example/x/y%2Fz",
+ "http://example/x%2Fabc"));
+
+ // 70-77
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "local2@domain2", "mailto:local1@domain1?query1", "mailto:local2@domain2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2",
+ "mailto:local1@domain1",
+ "mailto:local2@domain2?query2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("local2@domain2?query2",
+ "mailto:local1@domain1?query1",
+ "mailto:local2@domain2?query2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1",
+ "mailto:local@domain?query2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("local@domain?query2", "mailto:?query1",
+ "mailto:local@domain?query2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("?query2", "mailto:local@domain?query1",
+ "mailto:local@domain?query2"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b?c/../d", "foo:bar",
+ "http://example/a/b?c/../d"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http://example/a/b#c/../d", "foo:bar",
+ "http://example/a/b#c/../d"));
+
+ // 82-88
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http://example.org/base/uri",
+ "http:this"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("http:this", "http:base", "http:this"));
+ // Whole in the URI spec, see
+ // http://lists.w3.org/Archives/Public/uri/2007Aug/0003.html
+ // ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f://g")); // ORIGINAL
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(".//g", "f:/a", "f:/.//g")); // FIXED ONE
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("b/c//d/e", "f://example.org/base/a",
+ "f://example.org/base/b/c//d/e"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "m2@example.ord/c2@example.org", "mid:m@example.ord/c@example.org",
+ "mid:m@example.ord/m2@example.ord/c2@example.org"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper(
+ "mini1.xml", "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/",
+ "file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml"));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("../b/c", "foo:a/y/z", "foo:a/b/c"));
}
-
-
TEST(FourSuite, RelativizeTestCases) {
- const bool REMOVE_MODE = false;
- const bool DOMAIN_ROOT_MODE = true;
-
- // to convert, base, exptected
-
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d", "b/c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/b/c", "s://ex/a/d", "/b/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/b/", "c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://other.ex/a/b/", "s://ex/a/d", "//other.ex/a/b/", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://other.ex/a/d", "//ex/a/b/c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("t://ex/a/b/c", "s://ex/a/d", "t://ex/a/b/c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "t://ex/a/d", "s://ex/a/b/c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a", "s://ex/b/c/d", "/a", REMOVE_MODE, DOMAIN_ROOT_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/c/d", "s://ex/a", "b/c/d", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h", "s://ex/a/d?w", "b/c?h", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c#h", "s://ex/a/d#w", "b/c#h", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h#i", "s://ex/a/d?w#j", "b/c?h#i", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a#i", "s://ex/a", "#i", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a?i", "s://ex/a", "?i", REMOVE_MODE));
-
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/b/", "", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a/b", "", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/", "s://ex/", "", REMOVE_MODE));
-
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d/c", "../b/c", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/", "s://ex/a/d/c", "../b/c/", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/d", "s://ex/a/d/c/d", "../../b/c/d", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/d/e/f", "/a/b/c", REMOVE_MODE, DOMAIN_ROOT_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/c/d/e", "../../b/", REMOVE_MODE));
-
- // Some tests to ensure that empty path segments don't cause problems.
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a//b/c", "../../b", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a///b", "s://ex/a/", ".///b", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/", "s://ex/a///b", "../../", REMOVE_MODE));
- ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a//b/c", "s://ex/a/b", ".//b/c", REMOVE_MODE));
+ const bool REMOVE_MODE = false;
+ const bool DOMAIN_ROOT_MODE = true;
+
+ // to convert, base, expected
+
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d", "b/c", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/b/b/c", "s://ex/a/d", "/b/b/c",
+ REMOVE_MODE, DOMAIN_ROOT_MODE));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/b/", "c", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://other.ex/a/b/", "s://ex/a/d",
+ "//other.ex/a/b/", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://other.ex/a/d",
+ "//ex/a/b/c", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("t://ex/a/b/c", "s://ex/a/d", "t://ex/a/b/c",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "t://ex/a/d", "s://ex/a/b/c",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a", "s://ex/b/c/d", "/a", REMOVE_MODE,
+ DOMAIN_ROOT_MODE));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/b/c/d", "s://ex/a", "b/c/d", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h", "s://ex/a/d?w", "b/c?h",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c#h", "s://ex/a/d#w", "b/c#h",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c?h#i", "s://ex/a/d?w#j", "b/c?h#i",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a#i", "s://ex/a", "#i", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a?i", "s://ex/a", "?i", REMOVE_MODE));
+
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/b/", "", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a/b", "", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/", "s://ex/", "", REMOVE_MODE));
+
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/a/d/c", "../b/c", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/", "s://ex/a/d/c", "../b/c/",
+ REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c/d", "s://ex/a/d/c/d",
+ "../../b/c/d", REMOVE_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/c", "s://ex/d/e/f", "/a/b/c",
+ REMOVE_MODE, DOMAIN_ROOT_MODE));
+ ASSERT_TRUE(testAddOrRemoveBaseHelper("s://ex/a/b/", "s://ex/a/c/d/e", "../../b/",
+ REMOVE_MODE));
+
+ // Some tests to ensure that empty path segments don't cause problems.
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a/b", "s://ex/a//b/c", "../../b", REMOVE_MODE));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a///b", "s://ex/a/", ".///b", REMOVE_MODE));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a/", "s://ex/a///b", "../../", REMOVE_MODE));
+ ASSERT_TRUE(
+ testAddOrRemoveBaseHelper("s://ex/a//b/c", "s://ex/a/b", ".//b/c", REMOVE_MODE));
}
-
namespace {
int testParseUri(const char * uriText, const char ** expectedErrorPos = NULL) {
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
- int res = uriParseUriA(&state, uriText);
- if (expectedErrorPos != NULL) {
- *expectedErrorPos = state.errorPos;
- }
- uriFreeUriMembersA(&uri);
- return res;
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+ int res = uriParseUriA(&state, uriText);
+ if (expectedErrorPos != NULL) {
+ *expectedErrorPos = state.errorPos;
+ }
+ uriFreeUriMembersA(&uri);
+ return res;
}
-
-
bool testGoodUri(const char * uriText) {
- return (testParseUri(uriText) == 0);
+ return (testParseUri(uriText) == 0);
}
-
-
bool testBadUri(const char * uriText, int expectedErrorOffset = -1) {
- const char * errorPos = NULL;
- const int ret = testParseUri(uriText, &errorPos);
- return ((ret == URI_ERROR_SYNTAX)
- && (errorPos != NULL)
- && (
- (expectedErrorOffset == -1)
- || (errorPos == (uriText + expectedErrorOffset))
- ));
+ const char * errorPos = NULL;
+ const int ret = testParseUri(uriText, &errorPos);
+ return ((ret == URI_ERROR_SYNTAX) && (errorPos != NULL)
+ && ((expectedErrorOffset == -1)
+ || (errorPos == (uriText + expectedErrorOffset))));
}
} // namespace
-
-
TEST(FourSuite, GoodUriReferences) {
- ASSERT_TRUE(testGoodUri("file:///foo/bar"));
- ASSERT_TRUE(testGoodUri("mailto:user@host?subject=blah"));
- ASSERT_TRUE(testGoodUri("dav:")); // empty opaque part / rel-path allowed by RFC 2396bis
- ASSERT_TRUE(testGoodUri("about:")); // empty opaque part / rel-path allowed by RFC 2396bis
-
- // the following test cases are from a Perl script by David A. Wheeler
- // at http://www.dwheeler.com/secure-programs/url.pl
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/"));
- ASSERT_TRUE(testGoodUri("http://1.2.3.4/"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff/"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%20world/"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi+wan&status=jedi"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?onery"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com#bottom"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#bottom"));
- ASSERT_TRUE(testGoodUri("https://www.yahoo.com/"));
- ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/"));
- ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/hello"));
- ASSERT_TRUE(testGoodUri("demo.txt"));
- ASSERT_TRUE(testGoodUri("demo/hello.txt"));
- ASSERT_TRUE(testGoodUri("demo/hello.txt?query=hello#fragment"));
- ASSERT_TRUE(testGoodUri("/cgi-bin/query?query=hello#fragment"));
- ASSERT_TRUE(testGoodUri("/demo.txt"));
- ASSERT_TRUE(testGoodUri("/hello/demo.txt"));
- ASSERT_TRUE(testGoodUri("hello/demo.txt"));
- ASSERT_TRUE(testGoodUri("/"));
- ASSERT_TRUE(testGoodUri(""));
- ASSERT_TRUE(testGoodUri("#"));
- ASSERT_TRUE(testGoodUri("#here"));
-
- // Wheeler's script says these are invalid, but they aren't
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=%00%01"));
- ASSERT_TRUE(testGoodUri("http://www.yaho%6f.com"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%00world/"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello+world/"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&"));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&type="));
- ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#"));
- ASSERT_TRUE(testGoodUri("//"));
-
- // the following test cases are from a Haskell program by Graham Klyne
- // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs
- ASSERT_TRUE(testGoodUri("http://example.org/aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("mailto:local@domain.org"));
- ASSERT_TRUE(testGoodUri("mailto:local@domain.org#frag"));
- ASSERT_TRUE(testGoodUri("HTTP://EXAMPLE.ORG/AAA/BBB#CCC"));
- ASSERT_TRUE(testGoodUri("//example.org/aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("/aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("bbb#ccc"));
- ASSERT_TRUE(testGoodUri("#ccc"));
- ASSERT_TRUE(testGoodUri("#"));
- ASSERT_TRUE(testGoodUri("A'C"));
-
- // escapes
- ASSERT_TRUE(testGoodUri("http://example.org/aaa%2fbbb#ccc"));
- ASSERT_TRUE(testGoodUri("http://example.org/aaa%2Fbbb#ccc"));
- ASSERT_TRUE(testGoodUri("%2F"));
- ASSERT_TRUE(testGoodUri("aaa%2Fbbb"));
-
- // ports
- ASSERT_TRUE(testGoodUri("http://example.org:80/aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("http://example.org:/aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("http://example.org./aaa/bbb#ccc"));
- ASSERT_TRUE(testGoodUri("http://example.123./aaa/bbb#ccc"));
-
- // bare authority
- ASSERT_TRUE(testGoodUri("http://example.org"));
-
- // IPv6 literals (from RFC2732):
- ASSERT_TRUE(testGoodUri("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html"));
- ASSERT_TRUE(testGoodUri("http://[1080:0:0:0:8:800:200C:417A]/index.html"));
- ASSERT_TRUE(testGoodUri("http://[3ffe:2a00:100:7031::1]"));
- ASSERT_TRUE(testGoodUri("http://[1080::8:800:200C:417A]/foo"));
- ASSERT_TRUE(testGoodUri("http://[::192.9.5.5]/ipng"));
- ASSERT_TRUE(testGoodUri("http://[::FFFF:129.144.52.38]:80/index.html"));
- ASSERT_TRUE(testGoodUri("http://[2010:836B:4179::836B:4179]"));
- ASSERT_TRUE(testGoodUri("//[2010:836B:4179::836B:4179]"));
-
- // Random other things that crop up
- ASSERT_TRUE(testGoodUri("http://example/Andr&#567;"));
- ASSERT_TRUE(testGoodUri("file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/"));
+ ASSERT_TRUE(testGoodUri("file:///foo/bar"));
+ ASSERT_TRUE(testGoodUri("mailto:user@host?subject=blah"));
+ ASSERT_TRUE(
+ testGoodUri("dav:")); // empty opaque part / rel-path allowed by RFC 2396bis
+ ASSERT_TRUE(
+ testGoodUri("about:")); // empty opaque part / rel-path allowed by RFC 2396bis
+
+ // the following test cases are from a Perl script by David A. Wheeler
+ // at http://www.dwheeler.com/secure-programs/url.pl
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/"));
+ ASSERT_TRUE(testGoodUri("http://1.2.3.4/"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/stuff/"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%20world/"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi+wan&status=jedi"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?onery"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com#bottom"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#bottom"));
+ ASSERT_TRUE(testGoodUri("https://www.yahoo.com/"));
+ ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/"));
+ ASSERT_TRUE(testGoodUri("ftp://www.yahoo.com/hello"));
+ ASSERT_TRUE(testGoodUri("demo.txt"));
+ ASSERT_TRUE(testGoodUri("demo/hello.txt"));
+ ASSERT_TRUE(testGoodUri("demo/hello.txt?query=hello#fragment"));
+ ASSERT_TRUE(testGoodUri("/cgi-bin/query?query=hello#fragment"));
+ ASSERT_TRUE(testGoodUri("/demo.txt"));
+ ASSERT_TRUE(testGoodUri("/hello/demo.txt"));
+ ASSERT_TRUE(testGoodUri("hello/demo.txt"));
+ ASSERT_TRUE(testGoodUri("/"));
+ ASSERT_TRUE(testGoodUri(""));
+ ASSERT_TRUE(testGoodUri("#"));
+ ASSERT_TRUE(testGoodUri("#here"));
+
+ // Wheeler's script says these are invalid, but they aren't
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=%00%01"));
+ ASSERT_TRUE(testGoodUri("http://www.yaho%6f.com"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello%00world/"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/hello+world/"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&"));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com?name=obi&type="));
+ ASSERT_TRUE(testGoodUri("http://www.yahoo.com/yelp.html#"));
+ ASSERT_TRUE(testGoodUri("//"));
+
+ // the following test cases are from a Haskell program by Graham Klyne
+ // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs
+ ASSERT_TRUE(testGoodUri("http://example.org/aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("mailto:local@domain.org"));
+ ASSERT_TRUE(testGoodUri("mailto:local@domain.org#frag"));
+ ASSERT_TRUE(testGoodUri("HTTP://EXAMPLE.ORG/AAA/BBB#CCC"));
+ ASSERT_TRUE(testGoodUri("//example.org/aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("/aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("#ccc"));
+ ASSERT_TRUE(testGoodUri("#"));
+ ASSERT_TRUE(testGoodUri("A'C"));
+
+ // escapes
+ ASSERT_TRUE(testGoodUri("http://example.org/aaa%2fbbb#ccc"));
+ ASSERT_TRUE(testGoodUri("http://example.org/aaa%2Fbbb#ccc"));
+ ASSERT_TRUE(testGoodUri("%2F"));
+ ASSERT_TRUE(testGoodUri("aaa%2Fbbb"));
+
+ // ports
+ ASSERT_TRUE(testGoodUri("http://example.org:80/aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("http://example.org:/aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("http://example.org./aaa/bbb#ccc"));
+ ASSERT_TRUE(testGoodUri("http://example.123./aaa/bbb#ccc"));
+
+ // bare authority
+ ASSERT_TRUE(testGoodUri("http://example.org"));
+
+ // IPv6 literals (from RFC2732):
+ ASSERT_TRUE(
+ testGoodUri("http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html"));
+ ASSERT_TRUE(testGoodUri("http://[1080:0:0:0:8:800:200C:417A]/index.html"));
+ ASSERT_TRUE(testGoodUri("http://[3ffe:2a00:100:7031::1]"));
+ ASSERT_TRUE(testGoodUri("http://[1080::8:800:200C:417A]/foo"));
+ ASSERT_TRUE(testGoodUri("http://[::192.9.5.5]/ipng"));
+ ASSERT_TRUE(testGoodUri("http://[::FFFF:129.144.52.38]:80/index.html"));
+ ASSERT_TRUE(testGoodUri("http://[2010:836B:4179::836B:4179]"));
+ ASSERT_TRUE(testGoodUri("//[2010:836B:4179::836B:4179]"));
+
+ // Random other things that crop up
+ ASSERT_TRUE(testGoodUri("http://example/Andr&#567;"));
+ ASSERT_TRUE(testGoodUri("file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/"));
}
-
-
TEST(FourSuite, BadUriReferences) {
- ASSERT_TRUE(testBadUri("beepbeep\x07\x07", 8));
- ASSERT_TRUE(testBadUri("\n", 0));
- ASSERT_TRUE(testBadUri("::", 0)); // not OK, per Roy Fielding on the W3C uri list on 2004-04-01
-
- // the following test cases are from a Perl script by David A. Wheeler
- // at http://www.dwheeler.com/secure-programs/url.pl
- ASSERT_TRUE(testBadUri("http://www yahoo.com", 10));
- ASSERT_TRUE(testBadUri("http://www.yahoo.com/hello world/", 26));
- ASSERT_TRUE(testBadUri("http://www.yahoo.com/yelp.html#\"", 31));
-
- // the following test cases are from a Haskell program by Graham Klyne
- // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs
- ASSERT_TRUE(testBadUri("[2010:836B:4179::836B:4179]", 0));
- ASSERT_TRUE(testBadUri(" ", 0));
- ASSERT_TRUE(testBadUri("%", 1));
- ASSERT_TRUE(testBadUri("A%Z", 2));
- ASSERT_TRUE(testBadUri("%ZZ", 1));
- ASSERT_TRUE(testBadUri("%AZ", 2));
- ASSERT_TRUE(testBadUri("A C", 1));
- ASSERT_TRUE(testBadUri("A\\'C", 1)); // r"A\'C"
- ASSERT_TRUE(testBadUri("A`C", 1));
- ASSERT_TRUE(testBadUri("A<C", 1));
- ASSERT_TRUE(testBadUri("A>C", 1));
- ASSERT_TRUE(testBadUri("A^C", 1));
- ASSERT_TRUE(testBadUri("A\\\\C", 1)); // r'A\\C'
- ASSERT_TRUE(testBadUri("A{C", 1));
- ASSERT_TRUE(testBadUri("A|C", 1));
- ASSERT_TRUE(testBadUri("A}C", 1));
- ASSERT_TRUE(testBadUri("A[C", 1));
- ASSERT_TRUE(testBadUri("A]C", 1));
- ASSERT_TRUE(testBadUri("A[**]C", 1));
- ASSERT_TRUE(testBadUri("http://[xyz]/", 8));
- ASSERT_TRUE(testBadUri("http://]/", 7));
- ASSERT_TRUE(testBadUri("http://example.org/[2010:836B:4179::836B:4179]", 19));
- ASSERT_TRUE(testBadUri("http://example.org/abc#[2010:836B:4179::836B:4179]", 23));
- ASSERT_TRUE(testBadUri("http://example.org/xxx/[qwerty]#a[b]", 23));
-
- // from a post to the W3C uri list on 2004-02-17
- // breaks at 22 instead of 17 because everything up to that point is a valid userinfo
- ASSERT_TRUE(testBadUri("http://w3c.org:80path1/path2", 22));
+ ASSERT_TRUE(testBadUri("beepbeep\x07\x07", 8));
+ ASSERT_TRUE(testBadUri("\n", 0));
+ ASSERT_TRUE(testBadUri(
+ "::", 0)); // not OK, per Roy Fielding on the W3C uri list on 2004-04-01
+
+ // the following test cases are from a Perl script by David A. Wheeler
+ // at http://www.dwheeler.com/secure-programs/url.pl
+ ASSERT_TRUE(testBadUri("http://www yahoo.com", 10));
+ ASSERT_TRUE(testBadUri("http://www.yahoo.com/hello world/", 26));
+ ASSERT_TRUE(testBadUri("http://www.yahoo.com/yelp.html#\"", 31));
+
+ // the following test cases are from a Haskell program by Graham Klyne
+ // at http://www.ninebynine.org/Software/HaskellUtils/Network/URITest.hs
+ ASSERT_TRUE(testBadUri("[2010:836B:4179::836B:4179]", 0));
+ ASSERT_TRUE(testBadUri(" ", 0));
+ ASSERT_TRUE(testBadUri("%", 1));
+ ASSERT_TRUE(testBadUri("A%Z", 2));
+ ASSERT_TRUE(testBadUri("%ZZ", 1));
+ ASSERT_TRUE(testBadUri("%AZ", 2));
+ ASSERT_TRUE(testBadUri("A C", 1));
+ ASSERT_TRUE(testBadUri("A\\'C", 1)); // r"A\'C"
+ ASSERT_TRUE(testBadUri("A`C", 1));
+ ASSERT_TRUE(testBadUri("A<C", 1));
+ ASSERT_TRUE(testBadUri("A>C", 1));
+ ASSERT_TRUE(testBadUri("A^C", 1));
+ ASSERT_TRUE(testBadUri("A\\\\C", 1)); // r'A\\C'
+ ASSERT_TRUE(testBadUri("A{C", 1));
+ ASSERT_TRUE(testBadUri("A|C", 1));
+ ASSERT_TRUE(testBadUri("A}C", 1));
+ ASSERT_TRUE(testBadUri("A[C", 1));
+ ASSERT_TRUE(testBadUri("A]C", 1));
+ ASSERT_TRUE(testBadUri("A[**]C", 1));
+ ASSERT_TRUE(testBadUri("http://[xyz]/", 8));
+ ASSERT_TRUE(testBadUri("http://]/", 7));
+ ASSERT_TRUE(testBadUri("http://example.org/[2010:836B:4179::836B:4179]", 19));
+ ASSERT_TRUE(testBadUri("http://example.org/abc#[2010:836B:4179::836B:4179]", 23));
+ ASSERT_TRUE(testBadUri("http://example.org/xxx/[qwerty]#a[b]", 23));
+
+ // from a post to the W3C uri list on 2004-02-17
+ // breaks at 22 instead of 17 because everything up to that point is a valid userinfo
+ ASSERT_TRUE(testBadUri("http://w3c.org:80path1/path2", 22));
}
-
-
namespace {
-bool normalizeAndCompare(const char * uriText,
- const char * expectedNormalized) {
- UriParserStateA stateA;
- int res;
-
- UriUriA testUri;
- stateA.uri = &testUri;
- res = uriParseUriA(&stateA, uriText);
- if (res != 0) {
- uriFreeUriMembersA(&testUri);
- return false;
- }
-
- // Expected result
- UriUriA expectedUri;
- stateA.uri = &expectedUri;
- res = uriParseUriA(&stateA, expectedNormalized);
- if (res != 0) {
- uriFreeUriMembersA(&testUri);
- uriFreeUriMembersA(&expectedUri);
- return false;
- }
-
- res = uriNormalizeSyntaxA(&testUri);
- if (res != 0) {
- uriFreeUriMembersA(&testUri);
- uriFreeUriMembersA(&expectedUri);
- return false;
- }
-
- const bool equalAfter = (URI_TRUE == uriEqualsUriA(&testUri, &expectedUri));
- uriFreeUriMembersA(&testUri);
- uriFreeUriMembersA(&expectedUri);
- return equalAfter;
+bool normalizeAndCompare(const char * uriText, const char * expectedNormalized) {
+ UriParserStateA stateA;
+ int res;
+
+ UriUriA testUri;
+ stateA.uri = &testUri;
+ res = uriParseUriA(&stateA, uriText);
+ if (res != 0) {
+ uriFreeUriMembersA(&testUri);
+ return false;
+ }
+
+ // Expected result
+ UriUriA expectedUri;
+ stateA.uri = &expectedUri;
+ res = uriParseUriA(&stateA, expectedNormalized);
+ if (res != 0) {
+ uriFreeUriMembersA(&testUri);
+ uriFreeUriMembersA(&expectedUri);
+ return false;
+ }
+
+ res = uriNormalizeSyntaxA(&testUri);
+ if (res != 0) {
+ uriFreeUriMembersA(&testUri);
+ uriFreeUriMembersA(&expectedUri);
+ return false;
+ }
+
+ const bool equalAfter = (URI_TRUE == uriEqualsUriA(&testUri, &expectedUri));
+ uriFreeUriMembersA(&testUri);
+ uriFreeUriMembersA(&expectedUri);
+ return equalAfter;
}
} // namespace
-
-
TEST(FourSuite, CaseNormalizationTests) {
- ASSERT_TRUE(normalizeAndCompare("HTTP://www.EXAMPLE.com/", "http://www.example.com/"));
- ASSERT_TRUE(normalizeAndCompare("example://A/b/c/%7bfoo%7d", "example://a/b/c/%7Bfoo%7D"));
+ ASSERT_TRUE(
+ normalizeAndCompare("HTTP://www.EXAMPLE.com/", "http://www.example.com/"));
+ ASSERT_TRUE(
+ normalizeAndCompare("example://A/b/c/%7bfoo%7d", "example://a/b/c/%7Bfoo%7D"));
}
-
-
TEST(FourSuite, PctEncNormalizationTests) {
- ASSERT_TRUE(normalizeAndCompare("http://host/%7Euser/x/y/z", "http://host/~user/x/y/z"));
- ASSERT_TRUE(normalizeAndCompare("http://host/%7euser/x/y/z", "http://host/~user/x/y/z"));
+ ASSERT_TRUE(
+ normalizeAndCompare("http://host/%7Euser/x/y/z", "http://host/~user/x/y/z"));
+ ASSERT_TRUE(
+ normalizeAndCompare("http://host/%7euser/x/y/z", "http://host/~user/x/y/z"));
}
-
-
TEST(FourSuite, PathSegmentNormalizationTests) {
- ASSERT_TRUE(normalizeAndCompare("/a/b/../../c", "/c"));
- // ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "a/b/../../c"));
- // Fixed:
- ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "c"));
- ASSERT_TRUE(normalizeAndCompare("/a/b/././c", "/a/b/c"));
- // ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/././c"));
- // Fixed:
- ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/c"));
- ASSERT_TRUE(normalizeAndCompare("/a/b/../c/././d", "/a/c/d"));
- // ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/b/../c/././d"));
- // Fixed:
- ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/c/d"));
+ ASSERT_TRUE(normalizeAndCompare("/a/b/../../c", "/c"));
+ // ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "a/b/../../c"));
+ // Fixed:
+ ASSERT_TRUE(normalizeAndCompare("a/b/../../c", "c"));
+ ASSERT_TRUE(normalizeAndCompare("/a/b/././c", "/a/b/c"));
+ // ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/././c"));
+ // Fixed:
+ ASSERT_TRUE(normalizeAndCompare("a/b/././c", "a/b/c"));
+ ASSERT_TRUE(normalizeAndCompare("/a/b/../c/././d", "/a/c/d"));
+ // ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/b/../c/././d"));
+ // Fixed:
+ ASSERT_TRUE(normalizeAndCompare("a/b/../c/././d", "a/c/d"));
}
diff --git a/test/MemoryManagerSuite.cpp b/test/MemoryManagerSuite.cpp
index e4af977..5b64e90 100644
--- a/test/MemoryManagerSuite.cpp
+++ b/test/MemoryManagerSuite.cpp
@@ -33,413 +33,437 @@ extern "C" {
#include "../src/UriMemory.h"
}
-
namespace {
-
-
static void * failingMalloc(UriMemoryManager * memory, size_t size);
static void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size);
static void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size);
-static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size);
+static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb,
+ size_t size);
static void countingFree(UriMemoryManager * memory, void * ptr);
-
-
class FailingMemoryManager {
private:
- UriMemoryManager memoryManager;
- unsigned int callCountAlloc;
- unsigned int callCountFree;
- unsigned int failAllocAfterTimes;
-
- friend void * failingMalloc(UriMemoryManager * memory, size_t size);
- friend void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size);
- friend void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size);
- friend void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size);
- friend void countingFree(UriMemoryManager * memory, void * ptr);
+ UriMemoryManager memoryManager;
+ unsigned int callCountAlloc;
+ unsigned int callCountFree;
+ unsigned int failAllocAfterTimes;
+
+ friend void * failingMalloc(UriMemoryManager * memory, size_t size);
+ friend void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size);
+ friend void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size);
+ friend void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb,
+ size_t size);
+ friend void countingFree(UriMemoryManager * memory, void * ptr);
public:
- FailingMemoryManager(unsigned int failAllocAfterTimes = 0)
- : callCountAlloc(0), callCountFree(0),
- failAllocAfterTimes(failAllocAfterTimes) {
- this->memoryManager.malloc = failingMalloc;
- this->memoryManager.calloc = failingCalloc;
- this->memoryManager.realloc = failingRealloc;
- this->memoryManager.reallocarray = failingReallocarray;
- this->memoryManager.free = countingFree;
- this->memoryManager.userData = this;
- }
-
- UriMemoryManager * operator&() {
- return &(this->memoryManager);
- }
-
- unsigned int getCallCountFree() const {
- return this->callCountFree;
- }
+ FailingMemoryManager(unsigned int failAllocAfterTimes = 0)
+ : callCountAlloc(0), callCountFree(0), failAllocAfterTimes(failAllocAfterTimes) {
+ this->memoryManager.malloc = failingMalloc;
+ this->memoryManager.calloc = failingCalloc;
+ this->memoryManager.realloc = failingRealloc;
+ this->memoryManager.reallocarray = failingReallocarray;
+ this->memoryManager.free = countingFree;
+ this->memoryManager.userData = this;
+ }
+
+ UriMemoryManager * operator&() {
+ return &(this->memoryManager);
+ }
+
+ unsigned int getCallCountAlloc() const {
+ return this->callCountAlloc;
+ }
+
+ unsigned int getCallCountFree() const {
+ return this->callCountFree;
+ }
};
-
-
static void * failingMalloc(UriMemoryManager * memory, size_t size) {
- FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData);
- fmm->callCountAlloc++;
- if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
- errno = ENOMEM;
- return NULL;
- }
- return malloc(size);
+ FailingMemoryManager * const fmm =
+ static_cast<FailingMemoryManager *>(memory->userData);
+ fmm->callCountAlloc++;
+ if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return malloc(size);
}
-
-
static void * failingCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) {
- FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData);
- fmm->callCountAlloc++;
- if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
- errno = ENOMEM;
- return NULL;
- }
- return calloc(nmemb, size);
+ FailingMemoryManager * const fmm =
+ static_cast<FailingMemoryManager *>(memory->userData);
+ fmm->callCountAlloc++;
+ if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return calloc(nmemb, size);
}
-
-
static void * failingRealloc(UriMemoryManager * memory, void * ptr, size_t size) {
- FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData);
- fmm->callCountAlloc++;
- if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
- errno = ENOMEM;
- return NULL;
- }
- return realloc(ptr, size);
+ FailingMemoryManager * const fmm =
+ static_cast<FailingMemoryManager *>(memory->userData);
+ fmm->callCountAlloc++;
+ if (fmm->callCountAlloc > fmm->failAllocAfterTimes) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(ptr, size);
}
-
-
-static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb, size_t size) {
- return uriEmulateReallocarray(memory, ptr, nmemb, size);
+static void * failingReallocarray(UriMemoryManager * memory, void * ptr, size_t nmemb,
+ size_t size) {
+ return uriEmulateReallocarray(memory, ptr, nmemb, size);
}
-
-
static void countingFree(UriMemoryManager * memory, void * ptr) {
- FailingMemoryManager * const fmm = static_cast<FailingMemoryManager *>(memory->userData);
- fmm->callCountFree++;
- return free(ptr);
+ FailingMemoryManager * const fmm =
+ static_cast<FailingMemoryManager *>(memory->userData);
+ fmm->callCountFree++;
+ return free(ptr);
}
-
-
static UriUriA parse(const char * sourceUriString) {
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
- assert(uriParseUriA(&state, sourceUriString) == URI_SUCCESS);
- return uri;
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+ assert(uriParseUriA(&state, sourceUriString) == URI_SUCCESS);
+ return uri;
}
-
-
static UriQueryListA * parseQueryList(const char * queryString) {
- UriQueryListA * queryList;
- const char * const first = queryString;
- const char * const afterLast = first + strlen(first);
- assert(uriDissectQueryMallocA(&queryList, NULL, first, afterLast)
- == URI_SUCCESS);
- return queryList;
+ UriQueryListA * queryList;
+ const char * const first = queryString;
+ const char * const afterLast = first + strlen(first);
+ assert(uriDissectQueryMallocA(&queryList, NULL, first, afterLast) == URI_SUCCESS);
+ return queryList;
}
} // namespace
-
-
TEST(MemoryManagerCompletenessSuite, AllFunctionMembersRequired) {
- UriUriA uri = parse("whatever");
- UriMemoryManager memory;
+ UriUriA uri = parse("whatever");
+ UriMemoryManager memory;
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- memory.malloc = NULL;
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ memory.malloc = NULL;
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- memory.calloc = NULL;
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ memory.calloc = NULL;
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- memory.realloc = NULL;
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ memory.realloc = NULL;
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- memory.reallocarray = NULL;
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ memory.reallocarray = NULL;
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- memory.free = NULL;
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ memory.free = NULL;
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
- memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
- ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_SUCCESS);
+ memcpy(&memory, &defaultMemoryManager, sizeof(UriMemoryManager));
+ ASSERT_EQ(uriFreeUriMembersMmA(&uri, &memory), URI_SUCCESS);
}
+TEST(MemoryManagerCompletionSuite, MallocAndFreeRequired) {
+ UriMemoryManager memory;
+ UriMemoryManager backend;
+ memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager));
+ backend.malloc = NULL;
+ ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend),
+ URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
-TEST(MemoryManagerCompletenessSuite, MallocAndFreeRequiredOnly) {
- UriMemoryManager memory;
- UriMemoryManager backend;
-
- memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager));
- backend.malloc = NULL;
- ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
-
- memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager));
- backend.free = NULL;
- ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend),
- URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
+ memcpy(&backend, &defaultMemoryManager, sizeof(UriMemoryManager));
+ backend.free = NULL;
+ ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend),
+ URI_ERROR_MEMORY_MANAGER_INCOMPLETE);
}
-
-
TEST(MemoryManagerTestingSuite, DefaultMemoryManager) {
- ASSERT_EQ(uriTestMemoryManager(&defaultMemoryManager), URI_SUCCESS);
+ ASSERT_EQ(uriTestMemoryManagerEx(&defaultMemoryManager, URI_TRUE), URI_SUCCESS);
}
+TEST(MemoryManagerCompletionSuite, MallocAndFreeSufficient) {
+ UriMemoryManager memory;
+ UriMemoryManager backend;
+ memset(&backend, 0, sizeof(UriMemoryManager));
+ backend.malloc = defaultMemoryManager.malloc;
+ backend.free = defaultMemoryManager.free;
-TEST(MemoryManagerTestingSuite, CompleteMemoryManager) {
- UriMemoryManager memory;
- UriMemoryManager backend;
-
- memset(&backend, 0, sizeof(UriMemoryManager));
- backend.malloc = defaultMemoryManager.malloc;
- backend.free = defaultMemoryManager.free;
-
- ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend),
- URI_SUCCESS);
+ ASSERT_EQ(uriCompleteMemoryManager(&memory, &backend), URI_SUCCESS);
- ASSERT_EQ(uriTestMemoryManager(&memory), URI_SUCCESS);
+ ASSERT_EQ(uriTestMemoryManagerEx(&memory, URI_TRUE), URI_SUCCESS);
}
-
-
TEST(MemoryManagerTestingSuite, EmulateCalloc) {
- UriMemoryManager partialEmulationMemoryManager;
- memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
- sizeof(UriMemoryManager));
- partialEmulationMemoryManager.calloc = uriEmulateCalloc;
+ UriMemoryManager partialEmulationMemoryManager;
+ memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
+ sizeof(UriMemoryManager));
+ partialEmulationMemoryManager.calloc = uriEmulateCalloc;
- ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager),
- URI_SUCCESS);
+ ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE),
+ URI_SUCCESS);
}
-
-
TEST(MemoryManagerTestingSuite, EmulateReallocarray) {
- UriMemoryManager partialEmulationMemoryManager;
- memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
- sizeof(UriMemoryManager));
- partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray;
+ UriMemoryManager partialEmulationMemoryManager;
+ memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
+ sizeof(UriMemoryManager));
+ partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray;
- ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager),
- URI_SUCCESS);
+ ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE),
+ URI_SUCCESS);
}
+TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateCalloc) {
+ EXPECT_GT(2 * sizeof(size_t), sizeof(void *));
+ errno = 0;
+ ASSERT_EQ(NULL, uriEmulateCalloc(&defaultMemoryManager, (size_t)-1, (size_t)-1));
+ ASSERT_EQ(errno, ENOMEM);
+}
-TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateCalloc) {
- EXPECT_GT(2 * sizeof(size_t), sizeof(void *));
+TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateReallocarray) {
+ EXPECT_GT(2 * sizeof(size_t), sizeof(void *));
- errno = 0;
- ASSERT_EQ(NULL, uriEmulateCalloc(
- &defaultMemoryManager, (size_t)-1, (size_t)-1));
- ASSERT_EQ(errno, ENOMEM);
+ errno = 0;
+ ASSERT_EQ(NULL, uriEmulateReallocarray(&defaultMemoryManager, NULL, (size_t)-1,
+ (size_t)-1));
+ ASSERT_EQ(errno, ENOMEM);
}
+TEST(MemoryManagerTestingSuite, EmulateCallocAndReallocarray) {
+ UriMemoryManager partialEmulationMemoryManager;
+ memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
+ sizeof(UriMemoryManager));
+ partialEmulationMemoryManager.calloc = uriEmulateCalloc;
+ partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray;
+ ASSERT_EQ(uriTestMemoryManagerEx(&partialEmulationMemoryManager, URI_TRUE),
+ URI_SUCCESS);
+}
-TEST(MemoryManagerTestingOverflowDetectionSuite, EmulateReallocarray) {
- EXPECT_GT(2 * sizeof(size_t), sizeof(void *));
+TEST(FailingMemoryManagerSuite, AddBaseUriExMm) {
+ UriUriA absoluteDest;
+ UriUriA relativeSource = parse("foo");
+ UriUriA absoluteBase = parse("http://example.org/bar");
+ const UriResolutionOptions options = URI_RESOLVE_STRICTLY;
+ FailingMemoryManager failingMemoryManager;
- errno = 0;
- ASSERT_EQ(NULL, uriEmulateReallocarray(
- &defaultMemoryManager, NULL, (size_t)-1, (size_t)-1));
- ASSERT_EQ(errno, ENOMEM);
+ ASSERT_EQ(uriAddBaseUriExMmA(&absoluteDest, &relativeSource, &absoluteBase, options,
+ &failingMemoryManager),
+ URI_ERROR_MALLOC);
+
+ uriFreeUriMembersA(&relativeSource);
+ uriFreeUriMembersA(&absoluteBase);
}
+TEST(FailingMemoryManagerSuite, ComposeQueryMallocExMm) {
+ char * dest = NULL;
+ UriQueryListA * const queryList = parseQueryList("k1=v1");
+ UriBool spaceToPlus = URI_TRUE; // not of interest
+ UriBool normalizeBreaks = URI_TRUE; // not of interest
+ FailingMemoryManager failingMemoryManager;
+ ASSERT_EQ(uriComposeQueryMallocExMmA(&dest, queryList, spaceToPlus, normalizeBreaks,
+ &failingMemoryManager),
+ URI_ERROR_MALLOC);
-TEST(MemoryManagerTestingSuite, EmulateCallocAndReallocarray) {
- UriMemoryManager partialEmulationMemoryManager;
- memcpy(&partialEmulationMemoryManager, &defaultMemoryManager,
- sizeof(UriMemoryManager));
- partialEmulationMemoryManager.calloc = uriEmulateCalloc;
- partialEmulationMemoryManager.reallocarray = uriEmulateReallocarray;
+ uriFreeQueryListA(queryList);
+}
- ASSERT_EQ(uriTestMemoryManager(&partialEmulationMemoryManager),
- URI_SUCCESS);
+TEST(FailingMemoryManagerSuite, DissectQueryMallocExMm) {
+ UriQueryListA * queryList;
+ int itemCount;
+ const char * const first = "k1=v1&k2=v2";
+ const char * const afterLast = first + strlen(first);
+ const UriBool plusToSpace = URI_TRUE; // not of interest
+ const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; // not o. i.
+ FailingMemoryManager failingMemoryManager;
+
+ ASSERT_EQ(uriDissectQueryMallocExMmA(&queryList, &itemCount, first, afterLast,
+ plusToSpace, breakConversion,
+ &failingMemoryManager),
+ URI_ERROR_MALLOC);
}
+TEST(FailingMemoryManagerSuite, FreeQueryListMm) {
+ UriQueryListA * const queryList = parseQueryList("k1=v1");
+ FailingMemoryManager failingMemoryManager;
+ ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U);
+ uriFreeQueryListMmA(queryList, &failingMemoryManager);
-TEST(FailingMemoryManagerSuite, AddBaseUriExMm) {
- UriUriA absoluteDest;
- UriUriA relativeSource = parse("foo");
- UriUriA absoluteBase = parse("http://example.org/bar");
- const UriResolutionOptions options = URI_RESOLVE_STRICTLY;
- FailingMemoryManager failingMemoryManager;
+ ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U);
+}
+
+TEST(FailingMemoryManagerSuite, FreeUriMembersMm) {
+ UriUriA uri = parse("http://example.org/");
+ FailingMemoryManager failingMemoryManager;
+ ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U);
- ASSERT_EQ(uriAddBaseUriExMmA(&absoluteDest, &relativeSource,
- &absoluteBase, options, &failingMemoryManager),
- URI_ERROR_MALLOC);
+ uriFreeUriMembersMmA(&uri, &failingMemoryManager);
- uriFreeUriMembersA(&relativeSource);
- uriFreeUriMembersA(&absoluteBase);
+ ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U);
+ uriFreeUriMembersA(&uri);
}
+TEST(FailingMemoryManagerSuite, IsWellFormedHostIp6Mm) {
+ FailingMemoryManager failingMemoryManager;
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 0U);
+ EXPECT_EQ(uriIsWellFormedHostIp6MmA(first, afterLast, &failingMemoryManager),
+ URI_ERROR_MALLOC);
-TEST(FailingMemoryManagerSuite, ComposeQueryMallocExMm) {
- char * dest = NULL;
- UriQueryListA * const queryList = parseQueryList("k1=v1");
- UriBool spaceToPlus = URI_TRUE; // not of interest
- UriBool normalizeBreaks = URI_TRUE; // not of interest
- FailingMemoryManager failingMemoryManager;
+ EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 1U);
+}
+
+TEST(FailingMemoryManagerSuite, IsWellFormedHostIpFutureMm) {
+ FailingMemoryManager failingMemoryManager;
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 0U);
- ASSERT_EQ(uriComposeQueryMallocExMmA(&dest, queryList,
- spaceToPlus, normalizeBreaks, &failingMemoryManager),
- URI_ERROR_MALLOC);
+ EXPECT_EQ(uriIsWellFormedHostIpFutureMmA(first, afterLast, &failingMemoryManager),
+ URI_ERROR_MALLOC);
- uriFreeQueryListA(queryList);
+ EXPECT_EQ(failingMemoryManager.getCallCountAlloc(), 1U);
}
+TEST(FailingMemoryManagerSuite, SetPortTextMm) {
+ UriUriA uri = parse("https://host/");
+ FailingMemoryManager failingMemoryManager;
+ const char * const first = "443";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U);
+ ASSERT_EQ(uriSetPortTextMmA(&uri, first, afterLast, &failingMemoryManager),
+ URI_ERROR_MALLOC);
-TEST(FailingMemoryManagerSuite, DissectQueryMallocExMm) {
- UriQueryListA * queryList;
- int itemCount;
- const char * const first = "k1=v1&k2=v2";
- const char * const afterLast = first + strlen(first);
- const UriBool plusToSpace = URI_TRUE; // not of interest
- const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; // not o. i.
- FailingMemoryManager failingMemoryManager;
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U);
- ASSERT_EQ(uriDissectQueryMallocExMmA(&queryList, &itemCount,
- first, afterLast, plusToSpace, breakConversion,
- &failingMemoryManager),
- URI_ERROR_MALLOC);
+ uriFreeUriMembersA(&uri);
}
+TEST(FailingMemoryManagerSuite, SetQueryMm) {
+ UriUriA uri = parse("scheme://host/");
+ FailingMemoryManager failingMemoryManager;
+ const char * const first = "k1=v1";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U);
+ ASSERT_EQ(uriSetQueryMmA(&uri, first, afterLast, &failingMemoryManager),
+ URI_ERROR_MALLOC);
-TEST(FailingMemoryManagerSuite, FreeQueryListMm) {
- UriQueryListA * const queryList = parseQueryList("k1=v1");
- FailingMemoryManager failingMemoryManager;
- ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U);
-
- uriFreeQueryListMmA(queryList, &failingMemoryManager);
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U);
- ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U);
+ uriFreeUriMembersA(&uri);
}
+TEST(FailingMemoryManagerSuite, SetUserInfoMm) {
+ UriUriA uri = parse("scheme://host/");
+ FailingMemoryManager failingMemoryManager;
+ const char * const first = "user:password";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 0U);
+ ASSERT_EQ(uriSetUserInfoMmA(&uri, first, afterLast, &failingMemoryManager),
+ URI_ERROR_MALLOC);
-TEST(FailingMemoryManagerSuite, FreeUriMembersMm) {
- UriUriA uri = parse("http://example.org/");
- FailingMemoryManager failingMemoryManager;
- ASSERT_EQ(failingMemoryManager.getCallCountFree(), 0U);
-
- uriFreeUriMembersMmA(&uri, &failingMemoryManager);
+ ASSERT_EQ(failingMemoryManager.getCallCountAlloc(), 1U);
- ASSERT_GE(failingMemoryManager.getCallCountFree(), 1U);
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
}
namespace {
- void testNormalizeSyntaxWithFailingMallocCallsFreeTimes(const char * uriString,
- unsigned int mask,
- unsigned int failAllocAfterTimes = 0,
- unsigned int expectedCallCountFree = 0) {
- UriUriA uri = parse(uriString);
- FailingMemoryManager failingMemoryManager(failAllocAfterTimes);
+void testNormalizeSyntaxWithFailingMallocCallsFreeTimes(
+ const char * uriString, unsigned int mask, unsigned int failAllocAfterTimes = 0,
+ unsigned int expectedCallCountFree = 0) {
+ UriUriA uri = parse(uriString);
+ FailingMemoryManager failingMemoryManager(failAllocAfterTimes);
- ASSERT_EQ(uriNormalizeSyntaxExMmA(&uri, mask, &failingMemoryManager),
- URI_ERROR_MALLOC);
+ ASSERT_EQ(uriNormalizeSyntaxExMmA(&uri, mask, &failingMemoryManager),
+ URI_ERROR_MALLOC);
- EXPECT_EQ(failingMemoryManager.getCallCountFree(), expectedCallCountFree);
+ EXPECT_EQ(failingMemoryManager.getCallCountFree(), expectedCallCountFree);
- uriFreeUriMembersA(&uri);
- }
+ uriFreeUriMembersA(&uri);
+}
} // namespace
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmScheme) {
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("hTTp://example.org/path", URI_NORMALIZE_SCHEME);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("hTTp://example.org/path",
+ URI_NORMALIZE_SCHEME);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyUserInfo) {
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//@:123", URI_NORMALIZE_USER_INFO);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//@:123",
+ URI_NORMALIZE_USER_INFO);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyHostRegname) {
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123", URI_NORMALIZE_HOST);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123", URI_NORMALIZE_HOST);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyQuery) {
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123?", URI_NORMALIZE_QUERY);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123?", URI_NORMALIZE_QUERY);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmEmptyFragment) {
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123#", URI_NORMALIZE_FRAGMENT);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//:123#", URI_NORMALIZE_FRAGMENT);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextIp4) { // issue #121
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//192.0.2.0:123" /* RFC 5737 */, URI_NORMALIZE_HOST, 1, 1);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//192.0.2.0:123" /* RFC 5737 */,
+ URI_NORMALIZE_HOST, 1, 1);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextIp6) { // issue #121
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//[2001:db8::]:123" /* RFC 3849 */, URI_NORMALIZE_HOST, 1, 1);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes(
+ "//[2001:db8::]:123" /* RFC 3849 */, URI_NORMALIZE_HOST, 1, 1);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextRegname) { // issue #121
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//host123.test:123" /* RFC 6761 */, URI_NORMALIZE_HOST, 1, 1);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes(
+ "//host123.test:123" /* RFC 6761 */, URI_NORMALIZE_HOST, 1, 1);
}
TEST(FailingMemoryManagerSuite, NormalizeSyntaxExMmHostTextFuture) { // issue #121
- testNormalizeSyntaxWithFailingMallocCallsFreeTimes("//[v7.X]:123" /* arbitrary IPvFuture */, URI_NORMALIZE_HOST, 1, 1);
+ testNormalizeSyntaxWithFailingMallocCallsFreeTimes(
+ "//[v7.X]:123" /* arbitrary IPvFuture */, URI_NORMALIZE_HOST, 1, 1);
}
-
-
TEST(FailingMemoryManagerSuite, ParseSingleUriExMm) {
- UriUriA uri;
- const char * const first = "k1=v1&k2=v2";
- const char * const afterLast = first + strlen(first);
- FailingMemoryManager failingMemoryManager;
+ UriUriA uri;
+ const char * const first = "k1=v1&k2=v2";
+ const char * const afterLast = first + strlen(first);
+ FailingMemoryManager failingMemoryManager;
- ASSERT_EQ(uriParseSingleUriExMmA(&uri, first, afterLast, NULL,
- &failingMemoryManager),
- URI_ERROR_MALLOC);
+ ASSERT_EQ(uriParseSingleUriExMmA(&uri, first, afterLast, NULL, &failingMemoryManager),
+ URI_ERROR_MALLOC);
}
-
-
TEST(FailingMemoryManagerSuite, RemoveBaseUriMm) {
- UriUriA dest;
- UriUriA absoluteSource = parse("http://example.org/a/b/c/");
- UriUriA absoluteBase = parse("http://example.org/a/");
- const UriBool domainRootMode = URI_TRUE; // not of interest
- FailingMemoryManager failingMemoryManager;
-
- ASSERT_EQ(uriRemoveBaseUriMmA(&dest, &absoluteSource, &absoluteBase,
- domainRootMode, &failingMemoryManager),
- URI_ERROR_MALLOC);
-
- uriFreeUriMembersA(&absoluteSource);
- uriFreeUriMembersA(&absoluteBase);
+ UriUriA dest;
+ UriUriA absoluteSource = parse("http://example.org/a/b/c/");
+ UriUriA absoluteBase = parse("http://example.org/a/");
+ const UriBool domainRootMode = URI_TRUE; // not of interest
+ FailingMemoryManager failingMemoryManager;
+
+ ASSERT_EQ(uriRemoveBaseUriMmA(&dest, &absoluteSource, &absoluteBase, domainRootMode,
+ &failingMemoryManager),
+ URI_ERROR_MALLOC);
+
+ uriFreeUriMembersA(&absoluteSource);
+ uriFreeUriMembersA(&absoluteBase);
}
diff --git a/test/SetFragment.cpp b/test/SetFragment.cpp
new file mode 100644
index 0000000..71e5343
--- /dev/null
+++ b/test/SetFragment.cpp
@@ -0,0 +1,230 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedFragment(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedFragmentA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedFragment, Null) {
+ testIsWellFormedFragment(NULL, false);
+}
+
+TEST(IsWellFormedFragment, Empty) {
+ testIsWellFormedFragment("", true);
+}
+
+TEST(IsWellFormedFragment, AllowedCharacters) {
+ // The related grammar subset is this:
+ //
+ // fragment = *( pchar / "/" / "?" )
+ // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ // pct-encoded = "%" HEXDIG HEXDIG
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ //
+ // NOTE: Percent encoding has dedicated tests further down
+ testIsWellFormedFragment("0123456789"
+ "ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "-._~"
+ "!$&'()*+,;="
+ ":@"
+ "/?",
+ true);
+}
+
+TEST(IsWellFormedFragment, ForbiddenCharacters) {
+ testIsWellFormedFragment(" ", false);
+}
+
+TEST(IsWellFormedFragment, PercentEncodingWellFormed) {
+ testIsWellFormedFragment("%"
+ "aa"
+ "%"
+ "AA",
+ true);
+}
+
+TEST(IsWellFormedFragment, PercentEncodingMalformedCutOff1) {
+ testIsWellFormedFragment("%", false);
+}
+
+TEST(IsWellFormedFragment, PercentEncodingMalformedCutOff2) {
+ testIsWellFormedFragment("%"
+ "a",
+ false);
+}
+
+TEST(IsWellFormedFragment, PercentEncodingMalformedForbiddenCharacter1) {
+ testIsWellFormedFragment("%"
+ "ga",
+ false);
+}
+
+TEST(IsWellFormedFragment, PercentEncodingMalformedForbiddenCharacter2) {
+ testIsWellFormedFragment("%"
+ "ag",
+ false);
+}
+
+TEST(SetFragment, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "toc";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetFragmentA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetFragment, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const fragment = "toc";
+ const char * const first = NULL;
+ const char * const afterLast = fragment + strlen(fragment);
+ ASSERT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetFragment, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "toc";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetFragment, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#fragment");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetFragmentA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#old");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, NullValueApplied) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#fragment");
+
+ EXPECT_EQ(uriSetFragmentA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#fragment");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetFragmentA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/#");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, NonNullValueAppliedNonEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#old");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/#new");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/#fragment");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetFragment, UriWithoutHostTolerated) {
+ UriUriA uri = parseWellFormedUri("/no/host/here");
+ const char * const first = "toc";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_TRUE(uri.hostText.first == NULL); // self-test
+
+ EXPECT_EQ(uriSetFragmentA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/no/host/here#toc");
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetHostAuto.cpp b/test/SetHostAuto.cpp
new file mode 100644
index 0000000..48a7452
--- /dev/null
+++ b/test/SetHostAuto.cpp
@@ -0,0 +1,223 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+static void assertMalformedHostValueRejected(const char * text) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = text;
+ const char * const afterLast = text + strlen(text);
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+} // namespace
+
+TEST(SetHostAuto, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetHostAutoA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostAuto, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const fragment = "localhost";
+ const char * const first = NULL;
+ const char * const afterLast = fragment + strlen(fragment);
+ ASSERT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostAuto, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "localhost";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostAuto, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old/");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NullValueApplied) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NullValueAppliedNoPath) {
+ UriUriA uri = parseWellFormedUri("https://example.com");
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "https:");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NullValueAppliedNoPath2) {
+ UriUriA uri = parseWellFormedUri("https://example.com?foo=bar");
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "https:?foo=bar");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:///path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueAppliedNonEmptyIp4) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://1.2.3.4/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueAppliedNonEmptyIp6) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+ const char * const first = "[::1]";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueAppliedNonEmptyIpFuture) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+ const char * const first = "[v7.host]";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://[v7.host]/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, NonNullValueAppliedNonEmptyRegName) {
+ UriUriA uri = parseWellFormedUri("scheme://old/path");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://new/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIp6BothSquareBracketsMissing) {
+ assertMalformedHostValueRejected("::1");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIp6ClosingSquareBracketMissing) {
+ assertMalformedHostValueRejected("[::1");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIp6OpeningSquareBracketMissing) {
+ assertMalformedHostValueRejected("::1]");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIp6SquareBracketsMissing) {
+ assertMalformedHostValueRejected("::1");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIp6Empty) {
+ assertMalformedHostValueRejected("[]");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedIpFutureClosingSquareBracketMissing) {
+ assertMalformedHostValueRejected("[v7.host");
+}
+
+TEST(SetHostAuto, MalformedValueRejectedRegNameForbiddenCharacters) {
+ assertMalformedHostValueRejected("not well-formed");
+}
diff --git a/test/SetHostIp4.cpp b/test/SetHostIp4.cpp
new file mode 100644
index 0000000..727483d
--- /dev/null
+++ b/test/SetHostIp4.cpp
@@ -0,0 +1,316 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedHostIp4(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedHostIp4A(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+static void assertUriHostIp4Equal(const UriUriA * uri, unsigned char o1, unsigned char o2,
+ unsigned char o3, unsigned char o4) {
+ ASSERT_TRUE(uri->hostData.ip4 != NULL);
+ EXPECT_EQ(uri->hostData.ip4->data[0], o1);
+ EXPECT_EQ(uri->hostData.ip4->data[1], o2);
+ EXPECT_EQ(uri->hostData.ip4->data[2], o3);
+ EXPECT_EQ(uri->hostData.ip4->data[3], o4);
+}
+
+} // namespace
+
+TEST(IsWellFormedHostIp4, Null) {
+ testIsWellFormedHostIp4(NULL, false);
+}
+
+TEST(IsWellFormedHostIp4, Empty) {
+ testIsWellFormedHostIp4("", false);
+}
+
+TEST(IsWellFormedHostIp4, AllUnset) {
+ testIsWellFormedHostIp4("0.0.0.0", true);
+}
+
+TEST(IsWellFormedHostIp4, AllSet) {
+ testIsWellFormedHostIp4("255.255.255.255", true);
+}
+
+TEST(IsWellFormedHostIp4, ThreeOctets) {
+ testIsWellFormedHostIp4("1.2.3", false);
+}
+
+TEST(IsWellFormedHostIp4, FiveOctets) {
+ testIsWellFormedHostIp4("1.2.3.4.5", false);
+}
+
+TEST(IsWellFormedHostIp4, LeadingZeros) {
+ testIsWellFormedHostIp4("01.2.3.4", false);
+ testIsWellFormedHostIp4("1.02.3.4", false);
+ testIsWellFormedHostIp4("1.2.03.4", false);
+ testIsWellFormedHostIp4("1.2.3.04", false);
+}
+
+TEST(IsWellFormedHostIp4, Overflow) {
+ testIsWellFormedHostIp4("256.2.3.4", false);
+ testIsWellFormedHostIp4("1.256.3.4", false);
+ testIsWellFormedHostIp4("1.2.256.4", false);
+ testIsWellFormedHostIp4("1.2.3.256", false);
+}
+
+TEST(SetHostIp4, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetHostIp4A(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp4, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const host = "1.2.3.4";
+ const char * const first = NULL;
+ const char * const afterLast = host + strlen(host);
+ ASSERT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp4, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp4, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old/");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme://host//path1/path2");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedDotNotInserted) {
+ UriUriA uri = parseWellFormedUri("//host/./path1/path2");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:/path");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedPriorIp4) {
+ UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedPriorIp6) {
+ UriUriA uri = parseWellFormedUri("scheme://[::1]/path");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NullValueAppliedPriorRegName) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://1.2.3.4");
+ assertUriHostIp4Equal(&uri, 1, 2, 3, 4);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIp4) {
+ UriUriA uri = parseWellFormedUri("//1.2.3.4");
+ const char * const first = "5.6.7.8";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//5.6.7.8");
+ assertUriHostIp4Equal(&uri, 5, 6, 7, 8);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIp6) {
+ UriUriA uri = parseWellFormedUri("//[::1]");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//1.2.3.4");
+ assertUriHostIp4Equal(&uri, 1, 2, 3, 4);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("//[v7.host]");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//1.2.3.4");
+ assertUriHostIp4Equal(&uri, 1, 2, 3, 4);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, NonNullValueAppliedNonEmptyPriorRegName) {
+ UriUriA uri = parseWellFormedUri("//hostname.test");
+ const char * const first = "1.2.3.4";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//1.2.3.4");
+ assertUriHostIp4Equal(&uri, 1, 2, 3, 4);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, UriWithPortRejected) {
+ UriUriA uri = parseWellFormedUri("//host:1234");
+ EXPECT_TRUE(uri.portText.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp4, UriWithUserInfoRejected) {
+ UriUriA uri = parseWellFormedUri("//user:password@host");
+ EXPECT_TRUE(uri.userInfo.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIp4A(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetHostIp6.cpp b/test/SetHostIp6.cpp
new file mode 100644
index 0000000..e81eab9
--- /dev/null
+++ b/test/SetHostIp6.cpp
@@ -0,0 +1,387 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedHostIp6(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed =
+ (uriIsWellFormedHostIp6A(first, afterLast) == URI_SUCCESS) ? URI_TRUE : URI_FALSE;
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedHostIp6, Null) {
+ testIsWellFormedHostIp6(NULL, false);
+}
+
+TEST(IsWellFormedHostIp6, Empty) {
+ testIsWellFormedHostIp6("", false);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingAllUnset) {
+ testIsWellFormedHostIp6("::0.0.0.0", true);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingAllSet) {
+ testIsWellFormedHostIp6("::255.255.255.255", true);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingThreeOctets) {
+ testIsWellFormedHostIp6("::1.2.3", false);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingFiveOctets) {
+ testIsWellFormedHostIp6("::1.2.3.4.5", false);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingLeadingZeros) {
+ testIsWellFormedHostIp6("::01.2.3.4", false);
+ testIsWellFormedHostIp6("::1.02.3.4", false);
+ testIsWellFormedHostIp6("::1.2.03.4", false);
+ testIsWellFormedHostIp6("::1.2.3.04", false);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingOverflow) {
+ testIsWellFormedHostIp6("::256.2.3.4", false);
+ testIsWellFormedHostIp6("::1.256.3.4", false);
+ testIsWellFormedHostIp6("::1.2.256.4", false);
+ testIsWellFormedHostIp6("::1.2.3.256", false);
+}
+
+TEST(IsWellFormedHostIp6, Ip4EmbeddingHex) {
+ testIsWellFormedHostIp6("::a.2.3.4", false);
+ testIsWellFormedHostIp6("::1.a.3.4", false);
+ testIsWellFormedHostIp6("::1.2.a.4", false);
+ testIsWellFormedHostIp6("::1.2.3.a", false);
+}
+
+TEST(IsWellFormedHostIp6, Uppercase) {
+ testIsWellFormedHostIp6("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", true);
+}
+
+TEST(IsWellFormedHostIp6, Lowercase) {
+ testIsWellFormedHostIp6("abcd:ef01:2345:6789:abcd:ef01:2345:6789", true);
+}
+
+TEST(IsWellFormedHostIp6, MaxLengthViolation) {
+ testIsWellFormedHostIp6("aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa"
+ "X",
+ false);
+}
+
+TEST(IsWellFormedHostIp6, NineQuads) {
+ testIsWellFormedHostIp6("1:2:3:4:5:6:7:8:9", false);
+}
+
+TEST(IsWellFormedHostIp6, SevenQuads) {
+ testIsWellFormedHostIp6("1:2:3:4:5:6:7", false);
+}
+
+TEST(IsWellFormedHostIp6, AllUnset) {
+ testIsWellFormedHostIp6("::", true);
+}
+
+TEST(IsWellFormedHostIp6, Loopback) {
+ testIsWellFormedHostIp6("::1", true);
+}
+
+TEST(IsWellFormedHostIp6, SparseLeadingZeros) {
+ testIsWellFormedHostIp6("01:02:03:04:05:06:07:08", true);
+}
+
+TEST(IsWellFormedHostIp6, SingleZipper) {
+ testIsWellFormedHostIp6("1::8", true);
+}
+
+TEST(IsWellFormedHostIp6, TwoZippers) {
+ testIsWellFormedHostIp6("1::4::8", false);
+}
+
+TEST(IsWellFormedHostIp6, Overzipped) {
+ testIsWellFormedHostIp6("::1:2:3:4:5:6:7:8", false);
+ testIsWellFormedHostIp6("1:2:3:4::5:6:7:8", false);
+ testIsWellFormedHostIp6("1:2:3:4:5:6:7:8::", false);
+}
+
+TEST(IsWellFormedHostIp6, NonHex) {
+ testIsWellFormedHostIp6("000g::", false);
+ testIsWellFormedHostIp6("00g0::", false);
+ testIsWellFormedHostIp6("0g00::", false);
+ testIsWellFormedHostIp6("g000::", false);
+
+ testIsWellFormedHostIp6("000G::", false);
+ testIsWellFormedHostIp6("00G0::", false);
+ testIsWellFormedHostIp6("0G00::", false);
+ testIsWellFormedHostIp6("G000::", false);
+}
+
+TEST(IsWellFormedHostIp6, IpFuture) {
+ testIsWellFormedHostIp6("v7.host", false);
+ testIsWellFormedHostIp6("V7.host", false);
+}
+
+TEST(SetHostIp6, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetHostIp6A(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp6, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const host = "::1";
+ const char * const first = NULL;
+ const char * const afterLast = host + strlen(host);
+ ASSERT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp6, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "::1";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIp6, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old/");
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme://host//path1/path2");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedDotNotInserted) {
+ UriUriA uri = parseWellFormedUri("//host/./path1/path2");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:/path");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedPriorIp4) {
+ UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedPriorIp6) {
+ UriUriA uri = parseWellFormedUri("scheme://[::1]/path");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NullValueAppliedPriorRegName) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, MutationTesting) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "1:23:456:7890::5.43.219.0";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://[0001:0023:0456:7890:0000:0000:052b:db00]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp4) {
+ UriUriA uri = parseWellFormedUri("//1.2.3.4");
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp6) {
+ UriUriA uri = parseWellFormedUri("//[::1]");
+ const char * const first = "::2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0002]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("//[v7.host]");
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorRegName) {
+ UriUriA uri = parseWellFormedUri("//hostname.test");
+ const char * const first = "::1";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, UriWithPortRejected) {
+ UriUriA uri = parseWellFormedUri("//host:1234");
+ EXPECT_TRUE(uri.portText.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIp6, UriWithUserInfoRejected) {
+ UriUriA uri = parseWellFormedUri("//user:password@host");
+ EXPECT_TRUE(uri.userInfo.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIp6A(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetHostIpFuture.cpp b/test/SetHostIpFuture.cpp
new file mode 100644
index 0000000..7601ae0
--- /dev/null
+++ b/test/SetHostIpFuture.cpp
@@ -0,0 +1,300 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedHostIpFuture(const char * candidate,
+ bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed =
+ (uriIsWellFormedHostIpFutureA(first, afterLast) == URI_SUCCESS) ? URI_TRUE
+ : URI_FALSE;
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+static void assertIpFutureMatchHostText(const UriUriA * uri) {
+ ASSERT_TRUE(uri != NULL);
+ EXPECT_TRUE(uri->hostText.first != NULL);
+ EXPECT_TRUE(uri->hostText.afterLast != NULL);
+ EXPECT_EQ(uri->hostText.first, uri->hostData.ipFuture.first);
+ EXPECT_EQ(uri->hostText.afterLast, uri->hostData.ipFuture.afterLast);
+}
+
+} // namespace
+
+TEST(IsWellFormedHostIpFuture, Null) {
+ testIsWellFormedHostIpFuture(NULL, false);
+}
+
+TEST(IsWellFormedHostIpFuture, Empty) {
+ testIsWellFormedHostIpFuture("", false);
+}
+
+TEST(IsWellFormedHostIpFuture, Ip6) {
+ testIsWellFormedHostIpFuture("abcd:ef01:2345:6789:abcd:ef01:2345:6789", false);
+}
+
+TEST(IsWellFormedHostIpFuture, Lowercase) {
+ testIsWellFormedHostIpFuture("v7.host", true);
+}
+
+TEST(IsWellFormedHostIpFuture, Uppercase) {
+ testIsWellFormedHostIpFuture("V7.HOST", true);
+}
+
+TEST(SetHostIpFuture, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetHostIpFutureA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIpFuture, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const host = "v7.host";
+ const char * const first = NULL;
+ const char * const afterLast = host + strlen(host);
+ ASSERT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIpFuture, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "v7.host";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostIpFuture, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old/");
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme://host//path1/path2");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedDotNotInserted) {
+ UriUriA uri = parseWellFormedUri("//host/./path1/path2");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:/path");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedPriorIp4) {
+ UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedPriorIp6) {
+ UriUriA uri = parseWellFormedUri("scheme://[::1]/path");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NullValueAppliedPriorRegName) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://[v7.host]");
+ assertIpFutureMatchHostText(&uri);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIp4) {
+ UriUriA uri = parseWellFormedUri("//1.2.3.4");
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[v7.host]");
+ assertIpFutureMatchHostText(&uri);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIp6) {
+ UriUriA uri = parseWellFormedUri("//[::1]");
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[v7.host]");
+ assertIpFutureMatchHostText(&uri);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("//[v7.old]");
+ const char * const first = "v7.new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[v7.new]");
+ assertIpFutureMatchHostText(&uri);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, NonNullValueAppliedNonEmptyPriorRegName) {
+ UriUriA uri = parseWellFormedUri("//hostname.test");
+ const char * const first = "v7.host";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//[v7.host]");
+ assertIpFutureMatchHostText(&uri);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, UriWithPortRejected) {
+ UriUriA uri = parseWellFormedUri("//host:1234");
+ EXPECT_TRUE(uri.portText.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostIpFuture, UriWithUserInfoRejected) {
+ UriUriA uri = parseWellFormedUri("//user:password@host");
+ EXPECT_TRUE(uri.userInfo.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostIpFutureA(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetHostRegName.cpp b/test/SetHostRegName.cpp
new file mode 100644
index 0000000..4a525b1
--- /dev/null
+++ b/test/SetHostRegName.cpp
@@ -0,0 +1,336 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedHostRegName(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedHostRegNameA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedHostRegName, Null) {
+ testIsWellFormedHostRegName(NULL, false);
+}
+
+TEST(IsWellFormedHostRegName, Empty) {
+ testIsWellFormedHostRegName("", true);
+}
+
+TEST(IsWellFormedHostRegName, AllowedCharacters) {
+ // The related grammar subset is this:
+ //
+ // reg-name = *( unreserved / pct-encoded / sub-delims )
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ // pct-encoded = "%" HEXDIG HEXDIG
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ //
+ // NOTE: Percent encoding has dedicated tests further down
+ testIsWellFormedHostRegName("0123456789"
+ "ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "-._~"
+ "!$&'()*+,;=",
+ true);
+}
+
+TEST(IsWellFormedHostRegName, ForbiddenCharacters) {
+ testIsWellFormedHostRegName(" ", false);
+}
+
+TEST(IsWellFormedHostRegName, PercentEncodingWellFormed) {
+ testIsWellFormedHostRegName("%"
+ "aa"
+ "%"
+ "AA",
+ true);
+}
+
+TEST(IsWellFormedHostRegName, PercentEncodingMalformedCutOff1) {
+ testIsWellFormedHostRegName("%", false);
+}
+
+TEST(IsWellFormedHostRegName, PercentEncodingMalformedCutOff2) {
+ testIsWellFormedHostRegName("%"
+ "a",
+ false);
+}
+
+TEST(IsWellFormedHostRegName, PercentEncodingMalformedForbiddenCharacter1) {
+ testIsWellFormedHostRegName("%"
+ "ga",
+ false);
+}
+
+TEST(IsWellFormedHostRegName, PercentEncodingMalformedForbiddenCharacter2) {
+ testIsWellFormedHostRegName("%"
+ "ag",
+ false);
+}
+
+TEST(SetHostRegName, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetHostRegNameA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostRegName, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const fragment = "localhost";
+ const char * const first = NULL;
+ const char * const afterLast = fragment + strlen(fragment);
+ ASSERT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostRegName, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "localhost";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetHostRegName, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old/");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme://host//path1/path2");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.//path1/path2"); // i.e. not scheme://path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedDotNotInserted) {
+ UriUriA uri = parseWellFormedUri("//host/./path1/path2");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/./path1/path2"); // i.e. not /././path1/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:/path");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedPriorIp4) {
+ UriUriA uri = parseWellFormedUri("scheme://1.2.3.4/path");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedPriorIp6) {
+ UriUriA uri = parseWellFormedUri("scheme://[::1]/path");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("scheme://[v7.host]/path");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NullValueAppliedPriorRegName) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:///path");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorNull) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://localhost");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIp4) {
+ UriUriA uri = parseWellFormedUri("//1.2.3.4");
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//localhost");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIp6) {
+ UriUriA uri = parseWellFormedUri("//[::1]");
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//localhost");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorIpFuture) {
+ UriUriA uri = parseWellFormedUri("//[v7.host]");
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//localhost");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, NonNullValueAppliedNonEmptyPriorRegName) {
+ UriUriA uri = parseWellFormedUri("//hostname.test");
+ const char * const first = "localhost";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//localhost");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, UriWithPortRejected) {
+ UriUriA uri = parseWellFormedUri("//host:1234");
+ EXPECT_TRUE(uri.portText.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_ERROR_SETHOST_PORT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetHostRegName, UriWithUserInfoRejected) {
+ UriUriA uri = parseWellFormedUri("//user:password@host");
+ EXPECT_TRUE(uri.userInfo.first != NULL); // self-test
+
+ EXPECT_EQ(uriSetHostRegNameA(&uri, NULL, NULL), URI_ERROR_SETHOST_USERINFO_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetPath.cpp b/test/SetPath.cpp
new file mode 100644
index 0000000..fcb971f
--- /dev/null
+++ b/test/SetPath.cpp
@@ -0,0 +1,450 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedPath(const char * candidate, bool hasHost,
+ bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedPathA(first, afterLast, hasHost);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedPath, Null) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath(NULL, hasHost, false);
+ }
+}
+
+TEST(IsWellFormedPath, Empty) {
+ testIsWellFormedPath("", /* hasHost=*/true, false);
+ testIsWellFormedPath("", /* hasHost=*/false, true);
+}
+
+TEST(IsWellFormedPath, NonEmptyWithoutLeadingSlash) {
+ testIsWellFormedPath("no-leading-slash", /* hasHost=*/true, false);
+ testIsWellFormedPath("no-leading-slash", /* hasHost=*/false, true);
+}
+
+TEST(IsWellFormedPath, NonEmptySingleSlash) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/", hasHost, true);
+ }
+}
+
+TEST(IsWellFormedPath, NonEmptyTwoSlashes) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("//", hasHost, true);
+ }
+}
+
+TEST(IsWellFormedPath, AllowedCharacters) {
+ // The (simplified) related grammar subset is this:
+ //
+ // path = *( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" )
+ //
+ // NOTE: Percent encoding has dedicated tests further down
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "0123456789"
+ "ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "-._~"
+ "!$&'()*+,;="
+ ":@",
+ hasHost, true);
+ }
+}
+
+TEST(IsWellFormedPath, ForbiddenCharacters) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/ ", hasHost, false);
+ testIsWellFormedPath("/?", hasHost, false);
+ testIsWellFormedPath("/#", hasHost, false);
+ }
+}
+
+TEST(IsWellFormedPath, PercentEncodingWellFormed) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "%"
+ "aa"
+ "%"
+ "AA",
+ hasHost, true);
+ }
+}
+
+TEST(IsWellFormedPath, PercentEncodingMalformedCutOff1) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "%",
+ hasHost, false);
+ }
+}
+
+TEST(IsWellFormedPath, PercentEncodingMalformedCutOff2) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "%"
+ "a",
+ hasHost, false);
+ }
+}
+
+TEST(IsWellFormedPath, PercentEncodingMalformedForbiddenCharacter1) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "%"
+ "ga",
+ hasHost, false);
+ }
+}
+
+TEST(IsWellFormedPath, PercentEncodingMalformedForbiddenCharacter2) {
+ const bool hasHostValues[] = {true, false};
+ for (size_t i = 0; i < sizeof(hasHostValues) / sizeof(hasHostValues[0]); i++) {
+ const UriBool hasHost = hasHostValues[i] ? URI_TRUE : URI_FALSE;
+ testIsWellFormedPath("/"
+ "%"
+ "ag",
+ hasHost, false);
+ }
+}
+
+TEST(SetPath, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "path1/path2";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetPathA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPath, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const path = "path1/path2";
+ const char * const first = NULL;
+ const char * const afterLast = path + strlen(path);
+ ASSERT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPath, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "path1/path2";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPath, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("/path");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("//host/old");
+ const char * const first = "/new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NullValueAppliedWithHost) {
+ UriUriA uri = parseWellFormedUri("//host/path");
+
+ EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NullValueAppliedWithoutHost) {
+ UriUriA uri = parseWellFormedUri("scheme:/path");
+
+ EXPECT_EQ(uriSetPathA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedSingleSlashWithHost) {
+ UriUriA uri = parseWellFormedUri("//host/path");
+ const char * const first = "/";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host/");
+ EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedSingleSlashWithoutHost) {
+ UriUriA uri = parseWellFormedUri("scheme:path");
+ const char * const first = "/";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/");
+ EXPECT_EQ(uri.absolutePath, URI_TRUE);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedTwoSlashesWithHost) {
+ UriUriA uri = parseWellFormedUri("//host/path");
+ const char * const first = "//";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host//");
+ EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedTwoSlashesWithoutHostDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme:path");
+ const char * const first = "//";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.//"); // i.e. not scheme://
+ EXPECT_EQ(uri.absolutePath, URI_TRUE);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedThreeSlashesWithHost) {
+ UriUriA uri = parseWellFormedUri("//host/path");
+ const char * const first = "///";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host///");
+ EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedThreeSlashesWithoutHostDotInserted) {
+ UriUriA uri = parseWellFormedUri("scheme:path");
+ const char * const first = "///";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/.///"); // i.e. not scheme:///
+ EXPECT_EQ(uri.absolutePath, URI_TRUE);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedEmptyWithHost) {
+ UriUriA uri = parseWellFormedUri("//host/path");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetPathA(&uri, empty, empty), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedEmptyWithoutHost) {
+ UriUriA uri = parseWellFormedUri("scheme:path");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetPathA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:");
+ EXPECT_TRUE(uri.pathHead == NULL);
+ EXPECT_TRUE(uri.pathTail == NULL);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithEmptyHost) {
+ UriUriA uri = parseWellFormedUri("file:///old1/old2");
+ const char * const first = "/new1/new2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "file:///new1/new2");
+ EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithNonEmptyHost) {
+ UriUriA uri = parseWellFormedUri("//host/old1/old2");
+ const char * const first = "/new1/new2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host/new1/new2");
+ EXPECT_EQ(uri.absolutePath, URI_FALSE); // always false for URIs with host
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostRel) {
+ UriUriA uri = parseWellFormedUri("/old1/old2");
+ const char * const first = "new1/new2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "new1/new2");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostRelDotInserted) {
+ UriUriA uri = parseWellFormedUri("/old1/old2");
+ const char * const first = "path1:/path2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "./path1:/path2"); // i.e. not path1:/path2
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostAbs) {
+ UriUriA uri = parseWellFormedUri("old1/old2");
+ const char * const first = "/new1/new2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/new1/new2");
+ EXPECT_EQ(uri.absolutePath, URI_TRUE);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostAbsDotInserted) {
+ UriUriA uri = parseWellFormedUri("old1/old2");
+ const char * const first = "//path1/path2";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/.//path1/path2"); // i.e. not //path1/path2
+ EXPECT_EQ(uri.absolutePath, URI_TRUE);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, NonNullValueAppliedNonEmptyWithoutHostWithScheme) {
+ UriUriA uri = parseWellFormedUri("scheme:");
+ const char * const first = "path1:/path2/path3";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:path1:/path2/path3");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPath, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("/path");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPathA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetPort.cpp b/test/SetPort.cpp
new file mode 100644
index 0000000..d27361c
--- /dev/null
+++ b/test/SetPort.cpp
@@ -0,0 +1,191 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedPort(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedPortA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedPort, Null) {
+ testIsWellFormedPort(NULL, false);
+}
+
+TEST(IsWellFormedPort, Empty) {
+ testIsWellFormedPort("", true);
+}
+
+TEST(IsWellFormedPort, AllowedCharacters) {
+ testIsWellFormedPort("0123456789", true);
+}
+
+TEST(IsWellFormedPort, ForbiddenCharacters) {
+ testIsWellFormedPort(" ", false);
+}
+
+TEST(SetPortText, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "443";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetPortTextA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPortText, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const postText = "443";
+ const char * const first = NULL;
+ const char * const afterLast = postText + strlen(postText);
+ ASSERT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPortText, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "443";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetPortText, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+ const char * const first = "50443";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, NullValueApplied) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+
+ EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "https://host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetPortTextA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "https://host:/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, NonNullValueAppliedNonEmpty) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+ const char * const first = "50443";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "https://host:50443/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("https://host:443/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, UriWithoutHostNullTolerated) {
+ const char * originalText = "/no/host/here";
+ UriUriA uri = parseWellFormedUri(originalText);
+
+ EXPECT_EQ(uriSetPortTextA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, originalText);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetPortText, UriWithoutHostNonNullRejected) {
+ UriUriA uri = parseWellFormedUri("/no/host/here");
+ const char * const first = "443";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_TRUE(uri.hostText.first == NULL); // self-test
+
+ EXPECT_EQ(uriSetPortTextA(&uri, first, afterLast), URI_ERROR_SETPORT_HOST_NOT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetQuery.cpp b/test/SetQuery.cpp
new file mode 100644
index 0000000..3a69d17
--- /dev/null
+++ b/test/SetQuery.cpp
@@ -0,0 +1,231 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedQuery(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedQueryA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedQuery, Null) {
+ testIsWellFormedQuery(NULL, false);
+}
+
+TEST(IsWellFormedQuery, Empty) {
+ testIsWellFormedQuery("", true);
+}
+
+TEST(IsWellFormedQuery, AllowedCharacters) {
+ // The related grammar subset is this:
+ //
+ // query = *( pchar / "/" / "?" )
+ // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ // pct-encoded = "%" HEXDIG HEXDIG
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ //
+ // NOTE: Percent encoding has dedicated tests further down
+ testIsWellFormedQuery("0123456789"
+ "ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "-._~"
+ "!$&'()*+,;="
+ ":@"
+ "/?",
+ true);
+}
+
+TEST(IsWellFormedQuery, ForbiddenCharacters) {
+ testIsWellFormedQuery(" ", false);
+ testIsWellFormedQuery("#", false);
+}
+
+TEST(IsWellFormedQuery, PercentEncodingWellFormed) {
+ testIsWellFormedQuery("%"
+ "aa"
+ "%"
+ "AA",
+ true);
+}
+
+TEST(IsWellFormedQuery, PercentEncodingMalformedCutOff1) {
+ testIsWellFormedQuery("%", false);
+}
+
+TEST(IsWellFormedQuery, PercentEncodingMalformedCutOff2) {
+ testIsWellFormedQuery("%"
+ "a",
+ false);
+}
+
+TEST(IsWellFormedQuery, PercentEncodingMalformedForbiddenCharacter1) {
+ testIsWellFormedQuery("%"
+ "ga",
+ false);
+}
+
+TEST(IsWellFormedQuery, PercentEncodingMalformedForbiddenCharacter2) {
+ testIsWellFormedQuery("%"
+ "ag",
+ false);
+}
+
+TEST(SetQuery, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "k1=v1";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetQueryA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetQuery, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const query = "k1=v1";
+ const char * const first = NULL;
+ const char * const afterLast = query + strlen(query);
+ ASSERT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetQuery, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "k1=v1";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetQuery, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?query");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetQueryA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?old");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, NullValueApplied) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?query");
+
+ EXPECT_EQ(uriSetQueryA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?query");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetQueryA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/?");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, NonNullValueAppliedNonEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?old");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/?new");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/?query");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetQuery, UriWithoutHostTolerated) {
+ UriUriA uri = parseWellFormedUri("/no/host/here");
+ const char * const first = "k1=v1";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_TRUE(uri.hostText.first == NULL); // self-test
+
+ EXPECT_EQ(uriSetQueryA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/no/host/here?k1=v1");
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetScheme.cpp b/test/SetScheme.cpp
new file mode 100644
index 0000000..a609ab7
--- /dev/null
+++ b/test/SetScheme.cpp
@@ -0,0 +1,230 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedScheme(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedSchemeA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedScheme, Null) {
+ testIsWellFormedScheme(NULL, false);
+}
+
+TEST(IsWellFormedScheme, Empty) {
+ testIsWellFormedScheme("", false);
+}
+
+TEST(IsWellFormedScheme, AllowedCharacters) {
+ // The related grammar subset is this:
+ //
+ // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ //
+ testIsWellFormedScheme("ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "0123456789"
+ "+-.",
+ true);
+}
+
+TEST(IsWellFormedScheme, ForbiddenCharacters) {
+ testIsWellFormedScheme(" ", false);
+}
+
+TEST(SetScheme, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "ssh";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetSchemeA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetScheme, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const scheme = "ssh";
+ const char * const first = NULL;
+ const char * const afterLast = scheme + strlen(scheme);
+ ASSERT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetScheme, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "ssh";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetScheme, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("//host/");
+ const char * const first = "ssh";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedHost) {
+ UriUriA uri = parseWellFormedUri("ssh://host/");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedPathWithoutColon) {
+ UriUriA uri = parseWellFormedUri("scheme:path1/path2/path3");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "path1/path2/path3");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedPathWithColonRelativeDotPrepended) {
+ UriUriA uri = parseWellFormedUri("scheme:path1:/path2/path3");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "./path1:/path2/path3"); // i.e. not path1:/path2/path3
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedPathWithColonRelativeDotNotPrepended) {
+ UriUriA uri = parseWellFormedUri("scheme:path1/path2:/path3");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "path1/path2:/path3"); // i.e. not ./path1/path2:/path3
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedPathWithColonAbsolute) {
+ UriUriA uri = parseWellFormedUri("scheme:/path1:/path2/path3");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "/path1:/path2/path3");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NullValueAppliedPathWithColonAndHost) {
+ UriUriA uri = parseWellFormedUri("scheme://host/path1:/path2/path3");
+
+ EXPECT_EQ(uriSetSchemeA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "//host/path1:/path2/path3");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, NonNullValueApplied) {
+ UriUriA uri = parseWellFormedUri("old://host/");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "new://host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetScheme, UriWithoutHostTolerated) {
+ UriUriA uri = parseWellFormedUri("/no/host/here");
+ const char * const first = "scheme";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_TRUE(uri.hostText.first == NULL); // self-test
+
+ EXPECT_EQ(uriSetSchemeA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme:/no/host/here");
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/SetUserInfo.cpp b/test/SetUserInfo.cpp
new file mode 100644
index 0000000..304e8af
--- /dev/null
+++ b/test/SetUserInfo.cpp
@@ -0,0 +1,238 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2025, Sebastian Pipping <sebastian@pipping.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#undef NDEBUG // because we rely on assert(3) further down
+
+#include <cassert>
+
+#include <gtest/gtest.h>
+
+#include <uriparser/Uri.h>
+
+namespace {
+
+static void testIsWellFormedUserInfo(const char * candidate, bool expectedWellFormed) {
+ const char * const first = candidate;
+ const char * const afterLast =
+ (candidate == NULL) ? NULL : (candidate + strlen(candidate));
+
+ const UriBool actualWellFormed = uriIsWellFormedUserInfoA(first, afterLast);
+
+ ASSERT_EQ(actualWellFormed, expectedWellFormed);
+}
+
+static UriUriA parseWellFormedUri(const char * text) {
+ UriUriA uri;
+ const int error = uriParseSingleUriA(&uri, text, NULL);
+ // NOTE: we cannot use ASSERT_EQ here because of the outer non-void return type
+ assert(error == URI_SUCCESS);
+ return uri;
+}
+
+static void assertUriEqual(const UriUriA * uri, const char * expected) {
+ int charsRequired = -1;
+ ASSERT_EQ(uriToStringCharsRequiredA(uri, &charsRequired), URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= 0);
+
+ char * const buffer = (char *)malloc(charsRequired + 1);
+ ASSERT_TRUE(buffer != NULL);
+
+ ASSERT_EQ(uriToStringA(buffer, uri, charsRequired + 1, NULL), URI_SUCCESS);
+
+ EXPECT_STREQ(buffer, expected);
+
+ free(buffer);
+}
+
+} // namespace
+
+TEST(IsWellFormedUserInfo, Null) {
+ testIsWellFormedUserInfo(NULL, false);
+}
+
+TEST(IsWellFormedUserInfo, Empty) {
+ testIsWellFormedUserInfo("", true);
+}
+
+TEST(IsWellFormedUserInfo, AllowedCharacters) {
+ // The related grammar subset is this:
+ //
+ // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ // pct-encoded = "%" HEXDIG HEXDIG
+ // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ // / "*" / "+" / "," / ";" / "="
+ //
+ // NOTE: Percent encoding has dedicated tests further down
+ testIsWellFormedUserInfo("0123456789"
+ "ABCDEF"
+ "abcdef"
+ "gGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
+ "-._~"
+ "!$&'()*+,;="
+ ":",
+ true);
+}
+
+TEST(IsWellFormedUserInfo, ForbiddenCharacters) {
+ testIsWellFormedUserInfo(" ", false);
+}
+
+TEST(IsWellFormedUserInfo, PercentEncodingWellFormed) {
+ testIsWellFormedUserInfo("%"
+ "aa"
+ "%"
+ "AA",
+ true);
+}
+
+TEST(IsWellFormedUserInfo, PercentEncodingMalformedCutOff1) {
+ testIsWellFormedUserInfo("%", false);
+}
+
+TEST(IsWellFormedUserInfo, PercentEncodingMalformedCutOff2) {
+ testIsWellFormedUserInfo("%"
+ "a",
+ false);
+}
+
+TEST(IsWellFormedUserInfo, PercentEncodingMalformedForbiddenCharacter1) {
+ testIsWellFormedUserInfo("%"
+ "ga",
+ false);
+}
+
+TEST(IsWellFormedUserInfo, PercentEncodingMalformedForbiddenCharacter2) {
+ testIsWellFormedUserInfo("%"
+ "ag",
+ false);
+}
+
+TEST(SetUserInfo, NullUriOnly) {
+ UriUriA * const uri = NULL;
+ const char * const first = "user:password";
+ const char * const afterLast = first + strlen(first);
+ ASSERT_EQ(uriSetUserInfoA(uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetUserInfo, NullFirstOnly) {
+ UriUriA uri = {};
+ const char * const userInfo = "user:password";
+ const char * const first = NULL;
+ const char * const afterLast = userInfo + strlen(userInfo);
+ ASSERT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetUserInfo, NullAfterLastOnly) {
+ UriUriA uri = {};
+ const char * const first = "user:password";
+ const char * const afterLast = NULL;
+ ASSERT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_NULL);
+}
+
+TEST(SetUserInfo, NullValueLeavesOwnerAtFalse) {
+ UriUriA uri = parseWellFormedUri("scheme://userinfo@host/");
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_FALSE); // i.e. still false
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, NonNullValueMakesOwner) {
+ UriUriA uri = parseWellFormedUri("scheme://old@host/");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_EQ(uri.owner, URI_FALSE); // self-test
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_SUCCESS);
+
+ EXPECT_EQ(uri.owner, URI_TRUE); // i.e. now owned
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, NullValueApplied) {
+ UriUriA uri = parseWellFormedUri("scheme://old@host/");
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, NonNullValueAppliedEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://old@host/");
+ const char * const empty = "";
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, empty, empty), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://@host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, NonNullValueAppliedNonEmpty) {
+ UriUriA uri = parseWellFormedUri("scheme://old@host/");
+ const char * const first = "new";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_SUCCESS);
+
+ assertUriEqual(&uri, "scheme://new@host/");
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, MalformedValueRejected) {
+ UriUriA uri = parseWellFormedUri("scheme://userinfo@host/");
+ const char * const first = "not well-formed";
+ const char * const afterLast = first + strlen(first);
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast), URI_ERROR_SYNTAX);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, UriWithoutHostNullTolerated) {
+ const char * const originalText = "/no/host/here";
+ UriUriA uri = parseWellFormedUri(originalText);
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, NULL, NULL), URI_SUCCESS);
+
+ assertUriEqual(&uri, originalText);
+
+ uriFreeUriMembersA(&uri);
+}
+
+TEST(SetUserInfo, UriWithoutHostNonNullRejected) {
+ UriUriA uri = parseWellFormedUri("/no/host/here");
+ const char * const first = "user:password";
+ const char * const afterLast = first + strlen(first);
+ EXPECT_TRUE(uri.hostText.first == NULL); // self-test
+
+ EXPECT_EQ(uriSetUserInfoA(&uri, first, afterLast),
+ URI_ERROR_SETUSERINFO_HOST_NOT_SET);
+
+ uriFreeUriMembersA(&uri);
+}
diff --git a/test/VersionSuite.cpp b/test/VersionSuite.cpp
index 01f0284..cdc03b8 100644
--- a/test/VersionSuite.cpp
+++ b/test/VersionSuite.cpp
@@ -22,22 +22,20 @@
#include <cstdio>
-
#include "UriConfig.h" // for PACKAGE_VERSION
-#include <uriparser/UriBase.h>
-
+#include <uriparser/Uri.h>
TEST(VersionSuite, EnsureVersionDefinesInSync) {
- char INSIDE_VERSION[256];
- const int bytes_printed = sprintf(INSIDE_VERSION, "%d.%d.%d%s",
- URI_VER_MAJOR, URI_VER_MINOR, URI_VER_RELEASE, URI_VER_SUFFIX_ANSI);
- ASSERT_TRUE(bytes_printed != -1);
+ char INSIDE_VERSION[256];
+ const int bytes_printed =
+ sprintf(INSIDE_VERSION, "%d.%d.%d%s", URI_VER_MAJOR, URI_VER_MINOR,
+ URI_VER_RELEASE, URI_VER_SUFFIX_ANSI);
+ ASSERT_NE(bytes_printed, -1);
+ EXPECT_STREQ(INSIDE_VERSION, PACKAGE_VERSION);
+}
- const bool equal = !strcmp(INSIDE_VERSION, PACKAGE_VERSION);
- if (! equal) {
- printf("Inside/outside version mismatch detected:\n");
- printf(" Tarball version: <%s>\n", PACKAGE_VERSION);
- printf(" Header defines version: <%s>\n", INSIDE_VERSION);
- }
- ASSERT_TRUE(equal);
+TEST(VersionSuite, EnsureRuntimeVersionAsExpected) {
+ // NOTE: This needs a bump for every release
+ EXPECT_STREQ(uriBaseRuntimeVersionA(), "1.0.1");
+ EXPECT_STREQ(uriBaseRuntimeVersionW(), L"1.0.1");
}
diff --git a/test/copy.cpp b/test/copy.cpp
new file mode 100644
index 0000000..b058c98
--- /dev/null
+++ b/test/copy.cpp
@@ -0,0 +1,202 @@
+/*
+ * uriparser - RFC 3986 URI parsing library
+ *
+ * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+ * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+ * Copyright (C) 2025, Máté Kocsis <kocsismate@php.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <uriparser/Uri.h>
+#include <uriparser/UriIp4.h>
+#include <gtest/gtest.h>
+#include <memory>
+#include <cstdio>
+#include <cstdlib>
+#include <cwchar>
+#include <string>
+
+using namespace std;
+
+namespace {
+void testCopyUri(UriUriA * destUri, const char * const sourceUriString) {
+ UriUriA sourceUri;
+
+ ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS);
+
+ ASSERT_EQ(URI_SUCCESS, uriCopyUriA(destUri, &sourceUri));
+ ASSERT_EQ(URI_TRUE, uriEqualsUriA(destUri, &sourceUri));
+
+ uriFreeUriMembersA(&sourceUri);
+}
+} // namespace
+
+TEST(CopyUriSuite, ErrorSourceUriNull) {
+ UriUriA destUri;
+
+ ASSERT_EQ(uriCopyUriA(&destUri, NULL), URI_ERROR_NULL);
+}
+
+TEST(CopyUriSuite, ErrorDestUriNull) {
+ UriUriA sourceUri;
+ const char * const sourceUriString = "https://example.com";
+
+ ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS);
+
+ ASSERT_EQ(URI_ERROR_NULL, uriCopyUriA(NULL, &sourceUri));
+
+ uriFreeUriMembersA(&sourceUri);
+}
+
+TEST(CopyUriSuite, ErrorIncompleteMemoryManager) {
+ UriUriA sourceUri;
+ const char * const sourceUriString = "https://example.com";
+ UriMemoryManager memory = {NULL, NULL, NULL, NULL, NULL, NULL};
+
+ ASSERT_EQ(uriParseSingleUriA(&sourceUri, sourceUriString, NULL), URI_SUCCESS);
+
+ UriUriA destUri;
+ ASSERT_EQ(URI_ERROR_MEMORY_MANAGER_INCOMPLETE,
+ uriCopyUriMmA(&destUri, &sourceUri, &memory));
+
+ uriFreeUriMembersA(&sourceUri);
+}
+
+TEST(CopyUriSuite, SuccessRegName) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "https://somehost.com");
+
+ ASSERT_TRUE(destUri.hostData.ip4 == NULL);
+ ASSERT_TRUE(destUri.hostData.ip6 == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL);
+ ASSERT_EQ(0, strncmp(destUri.hostText.first, "somehost.com", strlen("somehost.com")));
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessCompleteUri) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "https://user:pass@somehost.com:80/path?query#frag");
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessRelativeReference) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "/foo/bar/baz");
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessEmail) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "mailto:fred@example.com");
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessIpV4) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "http://192.168.0.1/");
+
+ const unsigned char expected[4] = {192, 168, 0, 1};
+ ASSERT_EQ(memcmp(expected, destUri.hostData.ip4->data, sizeof(expected)), 0);
+
+ ASSERT_TRUE(destUri.hostData.ip6 == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL);
+ ASSERT_EQ(0, strncmp(destUri.hostText.first, "192.168.0.1", strlen("192.168.0.1")));
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessIpV6) {
+ UriUriA destUri;
+ testCopyUri(&destUri,
+ "https://[2001:0db8:0001:0000:0000:0ab9:c0a8:0102]"); // RFC 3849
+
+ const unsigned char expected[16] = {0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0xb9, 0xc0, 0xa8, 0x01, 0x02};
+ ASSERT_EQ(memcmp(expected, destUri.hostData.ip6->data, sizeof(expected)), 0);
+
+ ASSERT_TRUE(destUri.hostData.ip4 == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(destUri.hostData.ipFuture.afterLast == NULL);
+ ASSERT_EQ(0,
+ strncmp(destUri.hostText.first, "2001:0db8:0001:0000:0000:0ab9:c0a8:0102",
+ strlen("2001:0db8:0001:0000:0000:0ab9:c0a8:0102")));
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessIpFuture) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "//[v7.host]/source");
+
+ ASSERT_EQ(0, strncmp(destUri.hostData.ipFuture.first, "v7.host", strlen("v7.host")));
+
+ ASSERT_TRUE(destUri.hostData.ip4 == NULL);
+ ASSERT_TRUE(destUri.hostData.ip6 == NULL);
+ ASSERT_TRUE(destUri.hostText.first == destUri.hostData.ipFuture.first);
+ ASSERT_TRUE(destUri.hostText.afterLast == destUri.hostData.ipFuture.afterLast);
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessEmptyPort) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "http://example.com:/");
+
+ ASSERT_TRUE(destUri.portText.first != NULL);
+ ASSERT_TRUE(destUri.portText.afterLast != NULL);
+ ASSERT_EQ(destUri.portText.first, destUri.portText.afterLast);
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessEmptyUserInfo) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "http://@example.com/");
+
+ ASSERT_TRUE(destUri.userInfo.first != NULL);
+ ASSERT_TRUE(destUri.userInfo.afterLast != NULL);
+ ASSERT_EQ(destUri.userInfo.first, destUri.userInfo.afterLast);
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessEmptyQuery) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "http://example.com/?");
+
+ ASSERT_TRUE(destUri.query.first != NULL);
+ ASSERT_TRUE(destUri.query.afterLast != NULL);
+ ASSERT_EQ(destUri.query.first, destUri.query.afterLast);
+
+ uriFreeUriMembersA(&destUri);
+}
+
+TEST(CopyUriSuite, SuccessEmptyFragment) {
+ UriUriA destUri;
+ testCopyUri(&destUri, "http://example.com/#");
+
+ ASSERT_TRUE(destUri.fragment.first != NULL);
+ ASSERT_TRUE(destUri.fragment.afterLast != NULL);
+ ASSERT_EQ(destUri.fragment.first, destUri.fragment.afterLast);
+
+ uriFreeUriMembersA(&destUri);
+}
diff --git a/test/test.cpp b/test/test.cpp
index fade025..30399b3 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -29,79 +29,75 @@
using namespace std;
-
-
extern "C" {
UriBool uri_TESTING_ONLY_ParseIpSixA(const char * text);
UriBool uri_TESTING_ONLY_ParseIpFourA(const char * text);
int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b);
}
-
-
-#define URI_TEST_IP_FOUR_FAIL(x) ASSERT_TRUE(URI_FALSE == uri_TESTING_ONLY_ParseIpFourA(x))
-#define URI_TEST_IP_FOUR_PASS(x) ASSERT_TRUE(URI_TRUE == uri_TESTING_ONLY_ParseIpFourA(x))
+#define URI_TEST_IP_FOUR_FAIL(x) ASSERT_EQ(URI_FALSE, uri_TESTING_ONLY_ParseIpFourA(x))
+#define URI_TEST_IP_FOUR_PASS(x) ASSERT_EQ(URI_TRUE, uri_TESTING_ONLY_ParseIpFourA(x))
// Note the closing brackets! TODO
-#define URI_TEST_IP_SIX_FAIL(x) ASSERT_TRUE(URI_FALSE == uri_TESTING_ONLY_ParseIpSixA(x "]"))
-#define URI_TEST_IP_SIX_PASS(x) ASSERT_TRUE(URI_TRUE == uri_TESTING_ONLY_ParseIpSixA(x "]"))
+#define URI_TEST_IP_SIX_FAIL(x) ASSERT_EQ(URI_FALSE, uri_TESTING_ONLY_ParseIpSixA(x "]"))
+#define URI_TEST_IP_SIX_PASS(x) ASSERT_EQ(URI_TRUE, uri_TESTING_ONLY_ParseIpSixA(x "]"))
-#define URI_EXPECT_BETWEEN(candidate, first, afterLast) \
- EXPECT_TRUE((candidate >= first) && (candidate <= afterLast))
+#define URI_EXPECT_BETWEEN(candidate, first, afterLast) \
+ EXPECT_TRUE((candidate >= first) && (candidate <= afterLast))
-#define URI_EXPECT_OUTSIDE(candidate, first, afterLast) \
- EXPECT_TRUE((candidate < first) || (candidate > afterLast))
+#define URI_EXPECT_OUTSIDE(candidate, first, afterLast) \
+ EXPECT_TRUE((candidate < first) || (candidate > afterLast))
-#define URI_EXPECT_RANGE_BETWEEN(range, uriFirst, uriAfterLast) \
- URI_EXPECT_BETWEEN(range.first, uriFirst, uriAfterLast); \
- URI_EXPECT_BETWEEN(range.afterLast, uriFirst, uriAfterLast)
+#define URI_EXPECT_RANGE_BETWEEN(range, uriFirst, uriAfterLast) \
+ URI_EXPECT_BETWEEN(range.first, uriFirst, uriAfterLast); \
+ URI_EXPECT_BETWEEN(range.afterLast, uriFirst, uriAfterLast)
-#define URI_EXPECT_RANGE_OUTSIDE(range, uriFirst, uriAfterLast) \
- URI_EXPECT_OUTSIDE(range.first, uriFirst, uriAfterLast); \
- URI_EXPECT_OUTSIDE(range.afterLast, uriFirst, uriAfterLast)
+#define URI_EXPECT_RANGE_OUTSIDE(range, uriFirst, uriAfterLast) \
+ URI_EXPECT_OUTSIDE(range.first, uriFirst, uriAfterLast); \
+ URI_EXPECT_OUTSIDE(range.afterLast, uriFirst, uriAfterLast)
-#define URI_EXPECT_RANGE_EMPTY(range) \
- EXPECT_TRUE((range.first != NULL) \
- && (range.afterLast != NULL) \
- && (range.first == range.afterLast))
+#define URI_EXPECT_RANGE_EMPTY(range) \
+ EXPECT_TRUE((range.first != NULL) && (range.afterLast != NULL) \
+ && (range.first == range.afterLast))
namespace {
- bool testDistinctionHelper(const char * uriText, bool expectedHostSet,
- bool expectedAbsPath, bool expectedEmptyTailSegment) {
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
-
- int res = uriParseUriA(&state, uriText);
- if (res != URI_SUCCESS) {
- uriFreeUriMembersA(&uri);
- return false;
- }
-
- if (expectedHostSet != (uri.hostText.first != NULL)) {
- uriFreeUriMembersA(&uri);
- return false;
- }
-
- if (expectedAbsPath != (uri.absolutePath == URI_TRUE)) {
- uriFreeUriMembersA(&uri);
- return false;
- }
-
- if (expectedEmptyTailSegment != ((uri.pathTail != NULL)
- && (uri.pathTail->text.first == uri.pathTail->text.afterLast))) {
- uriFreeUriMembersA(&uri);
- return false;
- }
-
- uriFreeUriMembersA(&uri);
- return true;
- }
+bool testDistinctionHelper(const char * uriText, bool expectedHostSet,
+ bool expectedAbsPath, bool expectedEmptyTailSegment) {
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+
+ int res = uriParseUriA(&state, uriText);
+ if (res != URI_SUCCESS) {
+ uriFreeUriMembersA(&uri);
+ return false;
+ }
+
+ if (expectedHostSet != (uri.hostText.first != NULL)) {
+ uriFreeUriMembersA(&uri);
+ return false;
+ }
+
+ if (expectedAbsPath != (uri.absolutePath == URI_TRUE)) {
+ uriFreeUriMembersA(&uri);
+ return false;
+ }
+
+ if (expectedEmptyTailSegment
+ != ((uri.pathTail != NULL)
+ && (uri.pathTail->text.first == uri.pathTail->text.afterLast))) {
+ uriFreeUriMembersA(&uri);
+ return false;
+ }
+
+ uriFreeUriMembersA(&uri);
+ return true;
+}
} // namespace
-
TEST(UriSuite, TestDistinction) {
- /*
+ /* clang-format off */
+ /*
============================================================================
Rule | Example | hostSet | absPath | emptySeg
------------------------------------|---------|---------|---------|---------
@@ -123,2284 +119,2413 @@ Rule | Example | hostSet | absPath | emptySeg
| "a/" | false | false | true
4) path-empty | "" | false | false | false
============================================================================
- */
- ASSERT_TRUE(testDistinctionHelper("s://", true, false, false));
- ASSERT_TRUE(testDistinctionHelper("s:///", true, false, true));
- ASSERT_TRUE(testDistinctionHelper("s://a", true, false, false));
- ASSERT_TRUE(testDistinctionHelper("s://a/", true, false, true));
- ASSERT_TRUE(testDistinctionHelper("s:/", false, true, false));
- ASSERT_TRUE(testDistinctionHelper("s:a", false, false, false));
- ASSERT_TRUE(testDistinctionHelper("s:a/", false, false, true));
- ASSERT_TRUE(testDistinctionHelper("s:", false, false, false));
-
- ASSERT_TRUE(testDistinctionHelper("//", true, false, false));
- ASSERT_TRUE(testDistinctionHelper("///", true, false, true));
- ASSERT_TRUE(testDistinctionHelper("/", false, true, false));
- ASSERT_TRUE(testDistinctionHelper("a", false, false, false));
- ASSERT_TRUE(testDistinctionHelper("a/", false, false, true));
- ASSERT_TRUE(testDistinctionHelper("", false, false, false));
+ */
+ /* clang-format on */
+ ASSERT_TRUE(testDistinctionHelper("s://", true, false, false));
+ ASSERT_TRUE(testDistinctionHelper("s:///", true, false, true));
+ ASSERT_TRUE(testDistinctionHelper("s://a", true, false, false));
+ ASSERT_TRUE(testDistinctionHelper("s://a/", true, false, true));
+ ASSERT_TRUE(testDistinctionHelper("s:/", false, true, false));
+ ASSERT_TRUE(testDistinctionHelper("s:a", false, false, false));
+ ASSERT_TRUE(testDistinctionHelper("s:a/", false, false, true));
+ ASSERT_TRUE(testDistinctionHelper("s:", false, false, false));
+
+ ASSERT_TRUE(testDistinctionHelper("//", true, false, false));
+ ASSERT_TRUE(testDistinctionHelper("///", true, false, true));
+ ASSERT_TRUE(testDistinctionHelper("/", false, true, false));
+ ASSERT_TRUE(testDistinctionHelper("a", false, false, false));
+ ASSERT_TRUE(testDistinctionHelper("a/", false, false, true));
+ ASSERT_TRUE(testDistinctionHelper("", false, false, false));
}
TEST(UriSuite, TestIpFour) {
- URI_TEST_IP_FOUR_FAIL("01.0.0.0");
- URI_TEST_IP_FOUR_FAIL("001.0.0.0");
- URI_TEST_IP_FOUR_FAIL("00.0.0.0");
- URI_TEST_IP_FOUR_FAIL("000.0.0.0");
- URI_TEST_IP_FOUR_FAIL("256.0.0.0");
- URI_TEST_IP_FOUR_FAIL("300.0.0.0");
- URI_TEST_IP_FOUR_FAIL("1111.0.0.0");
- URI_TEST_IP_FOUR_FAIL("-1.0.0.0");
- URI_TEST_IP_FOUR_FAIL("0.0.0");
- URI_TEST_IP_FOUR_FAIL("0.0.0.");
- URI_TEST_IP_FOUR_FAIL("0.0.0.0.");
- URI_TEST_IP_FOUR_FAIL("0.0.0.0.0");
- URI_TEST_IP_FOUR_FAIL("0.0..0");
- URI_TEST_IP_FOUR_FAIL(".0.0.0");
-
- URI_TEST_IP_FOUR_PASS("255.0.0.0");
- URI_TEST_IP_FOUR_PASS("0.0.0.0");
- URI_TEST_IP_FOUR_PASS("1.0.0.0");
- URI_TEST_IP_FOUR_PASS("2.0.0.0");
- URI_TEST_IP_FOUR_PASS("3.0.0.0");
- URI_TEST_IP_FOUR_PASS("30.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("01.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("001.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("00.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("000.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("256.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("300.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("1111.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("-1.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("0.0.0");
+ URI_TEST_IP_FOUR_FAIL("0.0.0.");
+ URI_TEST_IP_FOUR_FAIL("0.0.0.0.");
+ URI_TEST_IP_FOUR_FAIL("0.0.0.0.0");
+ URI_TEST_IP_FOUR_FAIL("0.0..0");
+ URI_TEST_IP_FOUR_FAIL(".0.0.0");
+
+ URI_TEST_IP_FOUR_PASS("255.0.0.0");
+ URI_TEST_IP_FOUR_PASS("0.0.0.0");
+ URI_TEST_IP_FOUR_PASS("1.0.0.0");
+ URI_TEST_IP_FOUR_PASS("2.0.0.0");
+ URI_TEST_IP_FOUR_PASS("3.0.0.0");
+ URI_TEST_IP_FOUR_PASS("30.0.0.0");
}
TEST(UriSuite, TestIpSixPass) {
- // Quad length
- URI_TEST_IP_SIX_PASS("abcd::");
-
- URI_TEST_IP_SIX_PASS("abcd::1");
- URI_TEST_IP_SIX_PASS("abcd::12");
- URI_TEST_IP_SIX_PASS("abcd::123");
- URI_TEST_IP_SIX_PASS("abcd::1234");
-
- // Full length
- URI_TEST_IP_SIX_PASS("2001:0db8:0100:f101:0210:a4ff:fee3:9566"); // lower hex
- URI_TEST_IP_SIX_PASS("2001:0DB8:0100:F101:0210:A4FF:FEE3:9566"); // Upper hex
- URI_TEST_IP_SIX_PASS("2001:db8:100:f101:210:a4ff:fee3:9566");
- URI_TEST_IP_SIX_PASS("2001:0db8:100:f101:0:0:0:1");
- URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:255.255.255.255");
-
- // Legal IPv4
- URI_TEST_IP_SIX_PASS("::1.2.3.4");
- URI_TEST_IP_SIX_PASS("3:4::5:1.2.3.4");
- URI_TEST_IP_SIX_PASS("::ffff:1.2.3.4");
- URI_TEST_IP_SIX_PASS("::0.0.0.0"); // Min IPv4
- URI_TEST_IP_SIX_PASS("::255.255.255.255"); // Max IPv4
-
- // Zipper position
- URI_TEST_IP_SIX_PASS("::1:2:3:4:5:6:7");
- URI_TEST_IP_SIX_PASS("1::1:2:3:4:5:6");
- URI_TEST_IP_SIX_PASS("1:2::1:2:3:4:5");
- URI_TEST_IP_SIX_PASS("1:2:3::1:2:3:4");
- URI_TEST_IP_SIX_PASS("1:2:3:4::1:2:3");
- URI_TEST_IP_SIX_PASS("1:2:3:4:5::1:2");
- URI_TEST_IP_SIX_PASS("1:2:3:4:5:6::1");
- URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:7::");
-
- // Zipper length
- URI_TEST_IP_SIX_PASS("1:1:1::1:1:1:1");
- URI_TEST_IP_SIX_PASS("1:1:1::1:1:1");
- URI_TEST_IP_SIX_PASS("1:1:1::1:1");
- URI_TEST_IP_SIX_PASS("1:1::1:1");
- URI_TEST_IP_SIX_PASS("1:1::1");
- URI_TEST_IP_SIX_PASS("1::1");
- URI_TEST_IP_SIX_PASS("::1"); // == localhost
- URI_TEST_IP_SIX_PASS("::"); // == all addresses
-
- // A few more variations
- URI_TEST_IP_SIX_PASS("21ff:abcd::1");
- URI_TEST_IP_SIX_PASS("2001:db8:100:f101::1");
- URI_TEST_IP_SIX_PASS("a:b:c::12:1");
- URI_TEST_IP_SIX_PASS("a:b::0:1:2:3");
-
- // Issue #146: These are not leading zeros.
- URI_TEST_IP_SIX_PASS("::100.1.1.1");
- URI_TEST_IP_SIX_PASS("::1.100.1.1");
- URI_TEST_IP_SIX_PASS("::1.1.100.1");
- URI_TEST_IP_SIX_PASS("::1.1.1.100");
- URI_TEST_IP_SIX_PASS("::100.100.100.100");
- URI_TEST_IP_SIX_PASS("::10.1.1.1");
- URI_TEST_IP_SIX_PASS("::1.10.1.1");
- URI_TEST_IP_SIX_PASS("::1.1.10.1");
- URI_TEST_IP_SIX_PASS("::1.1.1.10");
- URI_TEST_IP_SIX_PASS("::10.10.10.10");
+ // Quad length
+ URI_TEST_IP_SIX_PASS("abcd::");
+
+ URI_TEST_IP_SIX_PASS("abcd::1");
+ URI_TEST_IP_SIX_PASS("abcd::12");
+ URI_TEST_IP_SIX_PASS("abcd::123");
+ URI_TEST_IP_SIX_PASS("abcd::1234");
+
+ // Full length
+ URI_TEST_IP_SIX_PASS("2001:0db8:0100:f101:0210:a4ff:fee3:9566"); // lower hex
+ URI_TEST_IP_SIX_PASS("2001:0DB8:0100:F101:0210:A4FF:FEE3:9566"); // Upper hex
+ URI_TEST_IP_SIX_PASS("2001:db8:100:f101:210:a4ff:fee3:9566");
+ URI_TEST_IP_SIX_PASS("2001:0db8:100:f101:0:0:0:1");
+ URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:255.255.255.255");
+
+ // Legal IPv4
+ URI_TEST_IP_SIX_PASS("::1.2.3.4");
+ URI_TEST_IP_SIX_PASS("3:4::5:1.2.3.4");
+ URI_TEST_IP_SIX_PASS("::ffff:1.2.3.4");
+ URI_TEST_IP_SIX_PASS("::0.0.0.0"); // Min IPv4
+ URI_TEST_IP_SIX_PASS("::255.255.255.255"); // Max IPv4
+
+ // Zipper position
+ URI_TEST_IP_SIX_PASS("::1:2:3:4:5:6:7");
+ URI_TEST_IP_SIX_PASS("1::1:2:3:4:5:6");
+ URI_TEST_IP_SIX_PASS("1:2::1:2:3:4:5");
+ URI_TEST_IP_SIX_PASS("1:2:3::1:2:3:4");
+ URI_TEST_IP_SIX_PASS("1:2:3:4::1:2:3");
+ URI_TEST_IP_SIX_PASS("1:2:3:4:5::1:2");
+ URI_TEST_IP_SIX_PASS("1:2:3:4:5:6::1");
+ URI_TEST_IP_SIX_PASS("1:2:3:4:5:6:7::");
+
+ // Zipper length
+ URI_TEST_IP_SIX_PASS("1:1:1::1:1:1:1");
+ URI_TEST_IP_SIX_PASS("1:1:1::1:1:1");
+ URI_TEST_IP_SIX_PASS("1:1:1::1:1");
+ URI_TEST_IP_SIX_PASS("1:1::1:1");
+ URI_TEST_IP_SIX_PASS("1:1::1");
+ URI_TEST_IP_SIX_PASS("1::1");
+ URI_TEST_IP_SIX_PASS("::1"); // == localhost
+ URI_TEST_IP_SIX_PASS("::"); // == all addresses
+
+ // A few more variations
+ URI_TEST_IP_SIX_PASS("21ff:abcd::1");
+ URI_TEST_IP_SIX_PASS("2001:db8:100:f101::1");
+ URI_TEST_IP_SIX_PASS("a:b:c::12:1");
+ URI_TEST_IP_SIX_PASS("a:b::0:1:2:3");
+
+ // Issue #146: These are not leading zeros.
+ URI_TEST_IP_SIX_PASS("::100.1.1.1");
+ URI_TEST_IP_SIX_PASS("::1.100.1.1");
+ URI_TEST_IP_SIX_PASS("::1.1.100.1");
+ URI_TEST_IP_SIX_PASS("::1.1.1.100");
+ URI_TEST_IP_SIX_PASS("::100.100.100.100");
+ URI_TEST_IP_SIX_PASS("::10.1.1.1");
+ URI_TEST_IP_SIX_PASS("::1.10.1.1");
+ URI_TEST_IP_SIX_PASS("::1.1.10.1");
+ URI_TEST_IP_SIX_PASS("::1.1.1.10");
+ URI_TEST_IP_SIX_PASS("::10.10.10.10");
}
TEST(UriSuite, TestIpSixFail) {
- // 5 char quad
- URI_TEST_IP_SIX_FAIL("::12345");
-
- // Two zippers
- URI_TEST_IP_SIX_FAIL("abcd::abcd::abcd");
-
- // Triple-colon zipper
- URI_TEST_IP_SIX_FAIL(":::1234");
- URI_TEST_IP_SIX_FAIL("1234:::1234:1234");
- URI_TEST_IP_SIX_FAIL("1234:1234:::1234");
- URI_TEST_IP_SIX_FAIL("1234:::");
-
- // No quads, just IPv4
- URI_TEST_IP_SIX_FAIL("1.2.3.4");
- URI_TEST_IP_SIX_FAIL("0001.0002.0003.0004");
-
- // Five quads
- URI_TEST_IP_SIX_FAIL("0000:0000:0000:0000:0000:1.2.3.4");
-
- // Seven quads
- URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0");
- URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:");
- URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:1.2.3.4");
-
- // Nine quads (or more)
- URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8:9");
- URI_TEST_IP_SIX_FAIL("::2:3:4:5:6:7:8:9");
- URI_TEST_IP_SIX_FAIL("1:2:3:4::6:7:8:9");
- URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8::");
-
- // Invalid IPv4 part
- URI_TEST_IP_SIX_FAIL("::ffff:001.02.03.004"); // Leading zeros
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.1111"); // Four char octet
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.256"); // > 255
- URI_TEST_IP_SIX_FAIL("::ffff:311.2.3.4"); // > 155
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3:4"); // Not a dot
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3"); // Missing octet
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3."); // Missing octet
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3a.4"); // Hex in octet
- URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.4:123"); // Crap input
-
- // Nonhex
- URI_TEST_IP_SIX_FAIL("g:0:0:0:0:0:0");
-
- // Issue #146: Zipper between the 7th and 8th quads.
- URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0::1");
-
- // Issue #146: Leading or trailing ":".
- URI_TEST_IP_SIX_FAIL(":1::1");
- URI_TEST_IP_SIX_FAIL("1::1:");
- URI_TEST_IP_SIX_FAIL(":1::1:");
- URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0");
- URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:0:");
- URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0:");
-
- // Issue #146: Zipper between six quads and IPv4 address.
- URI_TEST_IP_SIX_FAIL("1:1:1:1:1:1::1.1.1.1");
+ // 5 char quad
+ URI_TEST_IP_SIX_FAIL("::12345");
+
+ // Two zippers
+ URI_TEST_IP_SIX_FAIL("abcd::abcd::abcd");
+
+ // Triple-colon zipper
+ URI_TEST_IP_SIX_FAIL(":::1234");
+ URI_TEST_IP_SIX_FAIL("1234:::1234:1234");
+ URI_TEST_IP_SIX_FAIL("1234:1234:::1234");
+ URI_TEST_IP_SIX_FAIL("1234:::");
+
+ // No quads, just IPv4
+ URI_TEST_IP_SIX_FAIL("1.2.3.4");
+ URI_TEST_IP_SIX_FAIL("0001.0002.0003.0004");
+
+ // Five quads
+ URI_TEST_IP_SIX_FAIL("0000:0000:0000:0000:0000:1.2.3.4");
+
+ // Seven quads
+ URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0");
+ URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:");
+ URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:1.2.3.4");
+
+ // Nine quads (or more)
+ URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8:9");
+ URI_TEST_IP_SIX_FAIL("::2:3:4:5:6:7:8:9");
+ URI_TEST_IP_SIX_FAIL("1:2:3:4::6:7:8:9");
+ URI_TEST_IP_SIX_FAIL("1:2:3:4:5:6:7:8::");
+
+ // Invalid IPv4 part
+ URI_TEST_IP_SIX_FAIL("::ffff:001.02.03.004"); // Leading zeros
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.1111"); // Four char octet
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.256"); // > 255
+ URI_TEST_IP_SIX_FAIL("::ffff:311.2.3.4"); // > 155
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3:4"); // Not a dot
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3"); // Missing octet
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3."); // Missing octet
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3a.4"); // Hex in octet
+ URI_TEST_IP_SIX_FAIL("::ffff:1.2.3.4:123"); // Crap input
+
+ // Nonhex
+ URI_TEST_IP_SIX_FAIL("g:0:0:0:0:0:0");
+
+ // Issue #146: Zipper between the 7th and 8th quads.
+ URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0::1");
+
+ // Issue #146: Leading or trailing ":".
+ URI_TEST_IP_SIX_FAIL(":1::1");
+ URI_TEST_IP_SIX_FAIL("1::1:");
+ URI_TEST_IP_SIX_FAIL(":1::1:");
+ URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0");
+ URI_TEST_IP_SIX_FAIL("0:0:0:0:0:0:0:0:");
+ URI_TEST_IP_SIX_FAIL(":0:0:0:0:0:0:0:0:");
+
+ // Issue #146: Zipper between six quads and IPv4 address.
+ URI_TEST_IP_SIX_FAIL("1:1:1:1:1:1::1.1.1.1");
}
TEST(UriSuite, TestIpFuture) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
- // Issue #146: The leading "v" of IPvFuture is case-insensitive.
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "//[vF.addr]"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "//[VF.addr]"));
- uriFreeUriMembersA(&uriA);
+ // Issue #146: The leading "v" of IPvFuture is case-insensitive.
+ ASSERT_EQ(0, uriParseUriA(&stateA, "//[vF.addr]"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "//[VF.addr]"));
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestIpSixOverread) {
- UriUriA uri;
- const char * errorPos;
+ UriUriA uri;
+ const char * errorPos;
- // NOTE: This string is designed to not have a terminator
- char uriText[2 + 3 + 2 + 1 + 1];
- memcpy(uriText, "//[::44.1", sizeof(uriText));
+ // NOTE: This string is designed to not have a terminator
+ char uriText[2 + 3 + 2 + 1 + 1];
+ memcpy(uriText, "//[::44.1", sizeof(uriText));
- EXPECT_EQ(uriParseSingleUriExA(&uri, uriText,
- uriText + sizeof(uriText), &errorPos), URI_ERROR_SYNTAX);
- EXPECT_EQ(errorPos, uriText + sizeof(uriText));
+ EXPECT_EQ(uriParseSingleUriExA(&uri, uriText, uriText + sizeof(uriText), &errorPos),
+ URI_ERROR_SYNTAX);
+ EXPECT_EQ(errorPos, uriText + sizeof(uriText));
}
TEST(UriSuite, TestUri) {
- UriParserStateA stateA;
- UriParserStateW stateW;
- UriUriA uriA;
- UriUriW uriW;
-
- stateA.uri = &uriA;
- stateW.uri = &uriW;
-
- // On/off for each
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "//user:pass@[::1]:80/segment/index.html?query#frag"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://[::1]:80/segment/index.html?query#frag"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]/segment/index.html?query#frag"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80?query#frag"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html#frag"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html?query"));
- uriFreeUriMembersA(&uriA);
-
- // Schema, port, one segment
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "ftp://host:21/gnu/"));
- uriFreeUriMembersA(&uriA);
-
- // Relative
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "one/two/three"));
- ASSERT_TRUE(!uriA.absolutePath);
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "/one/two/three"));
- ASSERT_TRUE(uriA.absolutePath);
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "//user:pass@localhost/one/two/three"));
- uriFreeUriMembersA(&uriA);
-
- // Both narrow and wide string version
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://www.example.com/"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriW(&stateW, L"http://www.example.com/"));
- uriFreeUriMembersW(&uriW);
-
- // Real life examples
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://sourceforge.net/projects/uriparser/"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://sourceforge.net/project/platformdownload.php?group_id=182840"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "mailto:test@example.com"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "../../"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "/"));
- ASSERT_TRUE(uriA.absolutePath);
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, ""));
- ASSERT_TRUE(!uriA.absolutePath);
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "file:///bin/bash"));
- uriFreeUriMembersA(&uriA);
-
- // Percent encoding
- ASSERT_TRUE(0 == uriParseUriA(&stateA, "http://www.example.com/name%20with%20spaces/"));
- uriFreeUriMembersA(&uriA);
- ASSERT_TRUE(0 != uriParseUriA(&stateA, "http://www.example.com/name with spaces/"));
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriParserStateW stateW;
+ UriUriA uriA;
+ UriUriW uriW;
+
+ stateA.uri = &uriA;
+ stateW.uri = &uriW;
+
+ // On/off for each
+ ASSERT_EQ(
+ 0, uriParseUriA(&stateA, "//user:pass@[::1]:80/segment/index.html?query#frag"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "http://[::1]:80/segment/index.html?query#frag"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(
+ 0, uriParseUriA(&stateA, "http://user:pass@[::1]/segment/index.html?query#frag"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "http://user:pass@[::1]:80?query#frag"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0,
+ uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html#frag"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(
+ 0, uriParseUriA(&stateA, "http://user:pass@[::1]:80/segment/index.html?query"));
+ uriFreeUriMembersA(&uriA);
+
+ // Schema, port, one segment
+ ASSERT_EQ(0, uriParseUriA(&stateA, "ftp://host:21/gnu/"));
+ uriFreeUriMembersA(&uriA);
+
+ // Relative
+ ASSERT_EQ(0, uriParseUriA(&stateA, "one/two/three"));
+ ASSERT_TRUE(!uriA.absolutePath);
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "/one/two/three"));
+ ASSERT_TRUE(uriA.absolutePath);
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "//user:pass@localhost/one/two/three"));
+ uriFreeUriMembersA(&uriA);
+
+ // Both narrow and wide string version
+ ASSERT_EQ(0, uriParseUriA(&stateA, "http://www.example.com/"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriW(&stateW, L"http://www.example.com/"));
+ uriFreeUriMembersW(&uriW);
+
+ // Real life examples
+ ASSERT_EQ(0, uriParseUriA(&stateA, "http://sourceforge.net/projects/uriparser/"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0,
+ uriParseUriA(
+ &stateA,
+ "http://sourceforge.net/project/platformdownload.php?group_id=182840"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "mailto:test@example.com"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "../../"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "/"));
+ ASSERT_TRUE(uriA.absolutePath);
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, ""));
+ ASSERT_TRUE(!uriA.absolutePath);
+ uriFreeUriMembersA(&uriA);
+ ASSERT_EQ(0, uriParseUriA(&stateA, "file:///bin/bash"));
+ uriFreeUriMembersA(&uriA);
+
+ // Percent encoding
+ ASSERT_EQ(0, uriParseUriA(&stateA, "http://www.example.com/name%20with%20spaces/"));
+ uriFreeUriMembersA(&uriA);
+ ASSERT_NE(0, uriParseUriA(&stateA, "http://www.example.com/name with spaces/"));
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriComponents) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 15 01 0 7 01
- const char * const input = "http" "://" "sourceforge.net" "/" "project" "/"
- // 0 20 01 0 15
- "platformdownload.php" "?" "group_id=182840";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.scheme.first == input);
- ASSERT_TRUE(uriA.scheme.afterLast == input + 4);
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 15);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
-
- ASSERT_TRUE(uriA.pathHead->text.first == input + 4 + 3 + 15 + 1);
- ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 4 + 3 + 15 + 1 + 7);
- ASSERT_TRUE(uriA.pathHead->next->text.first == input + 4 + 3 + 15 + 1 + 7 + 1);
- ASSERT_TRUE(uriA.pathHead->next->text.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20);
- ASSERT_TRUE(uriA.pathHead->next->next == NULL);
- ASSERT_TRUE(uriA.pathTail == uriA.pathHead->next);
-
- ASSERT_TRUE(uriA.query.first == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1);
- ASSERT_TRUE(uriA.query.afterLast == input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1 + 15);
- ASSERT_TRUE(uriA.fragment.first == NULL);
- ASSERT_TRUE(uriA.fragment.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 15 01 0 7 01
+ const char * const input = "http" "://" "sourceforge.net" "/" "project" "/"
+ // 0 20 01 0 15
+ "platformdownload.php" "?" "group_id=182840";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.scheme.first, input);
+ ASSERT_EQ(uriA.scheme.afterLast, input + 4);
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 15);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+
+ ASSERT_EQ(uriA.pathHead->text.first, input + 4 + 3 + 15 + 1);
+ ASSERT_EQ(uriA.pathHead->text.afterLast, input + 4 + 3 + 15 + 1 + 7);
+ ASSERT_EQ(uriA.pathHead->next->text.first, input + 4 + 3 + 15 + 1 + 7 + 1);
+ ASSERT_EQ(uriA.pathHead->next->text.afterLast, input + 4 + 3 + 15 + 1 + 7 + 1 + 20);
+ ASSERT_TRUE(uriA.pathHead->next->next == NULL);
+ ASSERT_EQ(uriA.pathTail, uriA.pathHead->next);
+
+ ASSERT_EQ(uriA.query.first, input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1);
+ ASSERT_EQ(uriA.query.afterLast, input + 4 + 3 + 15 + 1 + 7 + 1 + 20 + 1 + 15);
+ ASSERT_TRUE(uriA.fragment.first == NULL);
+ ASSERT_TRUE(uriA.fragment.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriComponentsBug20070701) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 01 01 01
- const char * const input = "a" ":" "b";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.scheme.first == input);
- ASSERT_TRUE(uriA.scheme.afterLast == input + 1);
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.hostText.first == NULL);
- ASSERT_TRUE(uriA.hostText.afterLast == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
-
- ASSERT_TRUE(uriA.pathHead->text.first == input + 1 + 1);
- ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 1 + 1 + 1);
- ASSERT_TRUE(uriA.pathHead->next == NULL);
- ASSERT_TRUE(uriA.pathTail == uriA.pathHead);
-
- ASSERT_TRUE(uriA.query.first == NULL);
- ASSERT_TRUE(uriA.query.afterLast == NULL);
- ASSERT_TRUE(uriA.fragment.first == NULL);
- ASSERT_TRUE(uriA.fragment.afterLast == NULL);
-
- ASSERT_TRUE(!uriA.absolutePath);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 01 01 01
+ const char * const input = "a" ":" "b";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.scheme.first, input);
+ ASSERT_EQ(uriA.scheme.afterLast, input + 1);
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_TRUE(uriA.hostText.first == NULL);
+ ASSERT_TRUE(uriA.hostText.afterLast == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+
+ ASSERT_EQ(uriA.pathHead->text.first, input + 1 + 1);
+ ASSERT_EQ(uriA.pathHead->text.afterLast, input + 1 + 1 + 1);
+ ASSERT_TRUE(uriA.pathHead->next == NULL);
+ ASSERT_EQ(uriA.pathTail, uriA.pathHead);
+
+ ASSERT_TRUE(uriA.query.first == NULL);
+ ASSERT_TRUE(uriA.query.afterLast == NULL);
+ ASSERT_TRUE(uriA.fragment.first == NULL);
+ ASSERT_TRUE(uriA.fragment.afterLast == NULL);
+
+ ASSERT_TRUE(!uriA.absolutePath);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort1) {
- // User info with ":", no port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7 01 0 9
- const char * const input = "http" "://" "abc:def" "@" "localhost";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3);
- ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", no port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7 01 0 9
+ const char * const input = "http" "://" "abc:def" "@" "localhost";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.userInfo.first, input + 4 + 3);
+ ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort2) {
- // User info with ":", with port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7 01 0 9
- const char * const input = "http" "://" "abc:def" "@" "localhost"
- // 01 0 3
- ":" "123";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3);
- ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9);
- ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1);
- ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", with port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7 01 0 9
+ const char * const input = "http" "://" "abc:def" "@" "localhost"
+ // 01 0 3
+ ":" "123";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.userInfo.first, input + 4 + 3);
+ ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9);
+ ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 7 + 1 + 9 + 1);
+ ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 7 + 1 + 9 + 1 + 3);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort22Bug1948038) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
- int res;
+ int res;
- res = uriParseUriA(&stateA, "http://user:21@host/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:21", 7 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 7);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ res = uriParseUriA(&stateA, "http://user:21@host/");
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:21", 7 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 7);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
- res = uriParseUriA(&stateA, "http://user:1234@192.168.0.1:1234/foo.com");
- ASSERT_TRUE(URI_SUCCESS == res);
- uriFreeUriMembersA(&uriA);
+ res = uriParseUriA(&stateA, "http://user:1234@192.168.0.1:1234/foo.com");
+ ASSERT_EQ(URI_SUCCESS, res);
+ uriFreeUriMembersA(&uriA);
- res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo/");
- ASSERT_TRUE(URI_ERROR_SYNTAX == res);
- uriFreeUriMembersA(&uriA);
+ res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo/");
+ ASSERT_EQ(URI_ERROR_SYNTAX, res);
+ uriFreeUriMembersA(&uriA);
- res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo:21/");
- ASSERT_TRUE(URI_ERROR_SYNTAX == res);
- uriFreeUriMembersA(&uriA);
+ res = uriParseUriA(&stateA, "http://moo:21@moo:21@moo:21/");
+ ASSERT_EQ(URI_ERROR_SYNTAX, res);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198One) {
- // User info with ":", with port, with escaped chars in password
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 10 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "user:%2F21" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:%2F21", 10 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 10);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", with port, with escaped chars in password
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 10 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "user:%2F21" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:%2F21", 10 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 10);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Two) {
- // User info with ":", with port, with escaped chars in user name and password
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 13 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "%2Fuser:%2F21" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "%2Fuser:%2F21", 13 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 13);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", with port, with escaped chars in user name and password
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 13 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "%2Fuser:%2F21" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "%2Fuser:%2F21", 13 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 13);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Three) {
- // User info with ":", with port, with escaped chars in password
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 16 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "user:!$&'()*+,;=" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:!$&'()*+,;=", 16 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 16);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", with port, with escaped chars in password
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 16 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "user:!$&'()*+,;=" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "user:!$&'()*+,;=", 16 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 16);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198Four) {
- // User info with ":", with port, with escaped chars in user name and password
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 20 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "!$&'()*+,;=:password" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "!$&'()*+,;=:password", 20 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 20);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info with ":", with port, with escaped chars in user name and password
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 20 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "!$&'()*+,;=:password" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "!$&'()*+,;=:password", 20 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 20);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedOne) {
- // Empty user info
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(uriA.userInfo.afterLast != NULL);
- ASSERT_TRUE(uriA.userInfo.first != NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 0);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // Empty user info
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(uriA.userInfo.afterLast != NULL);
+ ASSERT_TRUE(uriA.userInfo.first != NULL);
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 0);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedOneTwo) {
- // Empty user info
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 7 01
- res = uriParseUriA(&stateA, "http" "://" "%2Fhost" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "%2Fhost", 7 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 7);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // Empty user info
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 7 01
+ res = uriParseUriA(&stateA, "http" "://" "%2Fhost" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "%2Fhost", 7 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 7);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort23Bug3510198RelatedTwo) {
- // Several colons in userinfo
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
-
- int res;
- // 0 4 0 3 0 2 01 0 4 01
- res = uriParseUriA(&stateA, "http" "://" "::" "@" "host" "/");
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(!memcmp(uriA.userInfo.first, "::", 2 * sizeof(char)));
- ASSERT_TRUE(uriA.userInfo.afterLast - uriA.userInfo.first == 2);
- ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 4);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // Several colons in userinfo
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+
+ int res;
+ // clang-format off
+ // 0 4 0 3 0 2 01 0 4 01
+ res = uriParseUriA(&stateA, "http" "://" "::" "@" "host" "/");
+ // clang-format on
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(!memcmp(uriA.userInfo.first, "::", 2 * sizeof(char)));
+ ASSERT_EQ(uriA.userInfo.afterLast - uriA.userInfo.first, 2);
+ ASSERT_TRUE(!memcmp(uriA.hostText.first, "host", 4 * sizeof(char)));
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 4);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort3) {
- // User info without ":", no port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7 01 0 9
- const char * const input = "http" "://" "abcdefg" "@" "localhost";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3);
- ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // User info without ":", no port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7 01 0 9
+ const char * const input = "http" "://" "abcdefg" "@" "localhost";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.userInfo.first, input + 4 + 3);
+ ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort4) {
- // User info without ":", with port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7 01 0 9
- const char * const input = "http" "://" "abcdefg" "@" "localhost"
- // 01 0 3
- ":" "123";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == input + 4 + 3);
- ASSERT_TRUE(uriA.userInfo.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 7 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7 + 1 + 9);
- ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 7 + 1 + 9 + 1);
- ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 7 + 1 + 9 + 1 + 3);
- uriFreeUriMembersA(&uriA);
+ // User info without ":", with port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7 01 0 9
+ const char * const input = "http" "://" "abcdefg" "@" "localhost"
+ // 01 0 3
+ ":" "123";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.userInfo.first, input + 4 + 3);
+ ASSERT_EQ(uriA.userInfo.afterLast, input + 4 + 3 + 7);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 7 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7 + 1 + 9);
+ ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 7 + 1 + 9 + 1);
+ ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 7 + 1 + 9 + 1 + 3);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort5) {
- // No user info, no port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 9
- const char * const input = "http" "://" "localhost";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 9);
- ASSERT_TRUE(uriA.portText.first == NULL);
- ASSERT_TRUE(uriA.portText.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ // No user info, no port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 9
+ const char * const input = "http" "://" "localhost";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 9);
+ ASSERT_TRUE(uriA.portText.first == NULL);
+ ASSERT_TRUE(uriA.portText.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriUserInfoHostPort6) {
- // No user info, with port
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 9 01 0 3
- const char * const input = "http" "://" "localhost" ":" "123";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 9);
- ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 9 + 1);
- ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 9 + 1 + 3);
- uriFreeUriMembersA(&uriA);
+ // No user info, with port
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 9 01 0 3
+ const char * const input = "http" "://" "localhost" ":" "123";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 9);
+ ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 9 + 1);
+ ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 9 + 1 + 3);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostRegname) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 11
- const char * const input = "http" "://" "example.com";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 11);
- ASSERT_TRUE(uriA.hostData.ip4 == NULL);
- ASSERT_TRUE(uriA.hostData.ip6 == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 11
+ const char * const input = "http" "://" "example.com";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 11);
+ ASSERT_TRUE(uriA.hostData.ip4 == NULL);
+ ASSERT_TRUE(uriA.hostData.ip6 == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostIpFour1) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7 01 0 2
- const char * const input = "http" "://" "1.2.3.4" ":" "80";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostData.ip4 != NULL);
- ASSERT_TRUE(uriA.hostData.ip6 == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7 01 0 2
+ const char * const input = "http" "://" "1.2.3.4" ":" "80";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7);
+ ASSERT_TRUE(uriA.hostData.ip4 != NULL);
+ ASSERT_TRUE(uriA.hostData.ip6 == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostIpFour2) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 0 7
- const char * const input = "http" "://" "1.2.3.4";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 7);
- ASSERT_TRUE(uriA.hostData.ip4 != NULL);
- ASSERT_TRUE(uriA.hostData.ip6 == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 0 7
+ const char * const input = "http" "://" "1.2.3.4";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 7);
+ ASSERT_TRUE(uriA.hostData.ip4 != NULL);
+ ASSERT_TRUE(uriA.hostData.ip6 == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostIpSix1) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 01 45 01 0 2
- const char * const input = "http" "://" "[::1]" ":" "80";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 4);
- ASSERT_TRUE(uriA.hostData.ip4 == NULL);
- ASSERT_TRUE(uriA.hostData.ip6 != NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 01 45 01 0 2
+ const char * const input = "http" "://" "[::1]" ":" "80";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 4);
+ ASSERT_TRUE(uriA.hostData.ip4 == NULL);
+ ASSERT_TRUE(uriA.hostData.ip6 != NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostIpSix2) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 01 45
- const char * const input = "http" "://" "[::1]";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.hostText.first == input + 4 + 3 + 1);
- ASSERT_TRUE(uriA.hostText.afterLast == input + 4 + 3 + 4);
- ASSERT_TRUE(uriA.hostData.ip4 == NULL);
- ASSERT_TRUE(uriA.hostData.ip6 != NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
- ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 01 45
+ const char * const input = "http" "://" "[::1]";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.hostText.first, input + 4 + 3 + 1);
+ ASSERT_EQ(uriA.hostText.afterLast, input + 4 + 3 + 4);
+ ASSERT_TRUE(uriA.hostData.ip4 == NULL);
+ ASSERT_TRUE(uriA.hostData.ip6 != NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.first == NULL);
+ ASSERT_TRUE(uriA.hostData.ipFuture.afterLast == NULL);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostEmpty) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 4 0 3 01 0 3
- const char * const input = "http" "://" ":" "123";
- const int res = uriParseUriA(&stateA, input);
- ASSERT_TRUE(URI_SUCCESS == res);
- ASSERT_TRUE(uriA.userInfo.first == NULL);
- ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
- ASSERT_TRUE(uriA.hostText.first != NULL);
- ASSERT_TRUE(uriA.hostText.afterLast != NULL);
- ASSERT_TRUE(uriA.hostText.afterLast - uriA.hostText.first == 0);
- ASSERT_TRUE(uriA.portText.first == input + 4 + 3 + 1);
- ASSERT_TRUE(uriA.portText.afterLast == input + 4 + 3 + 1 + 3);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 4 0 3 01 0 3
+ const char * const input = "http" "://" ":" "123";
+ // clang-format on
+ const int res = uriParseUriA(&stateA, input);
+ ASSERT_EQ(URI_SUCCESS, res);
+ ASSERT_TRUE(uriA.userInfo.first == NULL);
+ ASSERT_TRUE(uriA.userInfo.afterLast == NULL);
+ ASSERT_TRUE(uriA.hostText.first != NULL);
+ ASSERT_TRUE(uriA.hostText.afterLast != NULL);
+ ASSERT_EQ(uriA.hostText.afterLast - uriA.hostText.first, 0);
+ ASSERT_EQ(uriA.portText.first, input + 4 + 3 + 1);
+ ASSERT_EQ(uriA.portText.afterLast, input + 4 + 3 + 1 + 3);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestUriHostIpFuture) {
- // TODO
+ UriUriA uri;
+ // clang-format off
+ // 0 2 01 0 8 01
+ const char * const input = "//" "[" "v7.hello" "]";
+ // clang-format on
+ ASSERT_EQ(uriParseSingleUriA(&uri, input, NULL), URI_SUCCESS);
+ ASSERT_EQ(uri.hostText.first, input + 2 + 1);
+ ASSERT_EQ(uri.hostText.afterLast, input + 2 + 1 + 8);
+ ASSERT_EQ(uri.hostData.ipFuture.first, uri.hostText.first);
+ ASSERT_EQ(uri.hostData.ipFuture.afterLast, uri.hostText.afterLast);
+ uriFreeUriMembersA(&uri);
}
namespace {
- bool testEscapingHelper(const wchar_t * in, const wchar_t * expectedOut,
- bool spaceToPlus = false, bool normalizeBreaks = false) {
- wchar_t * const buffer = new wchar_t[(normalizeBreaks ? 6 : 3)
- * wcslen(in) + 1];
- if (uriEscapeW(in, buffer, spaceToPlus, normalizeBreaks)
- != buffer + wcslen(expectedOut)) {
- delete [] buffer;
- return false;
- }
-
- const bool equal = !wcscmp(buffer, expectedOut);
- delete [] buffer;
- return equal;
- }
+bool testEscapingHelper(const wchar_t * in, const wchar_t * expectedOut,
+ bool spaceToPlus = false, bool normalizeBreaks = false) {
+ wchar_t * const buffer = new wchar_t[(normalizeBreaks ? 6 : 3) * wcslen(in) + 1];
+ if (uriEscapeW(in, buffer, spaceToPlus, normalizeBreaks)
+ != buffer + wcslen(expectedOut)) {
+ delete[] buffer;
+ return false;
+ }
+
+ const bool equal = !wcscmp(buffer, expectedOut);
+ delete[] buffer;
+ return equal;
+}
} // namespace
TEST(UriSuite, TestEscaping) {
- const bool SPACE_TO_PLUS = true;
- const bool SPACE_TO_PERCENT = false;
- const bool KEEP_UNMODIFIED = false;
- const bool NORMALIZE = true;
-
- // '+' to ' '
- ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc+def", SPACE_TO_PLUS));
- ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc%20def", SPACE_TO_PERCENT));
-
- // Percent encoding
- ASSERT_TRUE(testEscapingHelper(L"\x00", L"\0"));
- ASSERT_TRUE(testEscapingHelper(L"\x01", L"%01"));
- ASSERT_TRUE(testEscapingHelper(L"\xff", L"%FF"));
-
- // Linebreak normalization
- ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED));
-
- ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED));
-
- ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED));
-
- ASSERT_TRUE(testEscapingHelper(L"\x0a\x0d", L"%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"g\x0a\x0d", L"g%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0a\x0dg", L"%0D%0A%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
- ASSERT_TRUE(testEscapingHelper(L"\x0a\x0d", L"%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"g\x0a\x0d", L"g%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
- ASSERT_TRUE(testEscapingHelper(L"\x0a\x0dg", L"%0A%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ const bool SPACE_TO_PLUS = true;
+ const bool SPACE_TO_PERCENT = false;
+ const bool KEEP_UNMODIFIED = false;
+ const bool NORMALIZE = true;
+
+ // '+' to ' '
+ ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc+def", SPACE_TO_PLUS));
+ ASSERT_TRUE(testEscapingHelper(L"abc def", L"abc%20def", SPACE_TO_PERCENT));
+
+ // Percent encoding
+ ASSERT_TRUE(testEscapingHelper(L"\x00", L"\0"));
+ ASSERT_TRUE(testEscapingHelper(L"\x01", L"%01"));
+ ASSERT_TRUE(testEscapingHelper(L"\xff", L"%FF"));
+
+ // Linebreak normalization
+ ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"\x0d", L"%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(testEscapingHelper(L"g\x0d", L"g%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(testEscapingHelper(L"\x0dg", L"%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+
+ ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"\x0a", L"%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(testEscapingHelper(L"g\x0a", L"g%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(testEscapingHelper(L"\x0ag", L"%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+
+ ASSERT_TRUE(testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0d\x0a", L"%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(
+ testEscapingHelper(L"g\x0d\x0a", L"g%0D%0A", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0d\x0ag", L"%0D%0Ag", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0a\x0d", L"%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(
+ testEscapingHelper(L"g\x0a\x0d", L"g%0D%0A%0D%0A", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0a\x0dg", L"%0D%0A%0D%0Ag", SPACE_TO_PLUS, NORMALIZE));
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0a\x0d", L"%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(
+ testEscapingHelper(L"g\x0a\x0d", L"g%0A%0D", SPACE_TO_PLUS, KEEP_UNMODIFIED));
+ ASSERT_TRUE(
+ testEscapingHelper(L"\x0a\x0dg", L"%0A%0Dg", SPACE_TO_PLUS, KEEP_UNMODIFIED));
}
namespace {
- bool testUnescapingHelper(const wchar_t * input, const wchar_t * output,
- bool plusToSpace = false, UriBreakConversion breakConversion = URI_BR_DONT_TOUCH) {
- wchar_t * working = new wchar_t[URI_STRLEN(input) + 1];
- wcscpy(working, input);
- const wchar_t * newTermZero = uriUnescapeInPlaceExW(working,
- plusToSpace ? URI_TRUE : URI_FALSE, breakConversion);
- const bool success = ((newTermZero == working + wcslen(output))
- && !wcscmp(working, output));
- delete[] working;
- return success;
- }
+bool testUnescapingHelper(const wchar_t * input, const wchar_t * output,
+ bool plusToSpace = false,
+ UriBreakConversion breakConversion = URI_BR_DONT_TOUCH) {
+ wchar_t * working = new wchar_t[URI_STRLEN(input) + 1];
+ wcscpy(working, input);
+ const wchar_t * newTermZero = uriUnescapeInPlaceExW(
+ working, plusToSpace ? URI_TRUE : URI_FALSE, breakConversion);
+ const bool success =
+ ((newTermZero == working + wcslen(output)) && !wcscmp(working, output));
+ delete[] working;
+ return success;
+}
} // namespace
TEST(UriSuite, TestUnescaping) {
- const bool PLUS_TO_SPACE = true;
- const bool PLUS_DONT_TOUCH = false;
-
-
- // Proper
- ASSERT_TRUE(testUnescapingHelper(L"abc%20%41BC", L"abc ABC"));
- ASSERT_TRUE(testUnescapingHelper(L"%20", L" "));
-
- // Incomplete
- ASSERT_TRUE(testUnescapingHelper(L"%0", L"%0"));
-
- // Nonhex
- ASSERT_TRUE(testUnescapingHelper(L"%0g", L"%0g"));
- ASSERT_TRUE(testUnescapingHelper(L"%G0", L"%G0"));
-
- // No double decoding
- ASSERT_TRUE(testUnescapingHelper(L"%2520", L"%20"));
-
- // Decoding of '+'
- ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc+def", PLUS_DONT_TOUCH));
- ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc def", PLUS_TO_SPACE));
-
- // Line break conversion
- ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
-
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
-
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
- ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0d\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+ const bool PLUS_TO_SPACE = true;
+ const bool PLUS_DONT_TOUCH = false;
+
+ // Proper
+ ASSERT_TRUE(testUnescapingHelper(L"abc%20%41BC", L"abc ABC"));
+ ASSERT_TRUE(testUnescapingHelper(L"%20", L" "));
+
+ // Incomplete
+ ASSERT_TRUE(testUnescapingHelper(L"%0", L"%0"));
+
+ // Nonhex
+ ASSERT_TRUE(testUnescapingHelper(L"%0g", L"%0g"));
+ ASSERT_TRUE(testUnescapingHelper(L"%G0", L"%G0"));
+
+ // No double decoding
+ ASSERT_TRUE(testUnescapingHelper(L"%2520", L"%20"));
+
+ // Decoding of '+'
+ ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc+def", PLUS_DONT_TOUCH));
+ ASSERT_TRUE(testUnescapingHelper(L"abc+def", L"abc def", PLUS_TO_SPACE));
+
+ // Line break conversion
+ ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d", L"\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a", L"\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a", L"\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a", L"\x0d\x0a", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0a", L"\x0d\x0a\x0a", PLUS_DONT_TOUCH,
+ URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d", L"\x0d\x0a\x0d", PLUS_DONT_TOUCH,
+ URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a",
+ PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH,
+ URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0d%0a%0d%0a", L"\x0d\x0a\x0d\x0a",
+ PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0d", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0d", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0d", L"\x0a\x0d", PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0a", PLUS_DONT_TOUCH, URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(
+ testUnescapingHelper(L"%0a%0d%0a", L"\x0d\x0d", PLUS_DONT_TOUCH, URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a", L"\x0a\x0d\x0a", PLUS_DONT_TOUCH,
+ URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a",
+ PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH,
+ URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0d", L"\x0a\x0d\x0d", PLUS_DONT_TOUCH,
+ URI_BR_DONT_TOUCH));
+
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0a\x0a", PLUS_DONT_TOUCH,
+ URI_BR_TO_UNIX));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0a\x0d\x0a\x0d\x0a",
+ PLUS_DONT_TOUCH, URI_BR_TO_WINDOWS));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0d\x0d\x0d", PLUS_DONT_TOUCH,
+ URI_BR_TO_MAC));
+ ASSERT_TRUE(testUnescapingHelper(L"%0a%0d%0a%0d", L"\x0a\x0d\x0a\x0d",
+ PLUS_DONT_TOUCH, URI_BR_DONT_TOUCH));
}
namespace {
- bool testAddBaseHelper(const wchar_t * base, const wchar_t * rel, const wchar_t * expectedResult, bool backward_compatibility = false) {
- UriParserStateW stateW;
-
- // Base
- UriUriW baseUri;
- stateW.uri = &baseUri;
- int res = uriParseUriW(&stateW, base);
- if (res != 0) {
- uriFreeUriMembersW(&baseUri);
- return false;
- }
-
- // Rel
- UriUriW relUri;
- stateW.uri = &relUri;
- res = uriParseUriW(&stateW, rel);
- if (res != 0) {
- uriFreeUriMembersW(&baseUri);
- uriFreeUriMembersW(&relUri);
- return false;
- }
-
- // Expected result
- UriUriW expectedUri;
- stateW.uri = &expectedUri;
- res = uriParseUriW(&stateW, expectedResult);
- if (res != 0) {
- uriFreeUriMembersW(&baseUri);
- uriFreeUriMembersW(&relUri);
- uriFreeUriMembersW(&expectedUri);
- return false;
- }
-
- // Transform
- UriUriW transformedUri;
- if (backward_compatibility) {
- res = uriAddBaseUriExW(&transformedUri, &relUri, &baseUri, URI_RESOLVE_IDENTICAL_SCHEME_COMPAT);
- } else {
- res = uriAddBaseUriW(&transformedUri, &relUri, &baseUri);
- }
-
- if (res != 0) {
- uriFreeUriMembersW(&baseUri);
- uriFreeUriMembersW(&relUri);
- uriFreeUriMembersW(&expectedUri);
- uriFreeUriMembersW(&transformedUri);
- return false;
- }
-
- const bool equal = (URI_TRUE == uriEqualsUriW(&transformedUri, &expectedUri));
- if (!equal) {
- wchar_t transformedUriText[1024 * 8];
- wchar_t expectedUriText[1024 * 8];
- uriToStringW(transformedUriText, &transformedUri, 1024 * 8, NULL);
- uriToStringW(expectedUriText, &expectedUri, 1024 * 8, NULL);
+bool testAddBaseHelper(const wchar_t * base, const wchar_t * rel,
+ const wchar_t * expectedResult,
+ bool backward_compatibility = false) {
+ UriParserStateW stateW;
+
+ // Base
+ UriUriW baseUri;
+ stateW.uri = &baseUri;
+ int res = uriParseUriW(&stateW, base);
+ if (res != 0) {
+ uriFreeUriMembersW(&baseUri);
+ return false;
+ }
+
+ // Rel
+ UriUriW relUri;
+ stateW.uri = &relUri;
+ res = uriParseUriW(&stateW, rel);
+ if (res != 0) {
+ uriFreeUriMembersW(&baseUri);
+ uriFreeUriMembersW(&relUri);
+ return false;
+ }
+
+ // Expected result
+ UriUriW expectedUri;
+ stateW.uri = &expectedUri;
+ res = uriParseUriW(&stateW, expectedResult);
+ if (res != 0) {
+ uriFreeUriMembersW(&baseUri);
+ uriFreeUriMembersW(&relUri);
+ uriFreeUriMembersW(&expectedUri);
+ return false;
+ }
+
+ // Transform
+ UriUriW transformedUri;
+ if (backward_compatibility) {
+ res = uriAddBaseUriExW(&transformedUri, &relUri, &baseUri,
+ URI_RESOLVE_IDENTICAL_SCHEME_COMPAT);
+ } else {
+ res = uriAddBaseUriW(&transformedUri, &relUri, &baseUri);
+ }
+
+ if (res != 0) {
+ uriFreeUriMembersW(&baseUri);
+ uriFreeUriMembersW(&relUri);
+ uriFreeUriMembersW(&expectedUri);
+ uriFreeUriMembersW(&transformedUri);
+ return false;
+ }
+
+ const bool equal = (URI_TRUE == uriEqualsUriW(&transformedUri, &expectedUri));
+ if (!equal) {
+ wchar_t transformedUriText[1024 * 8];
+ wchar_t expectedUriText[1024 * 8];
+ uriToStringW(transformedUriText, &transformedUri, 1024 * 8, NULL);
+ uriToStringW(expectedUriText, &expectedUri, 1024 * 8, NULL);
#ifdef HAVE_WPRINTF
- wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText, transformedUriText);
+ wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", expectedUriText,
+ transformedUriText);
#endif
- }
-
- uriFreeUriMembersW(&baseUri);
- uriFreeUriMembersW(&relUri);
- uriFreeUriMembersW(&expectedUri);
- uriFreeUriMembersW(&transformedUri);
- return equal;
- }
+ }
+
+ uriFreeUriMembersW(&baseUri);
+ uriFreeUriMembersW(&relUri);
+ uriFreeUriMembersW(&expectedUri);
+ uriFreeUriMembersW(&transformedUri);
+ return equal;
+}
} // namespace
TEST(UriSuite, TestTrailingSlash) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- // 0 3 01
- const char * const input = "abc" "/";
- ASSERT_TRUE(0 == uriParseUriA(&stateA, input));
-
- ASSERT_TRUE(uriA.pathHead->text.first == input);
- ASSERT_TRUE(uriA.pathHead->text.afterLast == input + 3);
- ASSERT_TRUE(uriA.pathHead->next->text.first == uriA.pathHead->next->text.afterLast);
- ASSERT_TRUE(uriA.pathHead->next->next == NULL);
- ASSERT_TRUE(uriA.pathTail == uriA.pathHead->next);
- uriFreeUriMembersA(&uriA);
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ // clang-format off
+ // 0 3 01
+ const char * const input = "abc" "/";
+ // clang-format on
+ ASSERT_EQ(0, uriParseUriA(&stateA, input));
+
+ ASSERT_EQ(uriA.pathHead->text.first, input);
+ ASSERT_EQ(uriA.pathHead->text.afterLast, input + 3);
+ ASSERT_EQ(uriA.pathHead->next->text.first, uriA.pathHead->next->text.afterLast);
+ ASSERT_TRUE(uriA.pathHead->next->next == NULL);
+ ASSERT_EQ(uriA.pathTail, uriA.pathHead->next);
+ uriFreeUriMembersA(&uriA);
}
TEST(UriSuite, TestAddBase) {
- // 5.4.1. Normal Examples
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g:h", L"g:h"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g", L"http://a/b/c/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g", L"http://a/b/c/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/", L"http://a/b/c/g/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g", L"http://a/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"//g", L"http://g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"?y", L"http://a/b/c/d;p?y"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y", L"http://a/b/c/g?y"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"#s", L"http://a/b/c/d;p?q#s"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s", L"http://a/b/c/g#s"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y#s", L"http://a/b/c/g?y#s"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L";x", L"http://a/b/c/;x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x", L"http://a/b/c/g;x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x?y#s", L"http://a/b/c/g;x?y#s"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"", L"http://a/b/c/d;p?q"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".", L"http://a/b/c/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./", L"http://a/b/c/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..", L"http://a/b/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../", L"http://a/b/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../g", L"http://a/b/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../..", L"http://a/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../", L"http://a/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../g", L"http://a/g"));
-
- // 5.4.2. Abnormal Examples
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../g", L"http://a/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../../g", L"http://a/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/./g", L"http://a/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/../g", L"http://a/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g.", L"http://a/b/c/g."));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".g", L"http://a/b/c/.g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g..", L"http://a/b/c/g.."));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..g", L"http://a/b/c/..g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./../g", L"http://a/b/g"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g/.", L"http://a/b/c/g/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/./h", L"http://a/b/c/g/h"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/../h", L"http://a/b/c/h"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/./y", L"http://a/b/c/g;x=1/y"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/../y", L"http://a/b/c/y"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/./x", L"http://a/b/c/g?y/./x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/../x", L"http://a/b/c/g?y/../x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/./x", L"http://a/b/c/g#s/./x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/../x", L"http://a/b/c/g#s/../x"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g"));
-
- // Backward compatibility (feature request #4, RFC3986 5.4.2)
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g", false));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http://a/b/c/g", true));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g?q#f", L"http://a/b/c/g?q#f", true));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"other:g?q#f", L"other:g?q#f", true));
-
- // Bug related to absolutePath flag set despite presence of host
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/", L"http://a/"));
- ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g/", L"http://a/g/"));
-
- // GitHub issue #92
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../..", L"http://a/"));
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../../", L"http://a/"));
-
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../..", L"http://a/"));
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../../", L"http://a/"));
-
- EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../..", L"http://a/"));
- EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../../", L"http://a/"));
-
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../..", L"http://a/"));
- EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../", L"http://a/"));
+ // 5.4.1. Normal Examples
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g:h", L"g:h"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g", L"http://a/b/c/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g", L"http://a/b/c/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/", L"http://a/b/c/g/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g", L"http://a/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"//g", L"http://g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"?y", L"http://a/b/c/d;p?y"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y", L"http://a/b/c/g?y"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"#s", L"http://a/b/c/d;p?q#s"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s", L"http://a/b/c/g#s"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y#s", L"http://a/b/c/g?y#s"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L";x", L"http://a/b/c/;x"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x", L"http://a/b/c/g;x"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x?y#s", L"http://a/b/c/g;x?y#s"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"", L"http://a/b/c/d;p?q"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".", L"http://a/b/c/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./", L"http://a/b/c/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..", L"http://a/b/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../", L"http://a/b/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../g", L"http://a/b/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../..", L"http://a/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../", L"http://a/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../g", L"http://a/g"));
+
+ // 5.4.2. Abnormal Examples
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../g", L"http://a/g"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../../g", L"http://a/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/./g", L"http://a/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/../g", L"http://a/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g.", L"http://a/b/c/g."));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L".g", L"http://a/b/c/.g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g..", L"http://a/b/c/g.."));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"..g", L"http://a/b/c/..g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./../g", L"http://a/b/g"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"./g/.", L"http://a/b/c/g/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/./h", L"http://a/b/c/g/h"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"g/../h", L"http://a/b/c/h"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/./y", L"http://a/b/c/g;x=1/y"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g;x=1/../y", L"http://a/b/c/y"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/./x", L"http://a/b/c/g?y/./x"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g?y/../x", L"http://a/b/c/g?y/../x"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/./x", L"http://a/b/c/g#s/./x"));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"g#s/../x", L"http://a/b/c/g#s/../x"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g"));
+
+ // Backward compatibility (feature request #4, RFC3986 5.4.2)
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http:g", false));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g", L"http://a/b/c/g", true));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"http:g?q#f",
+ L"http://a/b/c/g?q#f", true));
+ ASSERT_TRUE(
+ testAddBaseHelper(L"http://a/b/c/d;p?q", L"other:g?q#f", L"other:g?q#f", true));
+
+ // Bug related to absolutePath flag set despite presence of host
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/", L"http://a/"));
+ ASSERT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"/g/", L"http://a/g/"));
+
+ // GitHub issue #92
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../..", L"http://a/"));
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/../d;p?q", L"../../", L"http://a/"));
+
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../..", L"http://a/"));
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/../c/d;p?q", L"../../", L"http://a/"));
+
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../..", L"http://a/"));
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/../b/c/d;p?q", L"../../", L"http://a/"));
+
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../..", L"http://a/"));
+ EXPECT_TRUE(testAddBaseHelper(L"http://a/b/c/d;p?q", L"../../../", L"http://a/"));
}
namespace {
- bool testToStringHelper(const wchar_t * text) {
- // Parse
- UriParserStateW state;
- UriUriW uri;
- state.uri = &uri;
- int res = uriParseUriW(&state, text);
- if (res != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- // Back to string, _huge_ limit
- wchar_t shouldbeTheSame[1024 * 8];
- res = uriToStringW(shouldbeTheSame, &uri, 1024 * 8, NULL);
- if (res != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- // Compare
- bool equals = (0 == wcscmp(shouldbeTheSame, text));
- if (!equals) {
+bool testToStringHelper(const wchar_t * text) {
+ // Parse
+ UriParserStateW state;
+ UriUriW uri;
+ state.uri = &uri;
+ int res = uriParseUriW(&state, text);
+ if (res != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ // Back to string, _huge_ limit
+ wchar_t shouldbeTheSame[1024 * 8];
+ res = uriToStringW(shouldbeTheSame, &uri, 1024 * 8, NULL);
+ if (res != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ // Compare
+ bool equals = (0 == wcscmp(shouldbeTheSame, text));
+ if (!equals) {
#ifdef HAVE_WPRINTF
- wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", text, shouldbeTheSame);
+ wprintf(L"\n\n\nExpected: \"%s\"\nReceived: \"%s\"\n\n\n", text, shouldbeTheSame);
#endif
- }
-
- // Back to string, _exact_ limit
- const int len = static_cast<int>(wcslen(text));
- int charsWritten;
- res = uriToStringW(shouldbeTheSame, &uri, len + 1, &charsWritten);
- if ((res != 0) || (charsWritten != len + 1)) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- // Back to string, _too small_ limit
- res = uriToStringW(shouldbeTheSame, &uri, len, &charsWritten);
- if ((res == 0) || (charsWritten >= len + 1)) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- uriFreeUriMembersW(&uri);
- return equals;
- }
+ }
+
+ // Back to string, _exact_ limit
+ const int len = static_cast<int>(wcslen(text));
+ int charsWritten;
+ res = uriToStringW(shouldbeTheSame, &uri, len + 1, &charsWritten);
+ if ((res != 0) || (charsWritten != len + 1)) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ // Back to string, _too small_ limit
+ res = uriToStringW(shouldbeTheSame, &uri, len, &charsWritten);
+ if ((res == 0) || (charsWritten >= len + 1)) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ uriFreeUriMembersW(&uri);
+ return equals;
+}
} // namespace
TEST(UriSuite, TestToString) {
- // Scheme
- ASSERT_TRUE(testToStringHelper(L"ftp://localhost/"));
- // UserInfo
- ASSERT_TRUE(testToStringHelper(L"http://user:pass@localhost/"));
- // IPv4
- ASSERT_TRUE(testToStringHelper(L"http://123.0.1.255/"));
- // IPv6
- ASSERT_TRUE(testToStringHelper(L"http://[abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd]/"));
- // IPvFuture
- ASSERT_TRUE(testToStringHelper(L"http://[vA.123456]/"));
- // Port
- ASSERT_TRUE(testToStringHelper(L"http://example.com:123/"));
- // Path
- ASSERT_TRUE(testToStringHelper(L"http://example.com"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def/"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com//"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/./.."));
- // Query
- ASSERT_TRUE(testToStringHelper(L"http://example.com/?abc"));
- // Fragment
- ASSERT_TRUE(testToStringHelper(L"http://example.com/#abc"));
- ASSERT_TRUE(testToStringHelper(L"http://example.com/?def#abc"));
-
- // Relative
- ASSERT_TRUE(testToStringHelper(L"a"));
- ASSERT_TRUE(testToStringHelper(L"a/"));
- ASSERT_TRUE(testToStringHelper(L"/a"));
- ASSERT_TRUE(testToStringHelper(L"/a/"));
- ASSERT_TRUE(testToStringHelper(L"abc"));
- ASSERT_TRUE(testToStringHelper(L"abc/"));
- ASSERT_TRUE(testToStringHelper(L"/abc"));
- ASSERT_TRUE(testToStringHelper(L"/abc/"));
- ASSERT_TRUE(testToStringHelper(L"a/def"));
- ASSERT_TRUE(testToStringHelper(L"a/def/"));
- ASSERT_TRUE(testToStringHelper(L"/a/def"));
- ASSERT_TRUE(testToStringHelper(L"/a/def/"));
- ASSERT_TRUE(testToStringHelper(L"abc/def"));
- ASSERT_TRUE(testToStringHelper(L"abc/def/"));
- ASSERT_TRUE(testToStringHelper(L"/abc/def"));
- ASSERT_TRUE(testToStringHelper(L"/abc/def/"));
- ASSERT_TRUE(testToStringHelper(L"/"));
- ASSERT_TRUE(testToStringHelper(L"//a/"));
- ASSERT_TRUE(testToStringHelper(L"."));
- ASSERT_TRUE(testToStringHelper(L"./"));
- ASSERT_TRUE(testToStringHelper(L"/."));
- ASSERT_TRUE(testToStringHelper(L"/./"));
- ASSERT_TRUE(testToStringHelper(L""));
- ASSERT_TRUE(testToStringHelper(L"./abc/def"));
- ASSERT_TRUE(testToStringHelper(L"?query"));
- ASSERT_TRUE(testToStringHelper(L"#fragment"));
- ASSERT_TRUE(testToStringHelper(L"?query#fragment"));
-
- // Tests for bugs from the past
- ASSERT_TRUE(testToStringHelper(L"f:/.//g"));
+ // Scheme
+ ASSERT_TRUE(testToStringHelper(L"ftp://localhost/"));
+ // UserInfo
+ ASSERT_TRUE(testToStringHelper(L"http://user:pass@localhost/"));
+ // IPv4
+ ASSERT_TRUE(testToStringHelper(L"http://123.0.1.255/"));
+ // IPv6
+ ASSERT_TRUE(testToStringHelper(L"http://[abcd:abcd:abcd:abcd:abcd:abcd:abcd:abcd]/"));
+ // IPvFuture
+ ASSERT_TRUE(testToStringHelper(L"http://[vA.123456]/"));
+ // Port
+ ASSERT_TRUE(testToStringHelper(L"http://example.com:123/"));
+ // Path
+ ASSERT_TRUE(testToStringHelper(L"http://example.com"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/abc/def/"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com//"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/./.."));
+ // Query
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/?abc"));
+ // Fragment
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/#abc"));
+ ASSERT_TRUE(testToStringHelper(L"http://example.com/?def#abc"));
+
+ // Relative
+ ASSERT_TRUE(testToStringHelper(L"a"));
+ ASSERT_TRUE(testToStringHelper(L"a/"));
+ ASSERT_TRUE(testToStringHelper(L"/a"));
+ ASSERT_TRUE(testToStringHelper(L"/a/"));
+ ASSERT_TRUE(testToStringHelper(L"abc"));
+ ASSERT_TRUE(testToStringHelper(L"abc/"));
+ ASSERT_TRUE(testToStringHelper(L"/abc"));
+ ASSERT_TRUE(testToStringHelper(L"/abc/"));
+ ASSERT_TRUE(testToStringHelper(L"a/def"));
+ ASSERT_TRUE(testToStringHelper(L"a/def/"));
+ ASSERT_TRUE(testToStringHelper(L"/a/def"));
+ ASSERT_TRUE(testToStringHelper(L"/a/def/"));
+ ASSERT_TRUE(testToStringHelper(L"abc/def"));
+ ASSERT_TRUE(testToStringHelper(L"abc/def/"));
+ ASSERT_TRUE(testToStringHelper(L"/abc/def"));
+ ASSERT_TRUE(testToStringHelper(L"/abc/def/"));
+ ASSERT_TRUE(testToStringHelper(L"/"));
+ ASSERT_TRUE(testToStringHelper(L"//a/"));
+ ASSERT_TRUE(testToStringHelper(L"."));
+ ASSERT_TRUE(testToStringHelper(L"./"));
+ ASSERT_TRUE(testToStringHelper(L"/."));
+ ASSERT_TRUE(testToStringHelper(L"/./"));
+ ASSERT_TRUE(testToStringHelper(L""));
+ ASSERT_TRUE(testToStringHelper(L"./abc/def"));
+ ASSERT_TRUE(testToStringHelper(L"?query"));
+ ASSERT_TRUE(testToStringHelper(L"#fragment"));
+ ASSERT_TRUE(testToStringHelper(L"?query#fragment"));
+
+ // Tests for bugs from the past
+ ASSERT_TRUE(testToStringHelper(L"f:/.//g"));
}
TEST(UriSuite, TestToStringBug1950126) {
- UriParserStateW state;
- UriUriW uriOne;
- UriUriW uriTwo;
- const wchar_t * const uriOneString = L"http://e.com/";
- const wchar_t * const uriTwoString = L"http://e.com";
- state.uri = &uriOne;
- ASSERT_TRUE(URI_SUCCESS == uriParseUriW(&state, uriOneString));
- state.uri = &uriTwo;
- ASSERT_TRUE(URI_SUCCESS == uriParseUriW(&state, uriTwoString));
- ASSERT_TRUE(URI_FALSE == uriEqualsUriW(&uriOne, &uriTwo));
- uriFreeUriMembersW(&uriOne);
- uriFreeUriMembersW(&uriTwo);
-
- ASSERT_TRUE(testToStringHelper(uriOneString));
- ASSERT_TRUE(testToStringHelper(uriTwoString));
+ UriParserStateW state;
+ UriUriW uriOne;
+ UriUriW uriTwo;
+ const wchar_t * const uriOneString = L"http://e.com/";
+ const wchar_t * const uriTwoString = L"http://e.com";
+ state.uri = &uriOne;
+ ASSERT_EQ(URI_SUCCESS, uriParseUriW(&state, uriOneString));
+ state.uri = &uriTwo;
+ ASSERT_EQ(URI_SUCCESS, uriParseUriW(&state, uriTwoString));
+ ASSERT_EQ(URI_FALSE, uriEqualsUriW(&uriOne, &uriTwo));
+ uriFreeUriMembersW(&uriOne);
+ uriFreeUriMembersW(&uriTwo);
+
+ ASSERT_TRUE(testToStringHelper(uriOneString));
+ ASSERT_TRUE(testToStringHelper(uriTwoString));
}
namespace {
- bool testToStringCharsRequiredHelper(const wchar_t * text) {
- // Parse
- UriParserStateW state;
- UriUriW uri;
- state.uri = &uri;
- int res = uriParseUriW(&state, text);
- if (res != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- // Required space?
- int charsRequired;
- if (uriToStringCharsRequiredW(&uri, &charsRequired) != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- EXPECT_EQ(charsRequired, wcslen(text));
-
- // Minimum
- wchar_t * buffer = new wchar_t[charsRequired + 1];
- if (uriToStringW(buffer, &uri, charsRequired + 1, NULL) != 0) {
- uriFreeUriMembersW(&uri);
- delete [] buffer;
- return false;
- }
-
- // One less than minimum
- if (uriToStringW(buffer, &uri, charsRequired, NULL) == 0) {
- uriFreeUriMembersW(&uri);
- delete [] buffer;
- return false;
- }
-
- uriFreeUriMembersW(&uri);
- delete [] buffer;
- return true;
- }
+bool testToStringCharsRequiredHelper(const wchar_t * text) {
+ // Parse
+ UriParserStateW state;
+ UriUriW uri;
+ state.uri = &uri;
+ int res = uriParseUriW(&state, text);
+ if (res != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ // Required space?
+ int charsRequired;
+ if (uriToStringCharsRequiredW(&uri, &charsRequired) != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ EXPECT_EQ(charsRequired, wcslen(text));
+
+ // Minimum
+ wchar_t * buffer = new wchar_t[charsRequired + 1];
+ if (uriToStringW(buffer, &uri, charsRequired + 1, NULL) != 0) {
+ uriFreeUriMembersW(&uri);
+ delete[] buffer;
+ return false;
+ }
+
+ // One less than minimum
+ if (uriToStringW(buffer, &uri, charsRequired, NULL) == 0) {
+ uriFreeUriMembersW(&uri);
+ delete[] buffer;
+ return false;
+ }
+
+ uriFreeUriMembersW(&uri);
+ delete[] buffer;
+ return true;
+}
} // namespace
TEST(UriSuite, TestToStringCharsRequired) {
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://12.1.1.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://123.1.1.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.12.1.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.123.1.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.12.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.123.1/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.12/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.123/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com:80/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://user:pass@www.example.com/"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/index.html"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/#def"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc#def"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"/test"));
- EXPECT_TRUE(testToStringCharsRequiredHelper(L"test"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://12.1.1.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://123.1.1.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.12.1.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.123.1.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.12.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.123.1/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.12/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://1.1.1.123/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com:80/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://user:pass@www.example.com/"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/index.html"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/#def"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"http://www.example.com/?abc#def"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"/test"));
+ EXPECT_TRUE(testToStringCharsRequiredHelper(L"test"));
}
namespace {
- bool testNormalizeMaskHelper(const wchar_t * uriText, unsigned int expectedMask) {
- UriParserStateW state;
- UriUriW uri;
- state.uri = &uri;
- int res = uriParseUriW(&state, uriText);
- if (res != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- const unsigned int maskBefore = uriNormalizeSyntaxMaskRequiredW(&uri);
- if (maskBefore != expectedMask) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- res = uriNormalizeSyntaxW(&uri);
- if (res != 0) {
- uriFreeUriMembersW(&uri);
- return false;
- }
-
- const unsigned int maskAfter = uriNormalizeSyntaxMaskRequiredW(&uri);
- uriFreeUriMembersW(&uri);
-
- // Second call should be no problem
- uriFreeUriMembersW(&uri);
-
- return (maskAfter == URI_NORMALIZED);
- }
+bool testNormalizeMaskHelper(const wchar_t * uriText, unsigned int expectedMask) {
+ UriParserStateW state;
+ UriUriW uri;
+ state.uri = &uri;
+ int res = uriParseUriW(&state, uriText);
+ if (res != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ const unsigned int maskBefore = uriNormalizeSyntaxMaskRequiredW(&uri);
+ if (maskBefore != expectedMask) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ res = uriNormalizeSyntaxW(&uri);
+ if (res != 0) {
+ uriFreeUriMembersW(&uri);
+ return false;
+ }
+
+ const unsigned int maskAfter = uriNormalizeSyntaxMaskRequiredW(&uri);
+ uriFreeUriMembersW(&uri);
+
+ // Second call should be no problem
+ uriFreeUriMembersW(&uri);
+
+ return (maskAfter == URI_NORMALIZED);
+}
} // namespace
TEST(UriSuite, TestNormalizeSyntaxMaskRequired) {
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/", URI_NORMALIZED));
- ASSERT_TRUE(testNormalizeMaskHelper(L"httP://localhost/", URI_NORMALIZE_SCHEME));
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://%0d@localhost/", URI_NORMALIZE_USER_INFO));
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhosT/", URI_NORMALIZE_HOST));
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/./abc", URI_NORMALIZE_PATH));
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/?AB%43", URI_NORMALIZE_QUERY));
- ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/#AB%43", URI_NORMALIZE_FRAGMENT));
+ ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/", URI_NORMALIZED));
+ ASSERT_TRUE(testNormalizeMaskHelper(L"httP://localhost/", URI_NORMALIZE_SCHEME));
+ ASSERT_TRUE(
+ testNormalizeMaskHelper(L"http://%0d@localhost/", URI_NORMALIZE_USER_INFO));
+ ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhosT/", URI_NORMALIZE_HOST));
+ ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/./abc", URI_NORMALIZE_PATH));
+ ASSERT_TRUE(testNormalizeMaskHelper(L"http://localhost/?AB%43", URI_NORMALIZE_QUERY));
+ ASSERT_TRUE(
+ testNormalizeMaskHelper(L"http://localhost/#AB%43", URI_NORMALIZE_FRAGMENT));
+}
+
+TEST(UriSuite, TestNormalizeSyntaxMaskRequiredPort) {
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:443/", URI_NORMALIZED));
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:0/", URI_NORMALIZED));
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:/", URI_NORMALIZED));
+
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:0443/", URI_NORMALIZE_PORT));
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:00443/", URI_NORMALIZE_PORT));
+ EXPECT_TRUE(testNormalizeMaskHelper(L"https://localhost:00/", URI_NORMALIZE_PORT));
}
namespace {
- bool testNormalizeSyntaxHelper(const wchar_t * uriText, const wchar_t * expectedNormalized,
- unsigned int mask = static_cast<unsigned int>(-1)) {
- UriParserStateW stateW;
- int res;
-
- UriUriW testUri;
- stateW.uri = &testUri;
- res = uriParseUriW(&stateW, uriText);
- if (res != 0) {
- uriFreeUriMembersW(&testUri);
- return false;
- }
-
- // Expected result
- UriUriW expectedUri;
- stateW.uri = &expectedUri;
- res = uriParseUriW(&stateW, expectedNormalized);
- if (res != 0) {
- uriFreeUriMembersW(&testUri);
- uriFreeUriMembersW(&expectedUri);
- return false;
- }
-
- // First run
- res = uriNormalizeSyntaxExW(&testUri, mask);
- if (res != 0) {
- uriFreeUriMembersW(&testUri);
- uriFreeUriMembersW(&expectedUri);
- return false;
- }
-
- bool equalAfter = (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri));
-
- // Second run
- res = uriNormalizeSyntaxExW(&testUri, mask);
- if (res != 0) {
- uriFreeUriMembersW(&testUri);
- uriFreeUriMembersW(&expectedUri);
- return false;
- }
-
- equalAfter = equalAfter
- && (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri));
-
- uriFreeUriMembersW(&testUri);
- uriFreeUriMembersW(&expectedUri);
- return equalAfter;
- }
+bool testNormalizeSyntaxHelper(const wchar_t * uriText,
+ const wchar_t * expectedNormalized,
+ unsigned int mask = static_cast<unsigned int>(-1)) {
+ UriParserStateW stateW;
+ int res;
+
+ UriUriW testUri;
+ stateW.uri = &testUri;
+ res = uriParseUriW(&stateW, uriText);
+ if (res != 0) {
+ uriFreeUriMembersW(&testUri);
+ return false;
+ }
+
+ // Expected result
+ UriUriW expectedUri;
+ stateW.uri = &expectedUri;
+ res = uriParseUriW(&stateW, expectedNormalized);
+ if (res != 0) {
+ uriFreeUriMembersW(&testUri);
+ uriFreeUriMembersW(&expectedUri);
+ return false;
+ }
+
+ // First run
+ res = uriNormalizeSyntaxExW(&testUri, mask);
+ if (res != 0) {
+ uriFreeUriMembersW(&testUri);
+ uriFreeUriMembersW(&expectedUri);
+ return false;
+ }
+
+ bool equalAfter = (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri));
+
+ // Second run
+ res = uriNormalizeSyntaxExW(&testUri, mask);
+ if (res != 0) {
+ uriFreeUriMembersW(&testUri);
+ uriFreeUriMembersW(&expectedUri);
+ return false;
+ }
+
+ equalAfter = equalAfter && (URI_TRUE == uriEqualsUriW(&testUri, &expectedUri));
+
+ uriFreeUriMembersW(&testUri);
+ uriFreeUriMembersW(&expectedUri);
+ return equalAfter;
+}
} // namespace
TEST(UriSuite, TestNormalizeSyntax) {
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"eXAMPLE://a/./b/../b/%63/%7bfoo%7d",
- L"example://a/b/c/%7Bfoo%7D"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"eXAMPLE://a/./b/../b/%63/%7bfoo%7d",
+ L"example://a/b/c/%7Bfoo%7D"));
+
+ // Testcase by Adrian Manrique
+ ASSERT_TRUE(
+ testNormalizeSyntaxHelper(L"http://examp%4Ce.com/", L"http://example.com/"));
- // Testcase by Adrian Manrique
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"http://examp%4Ce.com/",
- L"http://example.com/"));
+ // Testcase by Adrian Manrique
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"http://example.com/a/b/%2E%2E/",
+ L"http://example.com/a/"));
- // Testcase by Adrian Manrique
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"http://example.com/a/b/%2E%2E/",
- L"http://example.com/a/"));
+ // Reported by Adrian Manrique
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"http://user:pass@SOMEHOST.COM:123",
+ L"http://user:pass@somehost.com:123"));
- // Reported by Adrian Manrique
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"http://user:pass@SOMEHOST.COM:123",
- L"http://user:pass@somehost.com:123"));
+ ASSERT_TRUE(
+ testNormalizeSyntaxHelper(L"https://%e4%bd%a0%e5%a5%bd%e4%bd%a0%e5%a5%bd.com",
+ L"https://%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD.com"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://a:b@HOST:123/./1/2/../%41?abc#def",
- L"http://a:b@host:123/1/A?abc#def"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"https://[2041:0000:140F::875B:131B]",
+ L"https://[2041:0000:140f::875b:131b]"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"../../abc",
- L"../../abc"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://a:b@HOST:123/./1/2/../%41?abc#def",
+ L"http://a:b@host:123/1/A?abc#def"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"../../abc/..",
- L"../../"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc", L"../../abc"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"../../abc/../def",
- L"../../def"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/..", L"../../"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"abc/..",
- L""));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/../def", L"../../def"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"abc/../",
- L""));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"abc/..", L""));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"../../abc/./def",
- L"../../abc/def"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"abc/../", L""));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"./def",
- L"def"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"../../abc/./def", L"../../abc/def"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"def/.",
- L"def/"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"./def", L"def"));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"./abc:def",
- L"./abc:def"));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"def/.", L"def/"));
+
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"./abc:def", L"./abc:def"));
}
TEST(UriSuite, TestNormalizeSyntaxComponents) {
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"http://%41@EXAMPLE.ORG/../a?%41#%41",
- URI_NORMALIZE_SCHEME));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"http://%41@EXAMPLE.ORG/../a?%41#%41",
+ URI_NORMALIZE_SCHEME));
+
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"HTTP://A@EXAMPLE.ORG/../a?%41#%41",
+ URI_NORMALIZE_USER_INFO));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"HTTP://A@EXAMPLE.ORG/../a?%41#%41",
- URI_NORMALIZE_USER_INFO));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"HTTP://%41@example.org/../a?%41#%41",
+ URI_NORMALIZE_HOST));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"HTTP://%41@example.org/../a?%41#%41",
- URI_NORMALIZE_HOST));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://EXAMPLE.ORG:00080/",
+ L"HTTP://EXAMPLE.ORG:80/", URI_NORMALIZE_PORT));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"HTTP://%41@EXAMPLE.ORG/a?%41#%41",
- URI_NORMALIZE_PATH));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"HTTP://%41@EXAMPLE.ORG/a?%41#%41",
+ URI_NORMALIZE_PATH));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"HTTP://%41@EXAMPLE.ORG/../a?A#%41",
- URI_NORMALIZE_QUERY));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"HTTP://%41@EXAMPLE.ORG/../a?A#%41",
+ URI_NORMALIZE_QUERY));
- ASSERT_TRUE(testNormalizeSyntaxHelper(
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
- L"HTTP://%41@EXAMPLE.ORG/../a?%41#A",
- URI_NORMALIZE_FRAGMENT));
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"HTTP://%41@EXAMPLE.ORG/../a?%41#%41",
+ L"HTTP://%41@EXAMPLE.ORG/../a?%41#A",
+ URI_NORMALIZE_FRAGMENT));
+}
+
+TEST(UriSuite, TestNormalizeSyntaxPort) {
+ // Empty port text unchanged
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:/", L"scheme://host:/",
+ URI_NORMALIZE_PORT));
+ // Zero port unchanged
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:0/", L"scheme://host:0/",
+ URI_NORMALIZE_PORT));
+ // All-zeros port turned into single zero
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:00/", L"scheme://host:0/",
+ URI_NORMALIZE_PORT));
+ // Leading zeros cut off
+ ASSERT_TRUE(testNormalizeSyntaxHelper(L"scheme://host:00080/", L"scheme://host:80/",
+ URI_NORMALIZE_PORT));
}
TEST(UriSuite, TestNormalizeSyntaxPath) {
- // These are from GitHub issue #92
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/b/c/../../..",
- L"http://a/",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/b/../c/../..",
- L"http://a/",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/b/c/../../..",
- L"http://a/",
- URI_NORMALIZE_PATH));
-
- // .. and these are related
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/..",
- L"http://a/",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"/..",
- L"/",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/..///",
- L"http://a///",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"http://a/..///..",
- L"http://a//",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"a/b/c/../../..",
- L"",
- URI_NORMALIZE_PATH));
- EXPECT_TRUE(testNormalizeSyntaxHelper(
- L"a/b/../../c/..",
- L"",
- URI_NORMALIZE_PATH));
+ // These are from GitHub issue #92
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/c/../../..", L"http://a/",
+ URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/../c/../..", L"http://a/",
+ URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/b/c/../../..", L"http://a/",
+ URI_NORMALIZE_PATH));
+
+ // .. and these are related
+ EXPECT_TRUE(
+ testNormalizeSyntaxHelper(L"http://a/..", L"http://a/", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"/..", L"/", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(
+ testNormalizeSyntaxHelper(L"http://a/..///", L"http://a///", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"http://a/..///..", L"http://a//",
+ URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"a/b/c/../../..", L"", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"a/b/../../c/..", L"", URI_NORMALIZE_PATH));
}
TEST(UriSuite, TestNormalizeCrashBug20080224) {
- UriParserStateW stateW;
- int res;
- UriUriW testUri;
- stateW.uri = &testUri;
-
- res = uriParseUriW(&stateW, L"http://example.org/abc//../def");
- ASSERT_TRUE(res == 0);
-
- // First call will make us owner of copied memory
- res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_SCHEME);
- ASSERT_TRUE(res == 0);
- res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_HOST);
- ASSERT_TRUE(res == 0);
-
- // Frees empty path segment -> crash
- res = uriNormalizeSyntaxW(&testUri);
- ASSERT_TRUE(res == 0);
-
- uriFreeUriMembersW(&testUri);
+ UriParserStateW stateW;
+ int res;
+ UriUriW testUri;
+ stateW.uri = &testUri;
+
+ res = uriParseUriW(&stateW, L"http://example.org/abc//../def");
+ ASSERT_EQ(res, 0);
+
+ // First call will make us owner of copied memory
+ res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_SCHEME);
+ ASSERT_EQ(res, 0);
+ res = uriNormalizeSyntaxExW(&testUri, URI_NORMALIZE_HOST);
+ ASSERT_EQ(res, 0);
+
+ // Frees empty path segment -> crash
+ res = uriNormalizeSyntaxW(&testUri);
+ ASSERT_EQ(res, 0);
+
+ uriFreeUriMembersW(&testUri);
+}
+
+TEST(UriSuite, TestNormalizeBug262Fixed) {
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:/.//foo/bar", L"scheme:/.//foo/bar",
+ URI_NORMALIZE_PATH));
+ EXPECT_TRUE(
+ testNormalizeSyntaxHelper(L"/.//foo/bar", L"/.//foo/bar", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(
+ testNormalizeSyntaxHelper(L".//foo/bar", L".//foo/bar", URI_NORMALIZE_PATH));
+}
+
+TEST(UriSuite, TestNormalizeBug262Unchanged) {
+ // 3x same as TestNormalizeBug262Fixed above
+ // but with a single slash rather than double slashes
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:/./foo/bar", L"scheme:/foo/bar",
+ URI_NORMALIZE_PATH));
+ EXPECT_TRUE(
+ testNormalizeSyntaxHelper(L"/./foo/bar", L"/foo/bar", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"./foo/bar", L"foo/bar", URI_NORMALIZE_PATH));
+
+ // 2x same as TestNormalizeBug262Fixed above
+ // but with a host added
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme://host/.//foo/bar",
+ L"scheme://host//foo/bar", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"//host/.//foo/bar", L"//host//foo/bar",
+ URI_NORMALIZE_PATH));
+
+ // Second path segment containing a colon
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"scheme:./path1:/path2",
+ L"scheme:path1:/path2", URI_NORMALIZE_PATH));
+ EXPECT_TRUE(testNormalizeSyntaxHelper(L"./path1:/path2", L"./path1:/path2",
+ URI_NORMALIZE_PATH));
}
namespace {
- void testFilenameUriConversionHelper(const wchar_t * filename,
- const wchar_t * uriString, bool forUnix,
- const wchar_t * expectedUriString = NULL) {
- const int prefixLen = forUnix ? 7 : 8;
- if (! expectedUriString) {
- expectedUriString = uriString;
- }
-
- // Filename to URI string
- const size_t uriBufferLen = prefixLen + 3 * wcslen(filename) + 1;
- wchar_t * uriBuffer = new wchar_t[uriBufferLen];
- if (forUnix) {
- uriUnixFilenameToUriStringW(filename, uriBuffer);
- } else {
- uriWindowsFilenameToUriStringW(filename, uriBuffer);
- }
-#ifdef HAVE_WPRINTF
- // wprintf(L"1 [%s][%s]\n", uriBuffer, expectedUriString);
-#endif
- ASSERT_TRUE(!wcscmp(uriBuffer, expectedUriString));
- delete [] uriBuffer;
-
- // URI string to filename
- const size_t filenameBufferLen = wcslen(uriString) + 1;
- wchar_t * filenameBuffer = new wchar_t[filenameBufferLen];
- if (forUnix) {
- uriUriStringToUnixFilenameW(uriString, filenameBuffer);
- } else {
- uriUriStringToWindowsFilenameW(uriString, filenameBuffer);
- }
-#ifdef HAVE_WPRINTF
- // wprintf(L"2 [%s][%s]\n", filenameBuffer, filename);
-#endif
- ASSERT_TRUE(!wcscmp(filenameBuffer, filename));
- delete [] filenameBuffer;
- }
+void testFilenameUriConversionHelper(const wchar_t * filename, const wchar_t * uriString,
+ bool forUnix,
+ const wchar_t * expectedUriString = NULL) {
+ const int prefixLen = forUnix ? 7 : 8;
+ if (!expectedUriString) {
+ expectedUriString = uriString;
+ }
+
+ // Filename to URI string
+ const size_t uriBufferLen = prefixLen + 3 * wcslen(filename) + 1;
+ wchar_t * uriBuffer = new wchar_t[uriBufferLen];
+ if (forUnix) {
+ uriUnixFilenameToUriStringW(filename, uriBuffer);
+ } else {
+ uriWindowsFilenameToUriStringW(filename, uriBuffer);
+ }
+ ASSERT_TRUE(!wcscmp(uriBuffer, expectedUriString));
+ delete[] uriBuffer;
+
+ // URI string to filename
+ const size_t filenameBufferLen = wcslen(uriString) + 1;
+ wchar_t * filenameBuffer = new wchar_t[filenameBufferLen];
+ if (forUnix) {
+ uriUriStringToUnixFilenameW(uriString, filenameBuffer);
+ } else {
+ uriUriStringToWindowsFilenameW(uriString, filenameBuffer);
+ }
+ ASSERT_TRUE(!wcscmp(filenameBuffer, filename));
+ delete[] filenameBuffer;
+}
} // namespace
TEST(UriSuite, TestFilenameUriConversion) {
- const bool FOR_UNIX = true;
- const bool FOR_WINDOWS = false;
- testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX);
- testFilenameUriConversionHelper(L"/bin/bash", L"file:/bin/bash", FOR_UNIX, L"file:///bin/bash");
- testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX);
+ const bool FOR_UNIX = true;
+ const bool FOR_WINDOWS = false;
+ testFilenameUriConversionHelper(L"/bin/bash", L"file:///bin/bash", FOR_UNIX);
+ testFilenameUriConversionHelper(L"/bin/bash", L"file:/bin/bash", FOR_UNIX,
+ L"file:///bin/bash");
+ testFilenameUriConversionHelper(L"./configure", L"./configure", FOR_UNIX);
- testFilenameUriConversionHelper(L"E:\\Documents and Settings", L"file:///E:/Documents%20and%20Settings", FOR_WINDOWS);
- testFilenameUriConversionHelper(L"c:\\path\\to\\file.txt", L"file:c:/path/to/file.txt", FOR_WINDOWS, L"file:///c:/path/to/file.txt");
+ testFilenameUriConversionHelper(L"E:\\Documents and Settings",
+ L"file:///E:/Documents%20and%20Settings",
+ FOR_WINDOWS);
+ testFilenameUriConversionHelper(L"c:\\path\\to\\file.txt",
+ L"file:c:/path/to/file.txt", FOR_WINDOWS,
+ L"file:///c:/path/to/file.txt");
- testFilenameUriConversionHelper(L".\\Readme.txt", L"./Readme.txt", FOR_WINDOWS);
+ testFilenameUriConversionHelper(L".\\Readme.txt", L"./Readme.txt", FOR_WINDOWS);
- testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_WINDOWS);
- testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_UNIX);
+ testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_WINDOWS);
+ testFilenameUriConversionHelper(L"index.htm", L"index.htm", FOR_UNIX);
- testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_WINDOWS);
- testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_UNIX);
+ testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_WINDOWS);
+ testFilenameUriConversionHelper(L"abc def", L"abc%20def", FOR_UNIX);
- testFilenameUriConversionHelper(L"\\\\Server01\\user\\docs\\Letter.txt", L"file://Server01/user/docs/Letter.txt", FOR_WINDOWS);
+ testFilenameUriConversionHelper(L"\\\\Server01\\user\\docs\\Letter.txt",
+ L"file://Server01/user/docs/Letter.txt", FOR_WINDOWS);
}
TEST(UriSuite, TestCrashFreeUriMembersBug20080116) {
- // Testcase by Adrian Manrique
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
- uriParseUriA(&state, "http://test/?");
- uriNormalizeSyntaxA(&uri);
- uriFreeUriMembersA(&uri);
+ // Testcase by Adrian Manrique
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+ uriParseUriA(&state, "http://test/?");
+ uriNormalizeSyntaxA(&uri);
+ uriFreeUriMembersA(&uri);
- ASSERT_TRUE(true);
+ ASSERT_TRUE(true);
}
namespace {
- void helperTestQueryString(char const * uriString, int pairsExpected);
+void helperTestQueryString(char const * uriString, int pairsExpected);
}
TEST(UriSuite, TestCrashReport2418192) {
- // Testcase by Harvey Vrsalovic
- helperTestQueryString("http://svcs.cnn.com/weather/wrapper.jsp?&csiID=csi1", 1);
+ // Testcase by Harvey Vrsalovic
+ helperTestQueryString("http://svcs.cnn.com/weather/wrapper.jsp?&csiID=csi1", 1);
}
TEST(UriSuite, TestPervertedQueryString) {
- helperTestQueryString("http://example.org/?&&=&&&=&&&&==&===&====", 5);
+ helperTestQueryString("http://example.org/?&&=&&&=&&&&==&===&====", 5);
}
TEST(UriSuite, TestQueryStringEndingInEqualSignNonBug32) {
- const char * queryString = "firstname=sdsd&lastname=";
+ const char * queryString = "firstname=sdsd&lastname=";
- UriQueryListA * queryList = NULL;
- int itemCount = 0;
- const int res = uriDissectQueryMallocA(&queryList, &itemCount,
- queryString, queryString + strlen(queryString));
+ UriQueryListA * queryList = NULL;
+ int itemCount = 0;
+ const int res = uriDissectQueryMallocA(&queryList, &itemCount, queryString,
+ queryString + strlen(queryString));
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(itemCount == 2);
- ASSERT_TRUE(queryList != NULL);
- ASSERT_TRUE(strcmp(queryList->key, "firstname") == 0);
- ASSERT_TRUE(strcmp(queryList->value, "sdsd") == 0);
- ASSERT_TRUE(strcmp(queryList->next->key, "lastname") == 0);
- ASSERT_TRUE(strcmp(queryList->next->value, "") == 0);
- ASSERT_TRUE(queryList->next->next == NULL);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_EQ(itemCount, 2);
+ ASSERT_TRUE(queryList != NULL);
+ EXPECT_STREQ(queryList->key, "firstname");
+ EXPECT_STREQ(queryList->value, "sdsd");
+ EXPECT_STREQ(queryList->next->key, "lastname");
+ EXPECT_STREQ(queryList->next->value, "");
+ ASSERT_TRUE(queryList->next->next == NULL);
- uriFreeQueryListA(queryList);
+ uriFreeQueryListA(queryList);
}
namespace {
- void helperTestQueryString(char const * uriString, int pairsExpected) {
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
- int res = uriParseUriA(&state, uriString);
- ASSERT_TRUE(res == URI_SUCCESS);
-
- UriQueryListA * queryList = NULL;
- int itemCount = 0;
-
- res = uriDissectQueryMallocA(&queryList, &itemCount,
- uri.query.first, uri.query.afterLast);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(queryList != NULL);
- ASSERT_TRUE(itemCount == pairsExpected);
- uriFreeQueryListA(queryList);
- uriFreeUriMembersA(&uri);
- }
+void helperTestQueryString(char const * uriString, int pairsExpected) {
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+ int res = uriParseUriA(&state, uriString);
+ ASSERT_EQ(res, URI_SUCCESS);
+
+ UriQueryListA * queryList = NULL;
+ int itemCount = 0;
+
+ res = uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
+ uri.query.afterLast);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(queryList != NULL);
+ ASSERT_EQ(itemCount, pairsExpected);
+ uriFreeQueryListA(queryList);
+ uriFreeUriMembersA(&uri);
+}
} // namespace
TEST(UriSuite, TestCrashMakeOwnerBug20080207) {
- // Testcase by Adrian Manrique
- UriParserStateA state;
- UriUriA sourceUri;
- state.uri = &sourceUri;
- const char * const sourceUriString = "http://user:pass@somehost.com:80/";
- if (uriParseUriA(&state, sourceUriString) != 0) {
- ASSERT_TRUE(false);
- }
- if (uriNormalizeSyntaxA(&sourceUri) != 0) {
- ASSERT_TRUE(false);
- }
- uriFreeUriMembersA(&sourceUri);
- ASSERT_TRUE(true);
+ // Testcase by Adrian Manrique
+ UriParserStateA state;
+ UriUriA sourceUri;
+ state.uri = &sourceUri;
+ const char * const sourceUriString = "http://user:pass@somehost.com:80/";
+ if (uriParseUriA(&state, sourceUriString) != 0) {
+ ASSERT_TRUE(false);
+ }
+ if (uriNormalizeSyntaxA(&sourceUri) != 0) {
+ ASSERT_TRUE(false);
+ }
+ uriFreeUriMembersA(&sourceUri);
+ ASSERT_TRUE(true);
}
namespace {
- void testQueryListHelper(const wchar_t * input, int expectedItemCount) {
- int res;
-
- UriBool spacePlusConversion = URI_TRUE;
- UriBool normalizeBreaks = URI_FALSE;
- UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
-
- int itemCount;
- UriQueryListW * queryList;
- res = uriDissectQueryMallocExW(&queryList, &itemCount,
- input, input + wcslen(input), spacePlusConversion, breakConversion);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(itemCount == expectedItemCount);
- ASSERT_TRUE((queryList == NULL) == (expectedItemCount == 0));
-
- if (expectedItemCount != 0) {
- // First
- int charsRequired;
- res = uriComposeQueryCharsRequiredExW(queryList, &charsRequired, spacePlusConversion,
- normalizeBreaks);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(charsRequired >= (int)wcslen(input));
-
- wchar_t * recomposed = new wchar_t[charsRequired + 1];
- int charsWritten;
- res = uriComposeQueryExW(recomposed, queryList, charsRequired + 1,
- &charsWritten, spacePlusConversion, normalizeBreaks);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(charsWritten <= charsRequired);
- ASSERT_TRUE(charsWritten == (int)wcslen(input) + 1);
- ASSERT_TRUE(!wcscmp(input, recomposed));
- delete [] recomposed;
-
- recomposed = NULL;
- res = uriComposeQueryMallocW(&recomposed, queryList);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(recomposed != NULL);
- ASSERT_TRUE(charsWritten == (int)wcslen(input) + 1);
- ASSERT_TRUE(!wcscmp(input, recomposed));
- free(recomposed);
- }
-
- uriFreeQueryListW(queryList);
- }
+void testQueryListHelper(const wchar_t * input, int expectedItemCount) {
+ int res;
+
+ UriBool spacePlusConversion = URI_TRUE;
+ UriBool normalizeBreaks = URI_FALSE;
+ UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
+
+ int itemCount;
+ UriQueryListW * queryList;
+ res = uriDissectQueryMallocExW(&queryList, &itemCount, input, input + wcslen(input),
+ spacePlusConversion, breakConversion);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_EQ(itemCount, expectedItemCount);
+ ASSERT_EQ((queryList == NULL), (expectedItemCount == 0));
+
+ if (expectedItemCount != 0) {
+ // First
+ int charsRequired;
+ res = uriComposeQueryCharsRequiredExW(queryList, &charsRequired,
+ spacePlusConversion, normalizeBreaks);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(charsRequired >= (int)wcslen(input));
+
+ wchar_t * recomposed = new wchar_t[charsRequired + 1];
+ int charsWritten;
+ res = uriComposeQueryExW(recomposed, queryList, charsRequired + 1, &charsWritten,
+ spacePlusConversion, normalizeBreaks);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(charsWritten <= charsRequired);
+ ASSERT_EQ(charsWritten, (int)wcslen(input) + 1);
+ ASSERT_TRUE(!wcscmp(input, recomposed));
+ delete[] recomposed;
+
+ recomposed = NULL;
+ res = uriComposeQueryMallocW(&recomposed, queryList);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(recomposed != NULL);
+ ASSERT_EQ(charsWritten, (int)wcslen(input) + 1);
+ ASSERT_TRUE(!wcscmp(input, recomposed));
+ free(recomposed);
+ }
+
+ uriFreeQueryListW(queryList);
+}
} // namespace
TEST(UriSuite, QueryList) {
- testQueryListHelper(L"one=ONE&two=TWO", 2);
- testQueryListHelper(L"one=ONE&two=&three=THREE", 3);
- testQueryListHelper(L"one=ONE&two&three=THREE", 3);
- testQueryListHelper(L"one=ONE", 1);
- testQueryListHelper(L"one", 1);
- testQueryListHelper(L"", 0);
+ testQueryListHelper(L"one=ONE&two=TWO", 2);
+ testQueryListHelper(L"one=ONE&two=&three=THREE", 3);
+ testQueryListHelper(L"one=ONE&two&three=THREE", 3);
+ testQueryListHelper(L"one=ONE", 1);
+ testQueryListHelper(L"one", 1);
+ testQueryListHelper(L"", 0);
}
namespace {
- void testQueryListPairHelper(const char * pair, const char * unescapedKey,
- const char * unescapedValue, const char * fixed = NULL) {
- int res;
- UriQueryListA * queryList;
- int itemCount;
-
- res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair));
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(queryList != NULL);
- ASSERT_TRUE(itemCount == 1);
- ASSERT_TRUE(!strcmp(queryList->key, unescapedKey));
- ASSERT_TRUE(!strcmp(queryList->value, unescapedValue));
-
- char * recomposed;
- res = uriComposeQueryMallocA(&recomposed, queryList);
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(recomposed != NULL);
- ASSERT_TRUE(!strcmp(recomposed, (fixed != NULL) ? fixed : pair));
- free(recomposed);
- uriFreeQueryListA(queryList);
- }
+void testQueryListPairHelper(const char * pair, const char * unescapedKey,
+ const char * unescapedValue, const char * fixed = NULL) {
+ int res;
+ UriQueryListA * queryList;
+ int itemCount;
+
+ res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair));
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(queryList != NULL);
+ ASSERT_EQ(itemCount, 1);
+ EXPECT_STREQ(queryList->key, unescapedKey);
+ EXPECT_STREQ(queryList->value, unescapedValue);
+
+ char * recomposed;
+ res = uriComposeQueryMallocA(&recomposed, queryList);
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(recomposed != NULL);
+ EXPECT_STREQ(recomposed, (fixed != NULL) ? fixed : pair);
+ free(recomposed);
+ uriFreeQueryListA(queryList);
+}
} // namespace
TEST(UriSuite, TestQueryListPair) {
- testQueryListPairHelper("one+two+%26+three=%2B", "one two & three", "+");
- testQueryListPairHelper("one=two=three", "one", "two=three", "one=two%3Dthree");
- testQueryListPairHelper("one=two=three=four", "one", "two=three=four", "one=two%3Dthree%3Dfour");
+ testQueryListPairHelper("one+two+%26+three=%2B", "one two & three", "+");
+ testQueryListPairHelper("one=two=three", "one", "two=three", "one=two%3Dthree");
+ testQueryListPairHelper("one=two=three=four", "one", "two=three=four",
+ "one=two%3Dthree%3Dfour");
}
TEST(UriSuite, TestQueryDissectionBug3590761) {
- int res;
- UriQueryListA * queryList;
- int itemCount;
- const char * const pair = "q=hello&x=&y=";
+ int res;
+ UriQueryListA * queryList;
+ int itemCount;
+ const char * const pair = "q=hello&x=&y=";
- res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair));
- ASSERT_TRUE(res == URI_SUCCESS);
- ASSERT_TRUE(queryList != NULL);
- ASSERT_TRUE(itemCount == 3);
+ res = uriDissectQueryMallocA(&queryList, &itemCount, pair, pair + strlen(pair));
+ ASSERT_EQ(res, URI_SUCCESS);
+ ASSERT_TRUE(queryList != NULL);
+ ASSERT_EQ(itemCount, 3);
- ASSERT_TRUE(!strcmp(queryList->key, "q"));
- ASSERT_TRUE(!strcmp(queryList->value, "hello"));
+ EXPECT_STREQ(queryList->key, "q");
+ EXPECT_STREQ(queryList->value, "hello");
- ASSERT_TRUE(!strcmp(queryList->next->key, "x"));
- ASSERT_TRUE(!strcmp(queryList->next->value, ""));
+ EXPECT_STREQ(queryList->next->key, "x");
+ EXPECT_STREQ(queryList->next->value, "");
- ASSERT_TRUE(!strcmp(queryList->next->next->key, "y"));
- ASSERT_TRUE(!strcmp(queryList->next->next->value, ""));
+ EXPECT_STREQ(queryList->next->next->key, "y");
+ EXPECT_STREQ(queryList->next->next->value, "");
- ASSERT_TRUE(! queryList->next->next->next);
+ ASSERT_TRUE(!queryList->next->next->next);
- uriFreeQueryListA(queryList);
+ uriFreeQueryListA(queryList);
}
TEST(UriSuite, TestQueryCompositionMathCalc) {
- UriQueryListA second = { /*.key =*/ "k2", /*.value =*/ "v2", /*.next =*/ NULL };
- UriQueryListA first = { /*.key =*/ "k1", /*.value =*/ "v1", /*.next =*/ &second };
+ UriQueryListA second = {/*.key =*/"k2", /*.value =*/"v2", /*.next =*/NULL};
+ UriQueryListA first = {/*.key =*/"k1", /*.value =*/"v1", /*.next =*/&second};
- int charsRequired;
- ASSERT_TRUE(uriComposeQueryCharsRequiredA(&first, &charsRequired)
- == URI_SUCCESS);
+ int charsRequired;
+ ASSERT_TRUE(uriComposeQueryCharsRequiredA(&first, &charsRequired) == URI_SUCCESS);
- const int FACTOR = 6; /* due to escaping with normalizeBreaks */
- ASSERT_TRUE((unsigned)charsRequired ==
- FACTOR * strlen(first.key) + 1 + FACTOR * strlen(first.value)
- + 1
- + FACTOR * strlen(second.key) + 1 + FACTOR * strlen(second.value)
- );
+ const int FACTOR = 6; /* due to escaping with normalizeBreaks */
+ ASSERT_EQ((unsigned)charsRequired,
+ FACTOR * strlen(first.key) + 1 + FACTOR * strlen(first.value) + 1
+ + FACTOR * strlen(second.key) + 1 + FACTOR * strlen(second.value));
}
TEST(UriSuite, TestQueryCompositionMathWriteGoogleAutofuzz113244572) {
- UriQueryListA second = { /*.key =*/ "\x11", /*.value =*/ NULL, /*.next =*/ NULL };
- UriQueryListA first = { /*.key =*/ "\x01", /*.value =*/ "\x02", /*.next =*/ &second };
-
- const UriBool spaceToPlus = URI_TRUE;
- const UriBool normalizeBreaks = URI_FALSE; /* for factor 3 but 6 */
-
- const int charsRequired = (3 + 1 + 3) + 1 + (3);
-
- {
- // Minimum space to hold everything fine
- const char * const expected = "%01=%02" "&" "%11";
- char dest[charsRequired + 1];
- int charsWritten;
- ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest),
- &charsWritten, spaceToPlus, normalizeBreaks)
- == URI_SUCCESS);
- ASSERT_TRUE(! strcmp(dest, expected));
- ASSERT_TRUE(charsWritten == strlen(expected) + 1);
- }
-
- {
- // Previous math failed to take ampersand into account
- char dest[charsRequired + 1 - 1];
- int charsWritten;
- ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest),
- &charsWritten, spaceToPlus, normalizeBreaks)
- == URI_ERROR_OUTPUT_TOO_LARGE);
- }
+ UriQueryListA second = {/*.key =*/"\x11", /*.value =*/NULL, /*.next =*/NULL};
+ UriQueryListA first = {/*.key =*/"\x01", /*.value =*/"\x02", /*.next =*/&second};
+
+ const UriBool spaceToPlus = URI_TRUE;
+ const UriBool normalizeBreaks = URI_FALSE; /* for factor 3 but 6 */
+
+ const int charsRequired = (3 + 1 + 3) + 1 + (3);
+
+ {
+ // Minimum space to hold everything fine
+ const char * const expected = "%01=%02"
+ "&"
+ "%11";
+ char dest[charsRequired + 1];
+ int charsWritten;
+ ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), &charsWritten,
+ spaceToPlus, normalizeBreaks)
+ == URI_SUCCESS);
+ EXPECT_STREQ(dest, expected);
+ ASSERT_EQ(charsWritten, strlen(expected) + 1);
+ }
+
+ {
+ // Previous math failed to take ampersand into account
+ char dest[charsRequired + 1 - 1];
+ int charsWritten;
+ ASSERT_TRUE(uriComposeQueryExA(dest, &first, sizeof(dest), &charsWritten,
+ spaceToPlus, normalizeBreaks)
+ == URI_ERROR_OUTPUT_TOO_LARGE);
+ }
}
TEST(UriSuite, TestFreeCrashBug20080827) {
- char const * const sourceUri = "abc";
- char const * const baseUri = "http://www.example.org/";
+ char const * const sourceUri = "abc";
+ char const * const baseUri = "http://www.example.org/";
- int res;
- UriParserStateA state;
- UriUriA absoluteDest;
- UriUriA relativeSource;
- UriUriA absoluteBase;
+ int res;
+ UriParserStateA state;
+ UriUriA absoluteDest;
+ UriUriA relativeSource;
+ UriUriA absoluteBase;
- state.uri = &relativeSource;
- res = uriParseUriA(&state, sourceUri);
- ASSERT_TRUE(res == URI_SUCCESS);
+ state.uri = &relativeSource;
+ res = uriParseUriA(&state, sourceUri);
+ ASSERT_EQ(res, URI_SUCCESS);
- state.uri = &absoluteBase;
- res = uriParseUriA(&state, baseUri);
- ASSERT_TRUE(res == URI_SUCCESS);
+ state.uri = &absoluteBase;
+ res = uriParseUriA(&state, baseUri);
+ ASSERT_EQ(res, URI_SUCCESS);
- res = uriRemoveBaseUriA(&absoluteDest, &relativeSource, &absoluteBase, URI_FALSE);
- ASSERT_TRUE(res == URI_ERROR_REMOVEBASE_REL_SOURCE);
+ res = uriRemoveBaseUriA(&absoluteDest, &relativeSource, &absoluteBase, URI_FALSE);
+ ASSERT_EQ(res, URI_ERROR_REMOVEBASE_REL_SOURCE);
- uriFreeUriMembersA(&relativeSource);
- uriFreeUriMembersA(&absoluteBase);
- uriFreeUriMembersA(&absoluteDest); // Crashed here
+ uriFreeUriMembersA(&relativeSource);
+ uriFreeUriMembersA(&absoluteBase);
+ uriFreeUriMembersA(&absoluteDest); // Crashed here
}
TEST(UriSuite, TestInvalidInputBug16) {
- UriParserStateA stateA;
- UriUriA uriA;
- stateA.uri = &uriA;
- const char * const input = "A>B";
+ UriParserStateA stateA;
+ UriUriA uriA;
+ stateA.uri = &uriA;
+ const char * const input = "A>B";
- const int res = uriParseUriA(&stateA, input);
+ const int res = uriParseUriA(&stateA, input);
- ASSERT_TRUE(res == URI_ERROR_SYNTAX);
- ASSERT_TRUE(stateA.errorPos == input + 1);
- ASSERT_TRUE(stateA.errorCode == URI_ERROR_SYNTAX); /* failed previously */
+ ASSERT_EQ(res, URI_ERROR_SYNTAX);
+ ASSERT_EQ(stateA.errorPos, input + 1);
+ ASSERT_EQ(stateA.errorCode, URI_ERROR_SYNTAX); /* failed previously */
- uriFreeUriMembersA(&uriA);
+ uriFreeUriMembersA(&uriA);
}
namespace {
- void testEqualsHelper(const char * uri_to_test) {
- UriParserStateA state;
- UriUriA uriOne;
- UriUriA uriTwo;
- state.uri = &uriOne;
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, uri_to_test));
- state.uri = &uriTwo;
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, uri_to_test));
- ASSERT_TRUE(URI_TRUE == uriEqualsUriA(&uriOne, &uriTwo));
- uriFreeUriMembersA(&uriOne);
- uriFreeUriMembersA(&uriTwo);
- }
+void testEqualsHelper(const char * uri_to_test) {
+ UriParserStateA state;
+ UriUriA uriOne;
+ UriUriA uriTwo;
+ state.uri = &uriOne;
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, uri_to_test));
+ state.uri = &uriTwo;
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, uri_to_test));
+ ASSERT_EQ(URI_TRUE, uriEqualsUriA(&uriOne, &uriTwo));
+ uriFreeUriMembersA(&uriOne);
+ uriFreeUriMembersA(&uriTwo);
+}
} // namespace
TEST(UriSuite, TestEquals) {
- testEqualsHelper("http://host");
- testEqualsHelper("http://host:123");
- testEqualsHelper("http://foo:bar@host:123");
- testEqualsHelper("http://foo:bar@host:123/");
- testEqualsHelper("http://foo:bar@host:123/path");
- testEqualsHelper("http://foo:bar@host:123/path?query");
- testEqualsHelper("http://foo:bar@host:123/path?query#fragment");
-
- testEqualsHelper("path");
- testEqualsHelper("/path");
- testEqualsHelper("/path/");
- testEqualsHelper("//path/");
- testEqualsHelper("//host");
- testEqualsHelper("//host:123");
+ testEqualsHelper("http://host");
+ testEqualsHelper("http://host:123");
+ testEqualsHelper("http://foo:bar@host:123");
+ testEqualsHelper("http://foo:bar@host:123/");
+ testEqualsHelper("http://foo:bar@host:123/path");
+ testEqualsHelper("http://foo:bar@host:123/path?query");
+ testEqualsHelper("http://foo:bar@host:123/path?query#fragment");
+
+ testEqualsHelper("path");
+ testEqualsHelper("/path");
+ testEqualsHelper("/path/");
+ testEqualsHelper("//path/");
+ testEqualsHelper("//host");
+ testEqualsHelper("//host:123");
}
TEST(UriSuite, TestHostTextTerminationIssue15) {
- UriParserStateA state;
- UriUriA uri;
- state.uri = &uri;
-
- // Empty host and port
- const char * const emptyHostWithPortUri = "//:123";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, emptyHostWithPortUri));
- ASSERT_TRUE(uri.hostText.first == emptyHostWithPortUri + strlen("//"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0);
- ASSERT_TRUE(uri.portText.first == emptyHostWithPortUri
- + strlen("//:"));
- ASSERT_TRUE(uri.portText.afterLast == uri.portText.first
- + strlen("123"));
- uriFreeUriMembersA(&uri);
-
- // Non-empty host and port
- const char * const hostWithPortUri = "//h:123";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, hostWithPortUri));
- ASSERT_TRUE(uri.hostText.first == hostWithPortUri + strlen("//"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first
- + strlen("h"));
- ASSERT_TRUE(uri.portText.first == hostWithPortUri + strlen("//h:"));
- ASSERT_TRUE(uri.portText.afterLast == uri.portText.first
- + strlen("123"));
- uriFreeUriMembersA(&uri);
-
- // Empty host, empty user info
- const char * const emptyHostEmptyUserInfoUri = "//@";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state,
- emptyHostEmptyUserInfoUri));
- ASSERT_TRUE(uri.userInfo.first == emptyHostEmptyUserInfoUri
- + strlen("//"));
- ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 0);
- ASSERT_TRUE(uri.hostText.first == emptyHostEmptyUserInfoUri
- + strlen("//@"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0);
- uriFreeUriMembersA(&uri);
-
- // Non-empty host, empty user info
- const char * const hostEmptyUserInfoUri = "//@h";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, hostEmptyUserInfoUri));
- ASSERT_TRUE(uri.userInfo.first == hostEmptyUserInfoUri + strlen("//"));
- ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 0);
- ASSERT_TRUE(uri.hostText.first == hostEmptyUserInfoUri
- + strlen("//@"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first
- + strlen("h"));
- uriFreeUriMembersA(&uri);
-
- // Empty host, non-empty user info
- const char * const emptyHostWithUserInfoUri = "//:@";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state,
- emptyHostWithUserInfoUri));
- ASSERT_TRUE(uri.userInfo.first == emptyHostWithUserInfoUri
- + strlen("//"));
- ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first + 1);
- ASSERT_TRUE(uri.hostText.first == emptyHostWithUserInfoUri
- + strlen("//:@"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0);
- uriFreeUriMembersA(&uri);
-
- // Exact case from issue #15
- const char * const issue15Uri = "//:%aa@";
- ASSERT_TRUE(URI_SUCCESS == uriParseUriA(&state, issue15Uri));
- ASSERT_TRUE(uri.userInfo.first == issue15Uri + strlen("//"));
- ASSERT_TRUE(uri.userInfo.afterLast == uri.userInfo.first
- + strlen(":%aa"));
- ASSERT_TRUE(uri.hostText.first == issue15Uri + strlen("//:%aa@"));
- ASSERT_TRUE(uri.hostText.afterLast == uri.hostText.first + 0);
- uriFreeUriMembersA(&uri);
+ UriParserStateA state;
+ UriUriA uri;
+ state.uri = &uri;
+
+ // Empty host and port
+ const char * const emptyHostWithPortUri = "//:123";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostWithPortUri));
+ ASSERT_EQ(uri.hostText.first, emptyHostWithPortUri + strlen("//"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0);
+ ASSERT_EQ(uri.portText.first, emptyHostWithPortUri + strlen("//:"));
+ ASSERT_EQ(uri.portText.afterLast, uri.portText.first + strlen("123"));
+ uriFreeUriMembersA(&uri);
+
+ // Non-empty host and port
+ const char * const hostWithPortUri = "//h:123";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, hostWithPortUri));
+ ASSERT_EQ(uri.hostText.first, hostWithPortUri + strlen("//"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + strlen("h"));
+ ASSERT_EQ(uri.portText.first, hostWithPortUri + strlen("//h:"));
+ ASSERT_EQ(uri.portText.afterLast, uri.portText.first + strlen("123"));
+ uriFreeUriMembersA(&uri);
+
+ // Empty host, empty user info
+ const char * const emptyHostEmptyUserInfoUri = "//@";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostEmptyUserInfoUri));
+ ASSERT_EQ(uri.userInfo.first, emptyHostEmptyUserInfoUri + strlen("//"));
+ ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 0);
+ ASSERT_EQ(uri.hostText.first, emptyHostEmptyUserInfoUri + strlen("//@"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0);
+ uriFreeUriMembersA(&uri);
+
+ // Non-empty host, empty user info
+ const char * const hostEmptyUserInfoUri = "//@h";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, hostEmptyUserInfoUri));
+ ASSERT_EQ(uri.userInfo.first, hostEmptyUserInfoUri + strlen("//"));
+ ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 0);
+ ASSERT_EQ(uri.hostText.first, hostEmptyUserInfoUri + strlen("//@"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + strlen("h"));
+ uriFreeUriMembersA(&uri);
+
+ // Empty host, non-empty user info
+ const char * const emptyHostWithUserInfoUri = "//:@";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, emptyHostWithUserInfoUri));
+ ASSERT_EQ(uri.userInfo.first, emptyHostWithUserInfoUri + strlen("//"));
+ ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + 1);
+ ASSERT_EQ(uri.hostText.first, emptyHostWithUserInfoUri + strlen("//:@"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0);
+ uriFreeUriMembersA(&uri);
+
+ // Exact case from issue #15
+ const char * const issue15Uri = "//:%aa@";
+ ASSERT_EQ(URI_SUCCESS, uriParseUriA(&state, issue15Uri));
+ ASSERT_EQ(uri.userInfo.first, issue15Uri + strlen("//"));
+ ASSERT_EQ(uri.userInfo.afterLast, uri.userInfo.first + strlen(":%aa"));
+ ASSERT_EQ(uri.hostText.first, issue15Uri + strlen("//:%aa@"));
+ ASSERT_EQ(uri.hostText.afterLast, uri.hostText.first + 0);
+ uriFreeUriMembersA(&uri);
}
namespace {
- void testCompareRangeHelper(const char * a, const char * b, int expected, bool avoidNullRange = true) {
- UriTextRangeA ra;
- UriTextRangeA rb;
-
- if (a) {
- ra.first = a;
- ra.afterLast = a + strlen(a);
- } else {
- ra.first = NULL;
- ra.afterLast = NULL;
- }
-
- if (b) {
- rb.first = b;
- rb.afterLast = b + strlen(b);
- } else {
- rb.first = NULL;
- rb.afterLast = NULL;
- }
-
- const int received = uriCompareRangeA(
- ((a == NULL) && avoidNullRange) ? NULL : &ra,
- ((b == NULL) && avoidNullRange) ? NULL : &rb);
- if (received != expected) {
- printf("Comparing <%s> to <%s> yields %d, expected %d.\n",
- a, b, received, expected);
- }
- ASSERT_TRUE(received == expected);
- }
+void testCompareRangeHelper(const char * a, const char * b, int expected,
+ bool avoidNullRange = true) {
+ UriTextRangeA ra;
+ UriTextRangeA rb;
+
+ if (a) {
+ ra.first = a;
+ ra.afterLast = a + strlen(a);
+ } else {
+ ra.first = NULL;
+ ra.afterLast = NULL;
+ }
+
+ if (b) {
+ rb.first = b;
+ rb.afterLast = b + strlen(b);
+ } else {
+ rb.first = NULL;
+ rb.afterLast = NULL;
+ }
+
+ const int received = uriCompareRangeA(((a == NULL) && avoidNullRange) ? NULL : &ra,
+ ((b == NULL) && avoidNullRange) ? NULL : &rb);
+ if (received != expected) {
+ printf("Comparing <%s> to <%s> yields %d, expected %d.\n", a, b, received,
+ expected);
+ }
+ ASSERT_EQ(received, expected);
+}
} // namespace
TEST(UriSuite, TestRangeComparison) {
- testCompareRangeHelper("", "", 0);
- testCompareRangeHelper("a", "", 1);
- testCompareRangeHelper("", "a", -1);
+ testCompareRangeHelper("", "", 0);
+ testCompareRangeHelper("a", "", 1);
+ testCompareRangeHelper("", "a", -1);
- testCompareRangeHelper("a", "a", 0);
- testCompareRangeHelper("a", "b", -1);
- testCompareRangeHelper("b", "a", 1);
+ testCompareRangeHelper("a", "a", 0);
+ testCompareRangeHelper("a", "b", -1);
+ testCompareRangeHelper("b", "a", 1);
- testCompareRangeHelper("a", "aa", -1);
- testCompareRangeHelper("aa", "a", 1);
+ testCompareRangeHelper("a", "aa", -1);
+ testCompareRangeHelper("aa", "a", 1);
- // Fixed with 0.8.1:
- testCompareRangeHelper(NULL, "a", -1);
- testCompareRangeHelper("a", NULL, 1);
- testCompareRangeHelper(NULL, NULL, 0);
+ // Fixed with 0.8.1:
+ testCompareRangeHelper(NULL, "a", -1);
+ testCompareRangeHelper("a", NULL, 1);
+ testCompareRangeHelper(NULL, NULL, 0);
- // Fixed with 0.8.3
- const bool KEEP_NULL_RANGE = false;
- const bool AVOID_NULL_RANGE = true;
- testCompareRangeHelper(NULL, "", -1, AVOID_NULL_RANGE);
- testCompareRangeHelper(NULL, "", -1, KEEP_NULL_RANGE);
- testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE);
- testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE);
+ // Fixed with 0.8.3
+ const bool KEEP_NULL_RANGE = false;
+ const bool AVOID_NULL_RANGE = true;
+ testCompareRangeHelper(NULL, "", -1, AVOID_NULL_RANGE);
+ testCompareRangeHelper(NULL, "", -1, KEEP_NULL_RANGE);
+ testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE);
+ testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE);
}
namespace {
- void testRemoveBaseUriHelper(const char * expected,
- const char * absSourceStr,
- const char * absBaseStr) {
- UriParserStateA state;
- UriUriA absSource;
- UriUriA absBase;
- UriUriA dest;
-
- state.uri = &absSource;
- ASSERT_TRUE(uriParseUriA(&state, absSourceStr) == URI_SUCCESS);
-
- state.uri = &absBase;
- ASSERT_TRUE(uriParseUriA(&state, absBaseStr) == URI_SUCCESS);
-
- ASSERT_TRUE(uriRemoveBaseUriA(&dest, &absSource, &absBase, URI_FALSE)
- == URI_SUCCESS);
-
- int size = 0;
- ASSERT_TRUE(uriToStringCharsRequiredA(&dest, &size) == URI_SUCCESS);
- char * const buffer = (char *)malloc(size + 1);
- ASSERT_TRUE(buffer);
- ASSERT_TRUE(uriToStringA(buffer, &dest, size + 1, &size)
- == URI_SUCCESS);
- if (strcmp(buffer, expected)) {
- printf("Expected \"%s\" but got \"%s\"\n", expected, buffer);
- ASSERT_TRUE(0);
- }
- free(buffer);
-
- uriFreeUriMembersA(&absSource);
- uriFreeUriMembersA(&absBase);
- uriFreeUriMembersA(&dest);
- }
+void testRemoveBaseUriHelper(const char * expected, const char * absSourceStr,
+ const char * absBaseStr) {
+ UriParserStateA state;
+ UriUriA absSource;
+ UriUriA absBase;
+ UriUriA dest;
+
+ state.uri = &absSource;
+ ASSERT_EQ(uriParseUriA(&state, absSourceStr), URI_SUCCESS);
+
+ state.uri = &absBase;
+ ASSERT_EQ(uriParseUriA(&state, absBaseStr), URI_SUCCESS);
+
+ ASSERT_TRUE(uriRemoveBaseUriA(&dest, &absSource, &absBase, URI_FALSE) == URI_SUCCESS);
+
+ int size = 0;
+ ASSERT_EQ(uriToStringCharsRequiredA(&dest, &size), URI_SUCCESS);
+ char * const buffer = (char *)malloc(size + 1);
+ ASSERT_TRUE(buffer);
+ ASSERT_TRUE(uriToStringA(buffer, &dest, size + 1, &size) == URI_SUCCESS);
+ EXPECT_STREQ(buffer, expected);
+ free(buffer);
+
+ uriFreeUriMembersA(&absSource);
+ uriFreeUriMembersA(&absBase);
+ uriFreeUriMembersA(&dest);
+}
} // namespace
TEST(UriSuite, TestRangeComparisonRemoveBaseUriIssue19) {
- // scheme
- testRemoveBaseUriHelper("scheme://host/source",
- "scheme://host/source",
- "schemelonger://host/base");
- testRemoveBaseUriHelper("schemelonger://host/source",
- "schemelonger://host/source",
- "scheme://host/base");
-
- // hostText
- testRemoveBaseUriHelper("//host/source",
- "http://host/source",
- "http://hostlonger/base");
- testRemoveBaseUriHelper("//hostlonger/source",
- "http://hostlonger/source",
- "http://host/base");
-
- // hostData.ipFuture
- testRemoveBaseUriHelper("//[v7.host]/source",
- "http://[v7.host]/source",
- "http://[v7.hostlonger]/base");
- testRemoveBaseUriHelper("//[v7.hostlonger]/source",
- "http://[v7.hostlonger]/source",
- "http://host/base");
-
- // path
- testRemoveBaseUriHelper("path1",
- "http://host/path1",
- "http://host/path111");
- testRemoveBaseUriHelper("../path1/path2",
- "http://host/path1/path2",
- "http://host/path111/path222");
- testRemoveBaseUriHelper("path111",
- "http://host/path111",
- "http://host/path1");
- testRemoveBaseUriHelper("../path111/path222",
- "http://host/path111/path222",
- "http://host/path1/path2");
-
- // Exact issue #19
- testRemoveBaseUriHelper("//example/x/abc",
- "http://example/x/abc",
- "http://example2/x/y/z");
+ // scheme
+ testRemoveBaseUriHelper("scheme://host/source", "scheme://host/source",
+ "schemelonger://host/base");
+ testRemoveBaseUriHelper("schemelonger://host/source", "schemelonger://host/source",
+ "scheme://host/base");
+
+ // hostText
+ testRemoveBaseUriHelper("//host/source", "http://host/source",
+ "http://hostlonger/base");
+ testRemoveBaseUriHelper("//hostlonger/source", "http://hostlonger/source",
+ "http://host/base");
+
+ // hostData.ipFuture
+ testRemoveBaseUriHelper("//[v7.host]/source", "http://[v7.host]/source",
+ "http://[v7.hostlonger]/base");
+ testRemoveBaseUriHelper("//[v7.hostlonger]/source", "http://[v7.hostlonger]/source",
+ "http://host/base");
+
+ // path
+ testRemoveBaseUriHelper("path1", "http://host/path1", "http://host/path111");
+ testRemoveBaseUriHelper("../path1/path2", "http://host/path1/path2",
+ "http://host/path111/path222");
+ testRemoveBaseUriHelper("path111", "http://host/path111", "http://host/path1");
+ testRemoveBaseUriHelper("../path111/path222", "http://host/path111/path222",
+ "http://host/path1/path2");
+
+ // Exact issue #19
+ testRemoveBaseUriHelper("//example/x/abc", "http://example/x/abc",
+ "http://example2/x/y/z");
}
TEST(ErrorPosSuite, TestErrorPosIPvFuture) {
- UriUriA uri;
- const char * errorPos;
+ UriUriA uri;
+ const char * errorPos;
- const char * const uriText = "http://[vA.123456"; // missing "]"
- EXPECT_EQ(uriParseSingleUriA(&uri, uriText, &errorPos),
- URI_ERROR_SYNTAX);
- EXPECT_EQ(errorPos, uriText + strlen(uriText));
+ const char * const uriText = "http://[vA.123456"; // missing "]"
+ EXPECT_EQ(uriParseSingleUriA(&uri, uriText, &errorPos), URI_ERROR_SYNTAX);
+ EXPECT_EQ(errorPos, uriText + strlen(uriText));
}
TEST(UriParseSingleSuite, Success) {
- UriUriA uri;
+ UriUriA uri;
- EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL),
- URI_SUCCESS);
+ EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), URI_SUCCESS);
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
}
TEST(UriParseSingleSuite, ErrorSyntaxParseErrorSetsErrorPos) {
- UriUriA uri;
- const char * errorPos;
- const char * const uriString = "abc{}def";
+ UriUriA uri;
+ const char * errorPos;
+ const char * const uriString = "abc{}def";
- EXPECT_EQ(uriParseSingleUriA(&uri, uriString, &errorPos),
- URI_ERROR_SYNTAX);
- EXPECT_EQ(errorPos, uriString + strlen("abc"));
+ EXPECT_EQ(uriParseSingleUriA(&uri, uriString, &errorPos), URI_ERROR_SYNTAX);
+ EXPECT_EQ(errorPos, uriString + strlen("abc"));
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
}
TEST(UriParseSingleSuite, ErrorNullFirstDetected) {
- UriUriA uri;
- const char * errorPos;
+ UriUriA uri;
+ const char * errorPos;
- EXPECT_EQ(uriParseSingleUriExA(&uri, NULL, "notnull", &errorPos),
- URI_ERROR_NULL);
+ EXPECT_EQ(uriParseSingleUriExA(&uri, NULL, "notnull", &errorPos), URI_ERROR_NULL);
}
TEST(UriParseSingleSuite, ErrorNullAfterLastDetected) {
- UriUriA uri;
+ UriUriA uri;
- EXPECT_EQ(uriParseSingleUriExA(&uri, "foo", NULL, NULL), URI_SUCCESS);
+ EXPECT_EQ(uriParseSingleUriExA(&uri, "foo", NULL, NULL), URI_SUCCESS);
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
}
TEST(UriParseSingleSuite, ErrorNullMemoryManagerDetected) {
- UriUriA uri;
- const char * errorPos;
- const char * const uriString = "somethingwellformed";
+ UriUriA uri;
+ const char * errorPos;
+ const char * const uriString = "somethingwellformed";
- EXPECT_EQ(uriParseSingleUriExMmA(&uri,
- uriString,
- uriString + strlen(uriString),
- &errorPos, NULL), URI_SUCCESS);
+ EXPECT_EQ(uriParseSingleUriExMmA(&uri, uriString, uriString + strlen(uriString),
+ &errorPos, NULL),
+ URI_SUCCESS);
- EXPECT_EQ(uriFreeUriMembersMmA(&uri, NULL), URI_SUCCESS);
+ EXPECT_EQ(uriFreeUriMembersMmA(&uri, NULL), URI_SUCCESS);
}
TEST(FreeUriMembersSuite, MultiFreeWorksFine) {
- UriUriA uri;
+ UriUriA uri;
- EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL),
- URI_SUCCESS);
+ EXPECT_EQ(uriParseSingleUriA(&uri, "file:///home/user/song.mp3", NULL), URI_SUCCESS);
- UriUriA uriBackup = uri;
- EXPECT_EQ(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0);
+ UriUriA uriBackup = uri;
+ EXPECT_EQ(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0);
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
- // Did some pointers change (to NULL)?
- EXPECT_NE(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0);
+ // Did some pointers change (to NULL)?
+ EXPECT_NE(memcmp(&uriBackup, &uri, sizeof(UriUriA)), 0);
- uriFreeUriMembersA(&uri); // second time
+ uriFreeUriMembersA(&uri); // second time
+}
+
+TEST(FreeUriMembersSuite, ZerosFreeWorksFine) {
+ UriUriA uri;
+ memset(&uri, 0, sizeof(uri));
+ uriFreeUriMembersA(&uri);
}
namespace {
- void testFreeUriMembersFreesHostText(const char *const uriFirst) { // issue #121
- const char *const uriAfterLast = uriFirst + strlen(uriFirst);
- UriUriA uri;
+void testFreeUriMembersFreesHostText(const char * const uriFirst) { // issue #121
+ const char * const uriAfterLast = uriFirst + strlen(uriFirst);
+ UriUriA uri;
- EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS);
- EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
+ EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS);
+ EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
- EXPECT_EQ(uri.owner, URI_TRUE);
- EXPECT_TRUE(uri.hostText.first);
- EXPECT_TRUE(uri.hostText.afterLast);
- EXPECT_NE(uri.hostText.first, uri.hostText.afterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
+ EXPECT_EQ(uri.owner, URI_TRUE);
+ EXPECT_TRUE(uri.hostText.first);
+ EXPECT_TRUE(uri.hostText.afterLast);
+ EXPECT_NE(uri.hostText.first, uri.hostText.afterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
- uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri);
- EXPECT_FALSE(uri.hostText.first);
- EXPECT_FALSE(uri.hostText.afterLast);
+ EXPECT_FALSE(uri.hostText.first);
+ EXPECT_FALSE(uri.hostText.afterLast);
- uriFreeUriMembersA(&uri); // second time
- }
+ uriFreeUriMembersA(&uri); // second time
+}
} // namespace
TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextIp4) { // issue #121
- testFreeUriMembersFreesHostText("//192.0.2.0"); // RFC 5737
+ testFreeUriMembersFreesHostText("//192.0.2.0"); // RFC 5737
}
TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextIp6) { // issue #121
- testFreeUriMembersFreesHostText("//[2001:db8::]"); // RFC 3849
+ testFreeUriMembersFreesHostText("//[2001:db8::]"); // RFC 3849
}
TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextRegname) { // issue #121
- testFreeUriMembersFreesHostText("//host123.test"); // RFC 6761
+ testFreeUriMembersFreesHostText("//host123.test"); // RFC 6761
}
TEST(FreeUriMembersSuite, FreeUriMembersFreesHostTextFuture) { // issue #121
- testFreeUriMembersFreesHostText("//[v7.X]"); // arbitrary IPvFuture
+ testFreeUriMembersFreesHostText("//[v7.X]"); // arbitrary IPvFuture
}
TEST(MakeOwnerSuite, MakeOwner) {
- const char * const uriString = "scheme://user:pass@[v7.X]:55555/path/../path/?query#fragment";
- UriUriA uri;
- char * uriFirst = strdup(uriString);
- const size_t uriLen = strlen(uriFirst);
- char * uriAfterLast = uriFirst + uriLen;
-
- EXPECT_EQ(uriParseSingleUriExA(&uri, uriFirst, uriAfterLast, NULL), URI_SUCCESS);
-
- // After plain parse, all strings should point inside the original URI string
- EXPECT_EQ(uri.owner, URI_FALSE);
- URI_EXPECT_RANGE_BETWEEN(uri.scheme, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.userInfo, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.hostData.ipFuture, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.portText, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.pathHead->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
- EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
- URI_EXPECT_RANGE_BETWEEN(uri.query, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_BETWEEN(uri.fragment, uriFirst, uriAfterLast);
-
- EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
-
- // After making owner, *none* of the strings should point inside the original URI string
- EXPECT_EQ(uri.owner, URI_TRUE);
- URI_EXPECT_RANGE_OUTSIDE(uri.scheme, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.userInfo, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.hostData.ipFuture, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.portText, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
- EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
- URI_EXPECT_RANGE_OUTSIDE(uri.query, uriFirst, uriAfterLast);
- URI_EXPECT_RANGE_OUTSIDE(uri.fragment, uriFirst, uriAfterLast);
-
- // Free originally used memory so we'd get violations on access with ASan
- uriAfterLast = NULL;
- free(uriFirst);
- uriFirst = NULL;
-
- // Can we recompose the URI without accessing any old freed memory?
- int charsRequired;
- EXPECT_EQ(uriToStringCharsRequiredA(&uri, &charsRequired), URI_SUCCESS);
- EXPECT_TRUE((charsRequired >= 0) && (charsRequired >= static_cast<int>(uriLen)));
- char * const uriRemake = new char[charsRequired + 1];
- EXPECT_TRUE(uriRemake != NULL);
- EXPECT_EQ(uriToStringA(uriRemake, &uri, charsRequired + 1, NULL), URI_SUCCESS);
- EXPECT_TRUE(! strcmp(uriString, uriRemake));
- delete [] uriRemake;
-
- uriFreeUriMembersA(&uri);
+ const char * const uriString =
+ "scheme://user:pass@[v7.X]:55555/path/../path/?query#fragment";
+ UriUriA uri;
+ char * uriFirst = strdup(uriString);
+ const size_t uriLen = strlen(uriFirst);
+ char * uriAfterLast = uriFirst + uriLen;
+
+ EXPECT_EQ(uriParseSingleUriExA(&uri, uriFirst, uriAfterLast, NULL), URI_SUCCESS);
+
+ // After plain parse, all strings should point inside the original URI string
+ EXPECT_EQ(uri.owner, URI_FALSE);
+ URI_EXPECT_RANGE_BETWEEN(uri.scheme, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.userInfo, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.hostData.ipFuture, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.portText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
+ EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
+ URI_EXPECT_RANGE_BETWEEN(uri.query, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_BETWEEN(uri.fragment, uriFirst, uriAfterLast);
+
+ EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
+
+ // After making owner, *none* of the strings should point inside the original URI
+ // string
+ EXPECT_EQ(uri.owner, URI_TRUE);
+ URI_EXPECT_RANGE_OUTSIDE(uri.scheme, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.userInfo, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostData.ipFuture, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.portText, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.pathHead->next->next->text, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_EMPTY(uri.pathHead->next->next->next->text);
+ EXPECT_TRUE(uri.pathHead->next->next->next->next == NULL);
+ URI_EXPECT_RANGE_OUTSIDE(uri.query, uriFirst, uriAfterLast);
+ URI_EXPECT_RANGE_OUTSIDE(uri.fragment, uriFirst, uriAfterLast);
+
+ // Free originally used memory so we'd get violations on access with ASan
+ uriAfterLast = NULL;
+ free(uriFirst);
+ uriFirst = NULL;
+
+ // Can we recompose the URI without accessing any old freed memory?
+ int charsRequired;
+ EXPECT_EQ(uriToStringCharsRequiredA(&uri, &charsRequired), URI_SUCCESS);
+ EXPECT_TRUE((charsRequired >= 0) && (charsRequired >= static_cast<int>(uriLen)));
+ char * const uriRemake = new char[charsRequired + 1];
+ EXPECT_TRUE(uriRemake != NULL);
+ EXPECT_EQ(uriToStringA(uriRemake, &uri, charsRequired + 1, NULL), URI_SUCCESS);
+ EXPECT_STREQ(uriString, uriRemake);
+ delete[] uriRemake;
+
+ uriFreeUriMembersA(&uri);
}
namespace {
- void testMakeOwnerCopiesHostText(const char *const uriFirst) { // issue #121
- const char *const uriAfterLast = uriFirst + strlen(uriFirst);
- UriUriA uri;
+void testMakeOwnerCopiesHostText(const char * const uriFirst) { // issue #121
+ const char * const uriAfterLast = uriFirst + strlen(uriFirst);
+ UriUriA uri;
- EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS);
- EXPECT_EQ(uri.owner, URI_FALSE);
- URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast);
+ EXPECT_EQ(uriParseSingleUriA(&uri, uriFirst, NULL), URI_SUCCESS);
+ EXPECT_EQ(uri.owner, URI_FALSE);
+ URI_EXPECT_RANGE_BETWEEN(uri.hostText, uriFirst, uriAfterLast);
- EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
+ EXPECT_EQ(uriMakeOwnerA(&uri), URI_SUCCESS);
- EXPECT_EQ(uri.owner, URI_TRUE);
- URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
+ EXPECT_EQ(uri.owner, URI_TRUE);
+ URI_EXPECT_RANGE_OUTSIDE(uri.hostText, uriFirst, uriAfterLast);
- uriFreeUriMembersA(&uri);
- uriFreeUriMembersA(&uri); // tried freeing stack pointers before the fix
- }
-} // namespace
+ uriFreeUriMembersA(&uri);
+ uriFreeUriMembersA(&uri); // tried freeing stack pointers before the fix
+}
+} // namespace
TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextIp4) { // issue #121
- testMakeOwnerCopiesHostText("//192.0.2.0"); // RFC 5737
+ testMakeOwnerCopiesHostText("//192.0.2.0"); // RFC 5737
}
TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextIp6) { // issue #121
- testMakeOwnerCopiesHostText("//[2001:db8::]"); // RFC 3849
+ testMakeOwnerCopiesHostText("//[2001:db8::]"); // RFC 3849
}
TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextRegname) { // issue #121
- testMakeOwnerCopiesHostText("//host123.test"); // RFC 6761
+ testMakeOwnerCopiesHostText("//host123.test"); // RFC 6761
}
TEST(MakeOwnerSuite, MakeOwnerCopiesHostTextFuture) { // issue #121
- testMakeOwnerCopiesHostText("//[v7.X]"); // arbitrary IPvFuture
+ testMakeOwnerCopiesHostText("//[v7.X]"); // arbitrary IPvFuture
}
TEST(ParseIpFourAddressSuite, FourSaneOctets) {
- unsigned char octetOutput[4];
- const char * const ipAddressText = "111.22.3.40";
- const int res = uriParseIpFourAddressA(octetOutput, ipAddressText,
- ipAddressText + strlen(ipAddressText));
- EXPECT_EQ(res, URI_SUCCESS);
- EXPECT_EQ(octetOutput[0], 111);
- EXPECT_EQ(octetOutput[1], 22);
- EXPECT_EQ(octetOutput[2], 3);
- EXPECT_EQ(octetOutput[3], 40);
+ unsigned char octetOutput[4];
+ const char * const ipAddressText = "111.22.3.40";
+ const int res = uriParseIpFourAddressA(octetOutput, ipAddressText,
+ ipAddressText + strlen(ipAddressText));
+ EXPECT_EQ(res, URI_SUCCESS);
+ EXPECT_EQ(octetOutput[0], 111);
+ EXPECT_EQ(octetOutput[1], 22);
+ EXPECT_EQ(octetOutput[2], 3);
+ EXPECT_EQ(octetOutput[3], 40);
}
+TEST(UriSuite, NoStackOverflowIssue282) {
+ const size_t sizeBytes = 2 * 1024 * 1024;
+
+ char * const uriString = new char[sizeBytes];
+ ASSERT_TRUE(uriString != NULL);
+ ::memset(uriString, 'x', sizeBytes - 1);
+ uriString[sizeBytes - 1] = '\0';
+
+ UriUriA uri;
+ ASSERT_EQ(uriParseSingleUriA(&uri, uriString, NULL), URI_SUCCESS);
+
+ uriFreeUriMembersA(&uri);
+ delete[] uriString;
+}
int main(int argc, char ** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tool/COPYING b/tool/COPYING
new file mode 100644
index 0000000..261c741
--- /dev/null
+++ b/tool/COPYING
@@ -0,0 +1,36 @@
+uriparser - RFC 3986 URI parsing library
+
+Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
+Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tool/uriparse.c b/tool/uriparse.c
index edd9e04..4897200 100644
--- a/tool/uriparse.c
+++ b/tool/uriparse.c
@@ -41,102 +41,98 @@
#include <uriparser/Uri.h>
#ifdef _WIN32
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# if defined(__MINGW32__) && \
- (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3 || \
- _WIN32_WINNT < _WIN32_WINNT_VISTA)
-WINSOCK_API_LINKAGE const char * WSAAPI inet_ntop(
- int af, const void *src, char *dst, size_t size);
-# endif
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# if defined(__MINGW32__) \
+ && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3 \
+ || _WIN32_WINNT < _WIN32_WINNT_VISTA)
+WINSOCK_API_LINKAGE const char * WSAAPI inet_ntop(int af, const void * src, char * dst,
+ size_t size);
+# endif
#else
-# include <sys/socket.h>
-# include <arpa/inet.h>
-# include <netinet/in.h>
+# include <sys/socket.h>
+# include <arpa/inet.h>
+# include <netinet/in.h>
#endif
-
-#define RANGE(x) (int)((x).afterLast-(x).first), ((x).first)
-
+#define RANGE(x) (int)((x).afterLast - (x).first), ((x).first)
void usage(void) {
- printf("Usage: uriparse URI [..]\n");
+ printf("Usage: uriparse URI [..]\n");
}
+int main(int argc, char * argv[]) {
+ int retval = EXIT_SUCCESS;
+ int i = 1;
-int main(int argc, char *argv[]) {
- int retval = EXIT_SUCCESS;
- int i = 1;
-
- if (argc < 2) {
- usage();
- exit(1);
- }
+ if (argc < 2) {
+ usage();
+ exit(1);
+ }
- for (; i < argc; i++) {
- UriParserStateA state;
- UriUriA uri;
- char ipstr[INET6_ADDRSTRLEN];
+ for (; i < argc; i++) {
+ UriParserStateA state;
+ UriUriA uri;
+ char ipstr[INET6_ADDRSTRLEN];
- state.uri = &uri;
- printf("uri: %s\n", argv[i]);
- if (uriParseUriA(&state, argv[i]) != URI_SUCCESS) {
- /* Failure */
- printf("Failure: %s @ '%.18s' (#%lu)\n",
- (state.errorCode == URI_ERROR_SYNTAX)
- ? "syntax"
- : (state.errorCode == URI_ERROR_MALLOC)
- ? "not enough memory"
- : "liburiparser bug (please report)",
- state.errorPos,
- (long unsigned int)(state.errorPos - argv[i]));
- retval = EXIT_FAILURE;
- } else {
- if (uri.scheme.first) {
- printf("scheme: %.*s\n", RANGE(uri.scheme));
- }
- if (uri.userInfo.first) {
- printf("userInfo: %.*s\n", RANGE(uri.userInfo));
- }
- if (uri.hostText.first) {
- printf("hostText: %.*s\n", RANGE(uri.hostText));
- }
- if (uri.hostData.ip4) {
- inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof ipstr);
- printf("hostData.ip4: %s\n", ipstr);
- }
- if (uri.hostData.ip6) {
- inet_ntop(AF_INET6, uri.hostData.ip6->data, ipstr, sizeof ipstr);
- printf("hostData.ip6: %s\n", ipstr);
- }
- if (uri.portText.first) {
- printf("portText: %.*s\n", RANGE(uri.portText));
- }
- if (uri.pathHead) {
- const UriPathSegmentA * p = uri.pathHead;
- for (; p; p = p->next) {
- printf(" .. pathSeg: %.*s\n", RANGE(p->text));
- }
- }
- if (uri.query.first) {
- printf("query: %.*s\n", RANGE(uri.query));
- }
- if (uri.fragment.first) {
- printf("fragment: %.*s\n", RANGE(uri.fragment));
- }
- {
- const char * const absolutePathLabel = "absolutePath: ";
- printf("%s%s\n", absolutePathLabel,
- (uri.absolutePath == URI_TRUE) ? "true" : "false");
- if (uri.hostText.first != NULL) {
- printf("%*s%s\n", (int)strlen(absolutePathLabel), "",
- "(always false for URIs with host)");
- }
- }
- }
- printf("\n");
+ state.uri = &uri;
+ printf("uri: %s\n", argv[i]);
+ if (uriParseUriA(&state, argv[i]) != URI_SUCCESS) {
+ /* Failure */
+ printf("Failure: %s @ '%.18s' (#%lu)\n",
+ (state.errorCode == URI_ERROR_SYNTAX) ? "syntax"
+ : (state.errorCode == URI_ERROR_MALLOC)
+ ? "not enough memory"
+ : "liburiparser bug (please report)",
+ state.errorPos, (long unsigned int)(state.errorPos - argv[i]));
+ retval = EXIT_FAILURE;
+ } else {
+ if (uri.scheme.first) {
+ printf("scheme: %.*s\n", RANGE(uri.scheme));
+ }
+ if (uri.userInfo.first) {
+ printf("userInfo: %.*s\n", RANGE(uri.userInfo));
+ }
+ if (uri.hostText.first) {
+ printf("hostText: %.*s\n", RANGE(uri.hostText));
+ }
+ if (uri.hostData.ip4) {
+ inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof ipstr);
+ printf("hostData.ip4: %s\n", ipstr);
+ }
+ if (uri.hostData.ip6) {
+ inet_ntop(AF_INET6, uri.hostData.ip6->data, ipstr, sizeof ipstr);
+ printf("hostData.ip6: %s\n", ipstr);
+ }
+ if (uri.hostData.ipFuture.first) {
+ printf("hostData.ipFuture: %.*s\n", RANGE(uri.hostData.ipFuture));
+ }
+ if (uri.portText.first) {
+ printf("portText: %.*s\n", RANGE(uri.portText));
+ }
+ if (uri.pathHead) {
+ const UriPathSegmentA * p = uri.pathHead;
+ for (; p; p = p->next) {
+ printf(" .. pathSeg: %.*s\n", RANGE(p->text));
+ }
+ }
+ if (uri.query.first) {
+ printf("query: %.*s\n", RANGE(uri.query));
+ }
+ if (uri.fragment.first) {
+ printf("fragment: %.*s\n", RANGE(uri.fragment));
+ }
+ const char * const absolutePathLabel = "absolutePath: ";
+ printf("%s%s\n", absolutePathLabel,
+ (uri.absolutePath == URI_TRUE) ? "true" : "false");
+ if (uri.hostText.first != NULL) {
+ printf("%*s%s\n", (int)strlen(absolutePathLabel), "",
+ "(always false for URIs with host)");
+ }
+ }
+ printf("\n");
- uriFreeUriMembersA(&uri);
- }
- return retval;
+ uriFreeUriMembersA(&uri);
+ }
+ return retval;
}