Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -37,11 +37,10 @@ tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/objc_sync/objc_sync tests/plugin/Info.plist -tests/serialization_xml.m tests/terminal/terminal_tests tests/testfile_bin.m tests/testfile_ini.m tests/tests tests/tests.3dsx Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -42,11 +42,10 @@ tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync tests/plugin/Info.plist -tests/serialization_xml.m tests/terminal/terminal_tests tests/testfile_bin.m tests/testfile_ini.m tests/tests tests/tests.3dsx ADDED .github/workflows/dragonflybsd.yml Index: .github/workflows/dragonflybsd.yml ================================================================== --- .github/workflows/dragonflybsd.yml +++ .github/workflows/dragonflybsd.yml @@ -0,0 +1,25 @@ +name: dragonflybsd +on: [push, pull_request] +jobs: + tests: + runs-on: macos-12 + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v3 + - uses: vmactions/dragonflybsd-vm@v0 + with: + usesh: true + copyback: false + prepare: | + pkg install -y autoconf automake gnutls llvm pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/freebsd.yml Index: .github/workflows/freebsd.yml ================================================================== --- .github/workflows/freebsd.yml +++ .github/workflows/freebsd.yml @@ -0,0 +1,25 @@ +name: freebsd +on: [push, pull_request] +jobs: + tests: + runs-on: macos-12 + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v3 + - uses: vmactions/freebsd-vm@v0 + with: + usesh: true + copyback: false + prepare: | + pkg install -y autoconf automake gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/netbsd-gcc.yml Index: .github/workflows/netbsd-gcc.yml ================================================================== --- .github/workflows/netbsd-gcc.yml +++ .github/workflows/netbsd-gcc.yml @@ -0,0 +1,25 @@ +name: netbsd-gcc +on: [push, pull_request] +jobs: + tests: + runs-on: macos-12 + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v3 + - uses: vmactions/netbsd-vm@v0 + with: + usesh: true + copyback: false + prepare: | + pkg_add autoconf automake gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=gcc ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/netbsd.yml Index: .github/workflows/netbsd.yml ================================================================== --- .github/workflows/netbsd.yml +++ .github/workflows/netbsd.yml @@ -0,0 +1,25 @@ +name: netbsd +on: [push, pull_request] +jobs: + tests: + runs-on: macos-12 + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v3 + - uses: vmactions/netbsd-vm@v0 + with: + usesh: true + copyback: false + prepare: | + pkg_add autoconf automake clang gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/openbsd.yml Index: .github/workflows/openbsd.yml ================================================================== --- .github/workflows/openbsd.yml +++ .github/workflows/openbsd.yml @@ -0,0 +1,25 @@ +name: openbsd +on: [push, pull_request] +jobs: + tests: + runs-on: macos-12 + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v3 + - uses: vmactions/openbsd-vm@v0 + with: + usesh: true + copyback: false + prepare: | + pkg_add autoconf-2.71 automake-1.16.5 gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -42,11 +42,10 @@ tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync tests/plugin/Info.plist -tests/serialization_xml.m tests/terminal/terminal_tests tests/testfile_bin.m tests/testfile_ini.m tests/tests tests/tests.3dsx Index: Doxyfile ================================================================== --- Doxyfile +++ Doxyfile @@ -6,37 +6,45 @@ HAVE_DOT = NO GENERATE_LATEX = NO HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_MEMBERS = YES TYPEDEF_HIDES_STRUCT = YES -PREDEFINED = __OBJC__ \ - _Nonnull= \ - _Nullable= \ - DOXYGEN \ - OF_BOXABLE= \ - OF_CONSUMED= \ - OF_DESIGNATED_INITIALIZER= \ - OF_GENERIC(...)= \ - OF_HAVE_BLOCKS \ - OF_HAVE_FILES \ - OF_HAVE_SANDBOX \ - OF_HAVE_SOCKETS \ - OF_HAVE_THREADS \ - OF_KINDOF(...)= \ - OF_NO_RETURN= \ - OF_NO_RETURN_FUNC= \ - OF_NULLABLE_PROPERTY(...)= \ - OF_NULL_RESETTABLE_PROPERTY(...)= \ - OF_REQUIRES_SUPER= \ - OF_RETURNS_INNER_POINTER= \ - OF_RETURNS_NOT_RETAINED= \ - OF_RETURNS_RETAINED= \ - OF_ROOT_CLASS= \ - OF_SENTINEL= \ - OF_WARN_UNUSED_RESULT= \ - OF_WEAK_UNAVAILABLE= \ - SIGHUP \ - SIGUSR1 \ +PREDEFINED = __OBJC__ \ + _Nonnull= \ + _Nullable= \ + DOXYGEN \ + OF_BOXABLE= \ + OF_CONSUMED= \ + OF_DESIGNATED_INITIALIZER= \ + OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES \ + OF_FILE_MANAGER_SUPPORTS_LINKS \ + OF_FILE_MANAGER_SUPPORTS_OWNER \ + OF_FILE_MANAGER_SUPPORTS_PERMISSIONS \ + OF_FILE_MANAGER_SUPPORTS_SYMLINKS \ + OF_GENERIC(...)= \ + OF_HAVE_APPLETALK \ + OF_HAVE_BLOCKS \ + OF_HAVE_FILES \ + OF_HAVE_IPV6 \ + OF_HAVE_IPX \ + OF_HAVE_SANDBOX \ + OF_HAVE_SOCKETS \ + OF_HAVE_THREADS \ + OF_KINDOF(...)= \ + OF_NO_RETURN= \ + OF_NO_RETURN_FUNC= \ + OF_NULLABLE_PROPERTY(...)= \ + OF_NULL_RESETTABLE_PROPERTY(...)= \ + OF_REQUIRES_SUPER= \ + OF_RETURNS_INNER_POINTER= \ + OF_RETURNS_NOT_RETAINED= \ + OF_RETURNS_RETAINED= \ + OF_ROOT_CLASS= \ + OF_SENTINEL= \ + OF_WARN_UNUSED_RESULT= \ + OF_WEAK_UNAVAILABLE= \ + SIGHUP \ + SIGUSR1 \ SIGUSR2 MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES IGNORE_PREFIX = OF of_ Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -10,11 +10,11 @@ config.status \ extra.mk include buildsys.mk -.PHONY: docs release +.PHONY: check docs release utils tests: src check: tests cd tests && ${MAKE} -s run Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -43,23 +43,34 @@ DragonFlyBSD ------------ * OS Versions: 3.0, 3.3-DEVELOPMENT - * Architectures: x86, x86_64 + * Architectures: AMD64, x86 * Compilers: GCC 4.4.7 * Runtimes: ObjFW FreeBSD ------- * OS Versions: 9.1-rc3, 10.0 - * Architectures: x86_64 + * Architectures: AMD64 * Compilers: Clang 3.1, Clang 3.3 * Runtimes: ObjFW + +GNU/Hurd +-------- + + * OS Versions: 0.9 + * Architectures: i686 + * Compilers: Clang 14.0.6 + * Runtimes: ObjFW + * Limitations: No support for UNIX sockets (`AF_UNIX` with `SOCK_DGRAM` is + currently broken in Hurd) + Haiku ----- * OS version: r1-alpha4 @@ -88,22 +99,22 @@ Linux ----- - * Architectures: Alpha, ARMv6, ARMv7, ARM64, Itanium, m68k, MIPS (O32), - MIPS64 (N64), RISC-V 64, PowerPC, S390x, SuperH-4, x86, - x86_64 + * Architectures: Alpha, AMD64, ARMv6, ARMv7, ARM64, Itanium, m68k, MIPS (O32), + MIPS64 (N64), RISC-V 64, PowerPC, S390x, SuperH-4, x86 * Compilers: Clang 3.0-10.0, GCC 4.6-10.0 + * C libraries: glibc, musl * Runtimes: ObjFW macOS ----- * OS Versions: 10.5, 10.7-10.15, Darling - * Architectures: PowerPC, PowerPC64, x86, x86_64 + * Architectures: AMD64, PowerPC, PowerPC64, x86 * Compilers: Clang 3.1-10.0, Apple GCC 4.0.1 & 4.2.1 * Runtimes: Apple, ObjFW MiNT @@ -127,12 +138,12 @@ NetBSD ------ * OS Versions: 5.1-9.0 - * Architectures: ARM, ARM (big endian, BE8 mode), MIPS (O32), PowerPC, SPARC, - SPARC64, x86, x86_64 + * Architectures: AMD64, ARM, ARM (big endian, BE8 mode), MIPS (O32), PowerPC, + SPARC, SPARC64, x86 * Compilers: Clang 3.0-3.2, GCC 4.1.3 & 4.5.3 & 7.4.0 * Runtimes: ObjFW Nintendo 3DS @@ -167,11 +178,11 @@ OpenBSD ------- * OS Versions: 5.2-6.7 - * Architectures: MIPS64, PA-RISC, PowerPC, SPARC64, x86_64 + * Architectures: AMD64, MIPS64, PA-RISC, PowerPC, SPARC64 * Compilers: GCC 6.3.0, Clang 4.0 * Runtimes: ObjFW PlayStation Portable @@ -194,13 +205,13 @@ Solaris ------- - * OS Versions: OpenIndiana 2015.03 - * Architectures: x86, x86_64 - * Compilers: Clang 3.4.2, GCC 4.8.3 + * OS Versions: OpenIndiana 2015.03, OpenIndiana 2023.04, Oracle Solaris 11.4 + * Architectures: AMD64, x86 + * Compilers: Clang 3.4.2, Clang 11.0.0, Clang 13.0.1, GCC 4.8.3, GCC 10.4.0 * Runtimes: ObjFW Wii --- @@ -226,14 +237,14 @@ Windows ------- * OS Versions: 98 SE, NT 4.0, XP (x86), 7 (x64), 8 (x64), 8.1 (x64), 10, 11, Wine (x86 & x64) - * Architectures: x86, x86_64, AArch64 - * Compilers: GCC 5.3.0 & 6.2.0 from msys2 (x86 & x64), + * Architectures: AArch64, AMD64, x86 + * Compilers: GCC 5.3.0 & 6.2.0 from msys2 (AMD64 & x86), Clang 3.9.0 from msys2 (x86), - Clang 10.0 from msys2 (x86 & x86_64), + Clang 10.0 from msys2 (AMD64 & x86), Clang 14.0.4 from msys2 (AArch64) * Runtimes: ObjFW Others @@ -254,16 +265,16 @@ As forwarding needs hand-written assembly for each combination of CPU architecture, executable format and calling convention, it is only available for the following platforms (except resolveClassMethod: and resolveInstanceMethod:, which are always available): + * AMD64 (SysV/ELF, Apple/Mach-O, Mach-O, Win64/PE) * ARM (EABI/ELF, Apple/Mach-O) * ARM64 (ARM64/ELF, Apple/Mach-O) * MIPS (O32/ELF, EABI/ELF) * PowerPC (SysV/ELF, EABI/ELF, Apple/Mach-O) * SPARC (SysV/ELF) * SPARC64 (SysV/ELF) * x86 (SysV/ELF, Apple/Mach-O, Win32/PE) - * x86_64 (SysV/ELF, Apple/Mach-O, Mach-O, Win64/PE) Apple/Mach-O means both, the Apple ABI and runtime, while Mach-O means the ObjFW runtime on Mach-O. Index: README.md ================================================================== --- README.md +++ README.md @@ -167,24 +167,23 @@ regular instructions above. To build for iOS, follow the regular instructions, but instead of `./configure` do something like this: - $ clang="clang -isysroot $(xcrun --sdk iphoneos --show-sdk-path)" - $ export OBJC="$clang -arch armv7 -arch arm64" - $ export OBJCPP="$clang -arch armv7 -E" - $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" + $ clang="xcrun --sdk iphoneos clang" + $ export OBJC="$clang -arch arm64e -arch arm64" + $ export OBJCPP="$clang -arch arm64e -E" + $ export IPHONEOS_DEPLOYMENT_TARGET="10.0" $ ./configure --prefix=/usr/local/ios --host=arm64-apple-darwin To build for the iOS simulator, follow the regular instructions, but instead of `./configure` use something like this: - $ clang="clang -isysroot $(xcrun --sdk iphonesimulator --show-sdk-path)" - $ export OBJC="$clang -arch arm64 -arch x86_64" - $ export OBJCPP="$clang -arch arm64 -E" - $ export IPHONEOS_DEPLOYMENT_TARGET="9.0" - $ ./configure --prefix=/usr/local/iossim --host=arm64-apple-darwin + $ clang="xcrun --sdk iphonesimulator clang" + $ export OBJC="$clang -arch $(uname -m)" + $ export IPHONEOS_DEPLOYMENT_TARGET="10.0" + $ ./configure --prefix=/usr/local/iossim --host=$(uname -m)-apple-darwin

Using the macOS or iOS framework in Xcode

To use the macOS framework in Xcode, you need to add the `.framework`s to your project and add the following flags to `Other C Flags`: Index: autogen.sh ================================================================== --- autogen.sh +++ autogen.sh @@ -1,11 +1,13 @@ #!/bin/sh set -e # Set a version for OpenBSD -: ${AUTOCONF_VERSION:=2.69} -: ${AUTOMAKE_VERSION:=1.16} -export AUTOCONF_VERSION AUTOMAKE_VERSION +if test x"$(uname -s)" = x"OpenBSD"; then + : ${AUTOCONF_VERSION:=2.71} + : ${AUTOMAKE_VERSION:=1.16} + export AUTOCONF_VERSION AUTOMAKE_VERSION +fi aclocal -I build-aux/m4 autoconf autoheader Index: build-aux/m4/buildsys.m4 ================================================================== --- build-aux/m4/buildsys.m4 +++ build-aux/m4/buildsys.m4 @@ -1,8 +1,8 @@ dnl dnl Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017, -dnl 2018, 2020, 2021, 2022 +dnl 2018, 2020, 2021, 2022, 2023 dnl Jonathan Schleifer dnl dnl https://fossil.nil.im/buildsys dnl dnl Permission to use, copy, modify, and/or distribute this software for any @@ -146,10 +146,11 @@ host_is_ios="yes" ], [ host_is_ios="no" ]) AC_MSG_RESULT($host_is_ios) + AC_CHECK_TOOL(CODESIGN, codesign) ;; esac ]) AC_DEFUN([BUILDSYS_PROG_IMPLIB], [ @@ -173,11 +174,11 @@ ]) AC_DEFUN([BUILDSYS_SHARED_LIB], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([BUILDSYS_CHECK_IOS]) - AC_MSG_CHECKING(for shared library system) + AC_MSG_CHECKING(for shared library type) case "$host" in *-*-darwin*) AC_MSG_RESULT(Darwin) LIB_CFLAGS='-fPIC -DPIC' @@ -186,22 +187,12 @@ LIB_PREFIX='lib' LIB_SUFFIX='.dylib' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,-rpath,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-bundle ${PLUGIN_LDFLAGS_BUNDLE_LOADER}' - PLUGIN_SUFFIX='.bundle' - AS_IF([test x"$host_is_ios" = x"yes"], [ - LINK_PLUGIN='rm -fr $$out && ${MKDIR_P} $$out && if test -f Info.plist; then ${INSTALL} -m 644 Info.plist $$out/Info.plist; fi && ${LD} -o $$out/$${out%${PLUGIN_SUFFIX}} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS} && ${CODESIGN} -fs ${CODESIGN_IDENTITY} --timestamp=none $$out' - ], [ - LINK_PLUGIN='rm -fr $$out && ${MKDIR_P} $$out/Contents/MacOS && if test -f Info.plist; then ${INSTALL} -m 644 Info.plist $$out/Contents/Info.plist; fi && ${LD} -o $$out/Contents/MacOS/$${out%${PLUGIN_SUFFIX}} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS} && ${CODESIGN} -fs ${CODESIGN_IDENTITY} --timestamp=none $$out' - ]) INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib && ${LN_S} -f $${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.dylib ${DESTDIR}${libdir}/$${i%.dylib}.${LIB_MAJOR}.${LIB_MINOR}.dylib' - INSTALL_PLUGIN='&& rm -fr ${DESTDIR}${plugindir}/$$i && cp -R $$i ${DESTDIR}${plugindir}/' - UNINSTALL_PLUGIN='&& rm -fr ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; *-*-mingw* | *-*-cygwin*) AC_MSG_RESULT(MinGW / Cygwin) LIB_CFLAGS='' @@ -208,18 +199,12 @@ LIB_LDFLAGS='-shared -Wl,--export-all-symbols' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='' LIB_SUFFIX='${LIB_MAJOR}.dll' LINK_LIB='&& rm -f lib$${out%${LIB_SUFFIX}}.dll.a && ${LN_S} $$out lib$${out%${LIB_SUFFIX}}.dll.a' - PLUGIN_CFLAGS='' - PLUGIN_LDFLAGS='-shared -Wl,--export-all-symbols' - PLUGIN_SUFFIX='.dll' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${MKDIR_P} ${DESTDIR}${bindir} && ${INSTALL} -m 755 $$i ${DESTDIR}${bindir}/$$i && ${INSTALL} -m 755 lib$${i%${LIB_SUFFIX}}.dll.a ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a' UNINSTALL_LIB='&& rm -f ${DESTDIR}${bindir}/$$i ${DESTDIR}${libdir}/lib$${i%${LIB_SUFFIX}}.dll.a' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='${SHARED_LIB}.a ${SHARED_LIB_NOINST}.a' ;; *-*-openbsd* | *-*-mirbsd*) AC_MSG_RESULT(OpenBSD) LIB_CFLAGS='-fPIC -DPIC' @@ -228,18 +213,12 @@ LIB_PREFIX='lib' LIB_SUFFIX='.so.${LIB_MAJOR}.${LIB_MINOR}' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,-rpath,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.so' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; *-*-solaris*) AC_MSG_RESULT(Solaris) LIB_CFLAGS='-fPIC -DPIC' @@ -248,35 +227,23 @@ LIB_PREFIX='lib' LIB_SUFFIX='.so' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,-rpath,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.so' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR} && rm -f ${DESTDIR}${libdir}/$$i && ${LN_S} $$i.${LIB_MAJOR}.${LIB_MINOR} ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; *-*-android*) AC_MSG_RESULT(Android) LIB_CFLAGS='-fPIC -DPIC' LIB_LDFLAGS='-shared -Wl,-soname=$$out.${LIB_MAJOR}' LIB_LDFLAGS_INSTALL_NAME='' LIB_PREFIX='lib' LIB_SUFFIX='.so' - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.so' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0 && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; hppa*-*-hpux*) AC_MSG_RESULT([HP-UX (PA-RISC)]) LIB_CFLAGS='-fPIC -DPIC' @@ -286,18 +253,12 @@ LIB_SUFFIX='.${LIB_MAJOR}' LINK_LIB='&& rm -f $${out%%.*}.sl && ${LN_S} $$out $${out%%.*}.sl' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,+b,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.sl' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.sl' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%%.*}.sl' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; ia64*-*-hpux*) AC_MSG_RESULT([HP-UX (Itanium)]) LIB_CFLAGS='-fPIC -DPIC' @@ -307,18 +268,12 @@ LIB_SUFFIX='.${LIB_MAJOR}' LINK_LIB='&& rm -f $${out%%.*}.so && ${LN_S} $$out $${out%%.*}.so' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,+b,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.so' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i && ${LN_S} -f $$i ${DESTDIR}${libdir}/$${i%%.*}.so' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$${i%%.*}.so' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; *) AC_MSG_RESULT(ELF) LIB_CFLAGS='-fPIC -DPIC' @@ -327,18 +282,12 @@ LIB_PREFIX='lib' LIB_SUFFIX='.so' AS_IF([test x"$enable_rpath" != x"no"], [ LDFLAGS_RPATH='-Wl,-rpath,${libdir}' ]) - PLUGIN_CFLAGS='-fPIC -DPIC' - PLUGIN_LDFLAGS='-shared' - PLUGIN_SUFFIX='.so' - LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' INSTALL_LIB='&& ${INSTALL} -m 755 $$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0 && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} && ${LN_S} -f $$i.${LIB_MAJOR}.${LIB_MINOR}.0 ${DESTDIR}${libdir}/$$i' UNINSTALL_LIB='&& rm -f ${DESTDIR}${libdir}/$$i ${DESTDIR}${libdir}/$$i.${LIB_MAJOR} ${DESTDIR}${libdir}/$$i.${LIB_MAJOR}.${LIB_MINOR}.0' - INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' - UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' CLEAN_LIB='' ;; esac AC_SUBST(LIB_CFLAGS) @@ -346,28 +295,20 @@ AC_SUBST(LIB_LDFLAGS_INSTALL_NAME) AC_SUBST(LIB_PREFIX) AC_SUBST(LIB_SUFFIX) AC_SUBST(LINK_LIB) AC_SUBST(LDFLAGS_RPATH) - AC_SUBST(PLUGIN_CFLAGS) - AC_SUBST(PLUGIN_LDFLAGS) - AC_SUBST(PLUGIN_SUFFIX) - AC_SUBST(LINK_PLUGIN) AC_SUBST(INSTALL_LIB) AC_SUBST(UNINSTALL_LIB) - AC_SUBST(INSTALL_PLUGIN) - AC_SUBST(UNINSTALL_PLUGIN) AC_SUBST(CLEAN_LIB) ]) AC_DEFUN([BUILDSYS_FRAMEWORK], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([BUILDSYS_CHECK_IOS]) AC_REQUIRE([BUILDSYS_SHARED_LIB]) - AC_CHECK_TOOL(CODESIGN, codesign) - case "$host_os" in darwin*) AS_IF([test x"$host_is_ios" = x"yes"], [ FRAMEWORK_LDFLAGS='-dynamiclib -current_version ${LIB_MAJOR}.${LIB_MINOR} -compatibility_version ${LIB_MAJOR}' FRAMEWORK_LDFLAGS_INSTALL_NAME='-Wl,-install_name,@executable_path/Frameworks/$$out/$${out%.framework}' @@ -382,5 +323,61 @@ $1 ;; esac ]) + +AC_DEFUN([BUILDSYS_PLUGIN], [ + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([BUILDSYS_CHECK_IOS]) + AC_MSG_CHECKING(for plugin type) + + case "$host" in + *-*-darwin*) + AC_MSG_RESULT(Darwin) + PLUGIN_CFLAGS='-fPIC -DPIC' + PLUGIN_LDFLAGS='-bundle ${PLUGIN_LDFLAGS_BUNDLE_LOADER}' + PLUGIN_SUFFIX='.bundle' + AS_IF([test x"$host_is_ios" = x"yes"], [ + LINK_PLUGIN='rm -fr $$out && ${MKDIR_P} $$out && if test -f Info.plist; then ${INSTALL} -m 644 Info.plist $$out/Info.plist; fi && ${LD} -o $$out/$${out%${PLUGIN_SUFFIX}} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS} && ${CODESIGN} -fs ${CODESIGN_IDENTITY} --timestamp=none $$out' + ], [ + LINK_PLUGIN='rm -fr $$out && ${MKDIR_P} $$out/Contents/MacOS && if test -f Info.plist; then ${INSTALL} -m 644 Info.plist $$out/Contents/Info.plist; fi && ${LD} -o $$out/Contents/MacOS/$${out%${PLUGIN_SUFFIX}} ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS} && ${CODESIGN} -fs ${CODESIGN_IDENTITY} --timestamp=none $$out' + ]) + INSTALL_PLUGIN='&& rm -fr ${DESTDIR}${plugindir}/$$i && cp -R $$i ${DESTDIR}${plugindir}/' + UNINSTALL_PLUGIN='&& rm -fr ${DESTDIR}${plugindir}/$$i' + ;; + *-*-mingw* | *-*-cygwin*) + AC_MSG_RESULT(MinGW / Cygwin) + PLUGIN_CFLAGS='' + PLUGIN_LDFLAGS='-shared -Wl,--export-all-symbols' + PLUGIN_SUFFIX='.dll' + LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' + INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' + UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' + ;; + hppa*-*-hpux*) + AC_MSG_RESULT([HP-UX (PA-RISC)]) + PLUGIN_CFLAGS='-fPIC -DPIC' + PLUGIN_LDFLAGS='-shared' + PLUGIN_SUFFIX='.sl' + LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' + INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' + UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' + ;; + *) + AC_MSG_RESULT(ELF) + PLUGIN_CFLAGS='-fPIC -DPIC' + PLUGIN_LDFLAGS='-shared' + PLUGIN_SUFFIX='.so' + LINK_PLUGIN='${LD} -o $$out ${PLUGIN_OBJS} ${PLUGIN_OBJS_EXTRA} ${PLUGIN_LDFLAGS} ${LDFLAGS} ${LIBS}' + INSTALL_PLUGIN='&& ${INSTALL} -m 755 $$i ${DESTDIR}${plugindir}/$$i' + UNINSTALL_PLUGIN='&& rm -f ${DESTDIR}${plugindir}/$$i' + ;; + esac + + AC_SUBST(PLUGIN_CFLAGS) + AC_SUBST(PLUGIN_LDFLAGS) + AC_SUBST(PLUGIN_SUFFIX) + AC_SUBST(LINK_PLUGIN) + AC_SUBST(INSTALL_PLUGIN) + AC_SUBST(UNINSTALL_PLUGIN) +]) Index: buildsys.mk.in ================================================================== --- buildsys.mk.in +++ buildsys.mk.in @@ -761,11 +761,11 @@ fi \ done install-extra: -uninstall: uninstall-extra +uninstall: for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \ test x"$$i" = x"" && continue; \ ${DIR_ENTER}; \ ${MAKE} -s uninstall || exit $$?; \ ${DIR_LEAVE}; \ @@ -873,10 +873,12 @@ else \ ${DELETE_FAILED}; \ fi \ fi \ done + + ${MAKE} -s uninstall-extra uninstall-extra: clean: for i in "" ${SUBDIRS} ${SUBDIRS_AFTER}; do \ Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -1,6 +1,6 @@ -AC_INIT(ObjFW, 1.1dev, js@nil.im) +AC_INIT(ObjFW, 1.1dev, js@nil.im, objfw, https://objfw.nil.im/) AC_CONFIG_SRCDIR(src) AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_MACRO_DIR(build-aux/m4) AC_DEFINE(OBJFW_VERSION_MAJOR, 1, [The major version of ObjFW]) @@ -101,11 +101,11 @@ enable_shared="no" enable_threads="no" enable_sockets="no" ;; *-*-mingw*) - LDFLAGS="$LDFLAGS -Wl,--allow-multiple-definition -static-libgcc" + LDFLAGS="$LDFLAGS -Wl,--allow-multiple-definition" LIBS="$LIBS -lversion" AC_SUBST(USE_SRCS_WINDOWS, '${SRCS_WINDOWS}') ;; *-psp-*) @@ -146,10 +146,18 @@ *-*-mint*) enable_shared="no" enable_threads="no" # TODO with_tls="no" ;; +*-apple-macos*) + enable_shared="no" + enable_threads="no" # TODO + enable_sockets="no" # TODO + + AC_DEFINE(OF_CLASSIC_MACOS, 1, + [Whether we are compiling for classic macOS]) + ;; esac AS_IF([test x"$host_os" = x"msdosdjgpp" -a x"$build_os" = x"msdosdjgpp"], [ dnl Hack to make configure find these on DOS. : ${AR:=ar.exe} @@ -169,11 +177,10 @@ ;; esac AC_PROG_OBJC($potential_compilers) AC_PROG_OBJCPP AC_PROG_LN_S -AC_PROG_EGREP BUILDSYS_CHECK_IOS AC_ARG_WITH(wii, AS_HELP_STRING([--with-wii], [build for Wii])) @@ -418,11 +425,13 @@ AC_ARG_ENABLE(shared, AS_HELP_STRING([--disable-shared], [do not build shared library])) AS_IF([test x"$enable_shared" != x"no"], [ BUILDSYS_SHARED_LIB - AC_SUBST(OBJFW_SHARED_LIB, "${LIB_PREFIX}objfw${LIB_SUFFIX}") + BUILDSYS_PLUGIN + + AC_SUBST(OBJFW_SHARED_LIB, '${LIB_PREFIX}objfw${LIB_SUFFIX}') AC_SUBST(EXCEPTIONS_LIB_A, "exceptions.lib.a") AC_SUBST(FORWARDING_LIB_A, "forwarding.lib.a") AC_SUBST(LOOKUP_ASM_LIB_A, "lookup-asm.lib.a") BUILDSYS_FRAMEWORK([ @@ -594,11 +603,11 @@ AC_SUBST(RUNTIME, "runtime") AC_CONFIG_FILES(src/runtime/Info.plist) AS_IF([test x"$enable_shared" != x"no"], [ AC_SUBST(OBJFWRT_SHARED_LIB, - "${LIB_PREFIX}objfwrt${LIB_SUFFIX}") + '${LIB_PREFIX}objfwrt${LIB_SUFFIX}') ]) AS_IF([test x"$enable_static" = x"yes"], [ AC_SUBST(OBJFWRT_STATIC_LIB, "libobjfwrt.a") ]) @@ -1056,11 +1065,29 @@ AC_DEFINE(OF_HAVE_SCHED_YIELD, 1, [Whether we have sched_yield()]) ]) AC_CHECK_FUNCS(pthread_attr_getschedpolicy) - AC_CHECK_FUNCS(pthread_attr_setinheritsched) + + old_OBJCFLAGS="$OBJCFLAGS" + OBJCFLAGS="$OBJCFLAGS -Werror" + AC_MSG_CHECKING(for pthread_attr_setinheritsched) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + pthread_attr_setinheritsched( + (pthread_attr_t *)-1, 0); + ]) + ], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PTHREAD_ATTR_SETINHERITSCHED, 1, + [Whether we have pthread_attr_setinheritsched]) + ], [ + AC_MSG_RESULT(no) + ]) + OBJCFLAGS="$old_OBJCFLAGS" AC_CHECK_HEADERS(pthread_np.h, [], [], [#include ]) AC_CHECK_FUNCS(pthread_set_name_np pthread_setname_np, break) ;; esac @@ -1332,11 +1359,11 @@ AC_CHECK_FUNCS([fcntl nanosleep]) ;; esac AC_CHECK_HEADERS(xlocale.h) -AC_CHECK_FUNCS([strtod_l strtof_l asprintf_l]) +AC_CHECK_FUNCS([strtod_l strtof_l asprintf_l uselocale]) AS_IF([test x"$gnu_source" != x"yes" -a \( \ x"$ac_cv_func_strtod_l" = x"yes" -o x"$ac_cv_func_strtof_l" = x"yes" -o \ x"$ac_cv_func_asprintf_l" = x"yes" \)], [ AC_MSG_CHECKING(whether *_l functions need _GNU_SOURCE) AC_COMPILE_IFELSE([ @@ -1418,21 +1445,44 @@ AC_CHECK_HEADER(sys/socket.h, [ AC_DEFINE(OF_HAVE_SYS_SOCKET_H, 1, [Whether we have sys/socket.h]) ]) + AC_CHECK_TYPE([struct sockaddr_storage], [ + AC_DEFINE(OF_HAVE_SOCKADDR_STORAGE, 1, + [Whether we have struct sockaddr_storage]) + ], [], [ + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #ifdef OF_HAVE_SYS_SOCKET_H + # include + #endif + #ifdef _WIN32 + # include + #endif + ]) AC_CHECK_HEADER(netinet/in.h, [ AC_DEFINE(OF_HAVE_NETINET_IN_H, 1, [Whether we have netinet/in.h]) ]) AC_CHECK_HEADER(netinet/tcp.h, [ AC_DEFINE(OF_HAVE_NETINET_TCP_H, 1, [Whether we have netinet/tcp.h]) ]) - AC_CHECK_HEADERS([arpa/inet.h netdb.h net/if.h]) + AC_CHECK_HEADERS([arpa/inet.h netdb.h]) + AC_CHECK_HEADERS([net/if.h net/if_arp.h net/if_dl.h net/if_types.h]) AC_CHECK_FUNCS([if_indextoname if_nametoindex]) + AC_CHECK_TYPES([struct sockaddr_dl], [], [], [ + #ifdef HAVAE_SYS_TYPES_H + # include + #endif + #ifdef HAVE_NET_IF_DL_H + # include + #endif + ]) AC_CHECK_HEADER(sys/un.h, [ AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h]) ]) AC_CHECK_MEMBER([struct sockaddr_in6.sin6_addr], [ AC_EGREP_CPP(egrep_cpp_yes, [ @@ -1495,10 +1545,25 @@ ]) AC_CHECK_MEMBER(struct sockaddr_un.sun_path, [ AC_DEFINE(OF_HAVE_UNIX_SOCKETS, 1, [Whether we have UNIX sockets]) AC_SUBST(USE_SRCS_UNIX_SOCKETS, '${SRCS_UNIX_SOCKETS}') + + AC_CHECK_MEMBERS(struct sockaddr_un.sun_len, [], [], [ + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #ifdef OF_HAVE_SYS_UN_H + # include + #endif + #ifdef _WIN32 + # include + #endif + #ifdef HAVE_AFUNIX_H + # include + #endif + ]) ], [], [ #ifdef OF_HAVE_SYS_TYPES_H # include #endif #ifdef OF_HAVE_SYS_UN_H @@ -1516,21 +1581,40 @@ #endif #ifdef __MINT__ # error Gives invalid argument at runtime #endif + + #ifdef __gnu_hurd__ + # error Empty sun_path in the source given by recvfrom() + #endif ]) AC_CHECK_HEADER(netipx/ipx.h, [ AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1, [Whether we have netipx/ipx.h]) ]) AC_CHECK_MEMBER(struct sockaddr_ipx.sipx_network, [], [ - AC_CHECK_MEMBER(struct sockaddr_ipx.sa_netnum, [], [], [ + AC_CHECK_MEMBER(struct sockaddr_ipx.sa_netnum, [], [ + AC_CHECK_MEMBER(struct sockaddr_ipx.sipx_addr.x_port, [ + ], [], [ + #ifdef HAVE_SYS_TYPES_H + # include + #endif + + #ifdef OF_HAVE_NETIPX_IPX_H + # include + #endif + ]) + ], [ #ifdef _WIN32 typedef int BOOL; #endif + + #ifdef HAVE_SYS_TYPES_H + # include + #endif #ifdef OF_HAVE_NETIPX_IPX_H # include #endif @@ -1547,10 +1631,14 @@ ]) ], [ #ifdef _WIN32 typedef int BOOL; #endif + + #ifdef HAVE_SYS_TYPES_H + # include + #endif #ifdef OF_HAVE_NETIPX_IPX_H # include #endif @@ -1564,11 +1652,12 @@ # include # include #endif ]) AS_IF([test x"$ac_cv_member_struct_sockaddr_ipx_sipx_network" = x"yes" \ - -o x"$ac_cv_member_struct_sockaddr_ipx_sa_netnum" = x"yes"], [ + -o x"$ac_cv_member_struct_sockaddr_ipx_sa_netnum" = x"yes" -o \ + x"$ac_cv_member_struct_sockaddr_ipx_sipx_addr_x_port" = x"yes"], [ AC_EGREP_CPP(egrep_cpp_yes, [ #ifdef _WIN32 typedef int BOOL; #endif @@ -1730,27 +1819,27 @@ "OFSelectKernelEventObserver.m") ]) ;; esac + AC_CHECK_HEADERS(net/if.h) + AC_CHECK_FUNCS(if_nameindex) + AC_ARG_WITH(tls, AS_HELP_STRING([--with-tls], [ enable TLS support using the specified library (yes, openssl, gnutls, securetransport or no)])) AS_IF([test x"$with_tls" = x""], [with_tls="yes"]) tls_support="no" AS_IF([test x"$with_tls" = x"securetransport" \ - -o x"$with_tls" = x"yes"], [ + -o x"$with_tls" = x"yes"], [ AC_CHECK_HEADERS(Security/SecureTransport.h, [ old_LIBS="$LIBS" LIBS="-framework Security -framework Foundation $LIBS" AC_CHECK_FUNC(SSLHandshake, [ - AC_DEFINE(HAVE_SECURE_TRANSPORT, 1, - [Whether we have Secure Transport]) - tls_support="Secure Transport" TLS_LIBS="-framework Foundation $TLS_LIBS" TLS_LIBS="-framework Security $TLS_LIBS" AC_SUBST(OF_SECURE_TRANSPORT_TLS_STREAM_M, @@ -1762,14 +1851,12 @@ LIBS="$old_LIBS" ]) ]) AS_IF([test x"$with_tls" = x"gnutls" \ - -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ PKG_CHECK_MODULES(gnutls, [gnutls >= 3.5.0], [ - AC_DEFINE(HAVE_GNUTLS, 1, [Whether we have GnuTLS]) - tls_support="GnuTLS" TLS_CPPFLAGS="$gnutls_CFLAGS $TLS_CPPFLAGS" TLS_LIBS="$gnutls_LIBS $TLS_LIBS" AC_SUBST(OF_GNUTLS_TLS_STREAM_M, "OFGnuTLSTLSStream.m") @@ -1779,11 +1866,11 @@ : ]) ]) AS_IF([test x"$with_tls" = x"openssl" \ - -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ case "$host_os" in morphos*) ssl="ssl_shared" crypto="crypto_shared" ;; @@ -1793,13 +1880,10 @@ ;; esac AC_CHECK_LIB($ssl, SSL_set1_host, [ AC_CHECK_HEADER(openssl/ssl.h, [ - AC_DEFINE(HAVE_OPENSSL, 1, - [Whether we have OpenSSL]) - tls_support="OpenSSL" TLS_LIBS="-l$ssl -l$crypto $TLS_LIBS" AC_SUBST(OF_OPENSSL_TLS_STREAM_M, "OFOpenSSLTLSStream.m") @@ -1817,11 +1901,11 @@ OFHTTP_LIBS="-lobjfwtls $TLS_LIBS $OFHTTP_LIBS" AS_IF([test x"$enable_shared" != x"no"], [ AC_SUBST(OBJFWTLS_SHARED_LIB, - "${LIB_PREFIX}objfwtls${LIB_SUFFIX}") + '${LIB_PREFIX}objfwtls${LIB_SUFFIX}') ]) AS_IF([test x"$enable_static" = x"yes" \ -o x"$enable_shared" = x"no"], [ AC_SUBST(OBJFWTLS_STATIC_LIB, "libobjfwtls.a") ]) @@ -1881,14 +1965,10 @@ (!defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR) egrep_cpp_yes #endif ], [ AC_MSG_RESULT(yes) - have_subprocesses="yes" - - AC_CHECK_FUNCS(posix_spawnp) - AC_CHECK_HEADERS(spawn.h) ], [ AC_MSG_RESULT(no) have_subprocesses="no" ]) ;; @@ -1896,21 +1976,22 @@ have_subprocesses="yes" ;; msdosdjgpp*) have_subprocesses="no" ;; -*) +esac +AS_IF([test x"$have_subprocesses" = x""], [ AC_HEADER_SYS_WAIT AC_CHECK_FUNCS(kill) AC_CHECK_FUNCS(posix_spawnp, [ AS_IF([test x"$ac_cv_func_kill" = x"yes"], [ - have_subprocesses="yes" - - AC_CHECK_HEADERS(spawn.h) + AC_CHECK_HEADERS(spawn.h, [have_subprocesses="yes"]) ]) - ], [ + ]) + + AS_IF([test x"$have_subprocesses" = x""], [ AC_CHECK_FUNCS([vfork dup2 execvp _exit], [ AS_IF([test x"$ac_cv_func_vfork" = x"yes" \ -a x"$ac_cv_func_pipe" = x"yes" \ -a x"$ac_cv_func_dup2" = x"yes" \ -a x"$ac_cv_func_execvp" = x"yes" \ @@ -1920,19 +2001,18 @@ ]) ], [ break ]) ]) - ;; -esac +]) AS_IF([test x"$have_subprocesses" = x"yes"], [ AC_SUBST(OF_SUBPROCESS_M, "OFSubprocess.m") AC_DEFINE(OF_HAVE_SUBPROCESSES, 1, [Whether we have subprocesses]) ]) AC_CHECK_HEADERS_ONCE([complex.h sys/ioctl.h sys/ttycom.h]) -AC_CHECK_FUNCS(isatty) +AC_CHECK_FUNCS(ioctl isatty) AC_CHECK_FUNC(pledge, [ AC_DEFINE(OF_HAVE_PLEDGE, 1, [Whether we have pledge()]) ]) @@ -1941,11 +2021,11 @@ AC_SUBST(BRIDGE, "bridge") AC_CONFIG_FILES(src/bridge/Info.plist) AS_IF([test x"$enable_shared" != x"no"], [ AC_SUBST(OBJFWBRIDGE_SHARED_LIB, - "${LIB_PREFIX}objfwbridge${LIB_SUFFIX}") + '${LIB_PREFIX}objfwbridge${LIB_SUFFIX}') ]) AS_IF([test x"$enable_static" = x"yes" \ -o x"$enable_shared" = x"no"], [ AC_SUBST(OBJFWBRIDGE_STATIC_LIB, "libobjfwbridge.a") ]) @@ -2219,10 +2299,24 @@ ], [ AC_MSG_RESULT(yes) OBJCFLAGS="$old_OBJCFLAGS" ]) ]) + + AC_MSG_CHECKING(whether we need -Wno-strict-prototypes) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + ], [ + signal(SIGINT, SIG_DFL); + ]) + ], [ + AC_MSG_RESULT(no) + ], [ + AC_MSG_RESULT(yes) + OBJCFLAGS="$OBJCFLAGS -Wno-strict-prototypes" + ]) AS_IF([test x"$ac_cv_header_complex_h" = x"yes"], [ AC_MSG_CHECKING(whether we need -Wno-gnu-imaginary-constant) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([ @@ -2249,14 +2343,11 @@ ;; x86_64-*-mingw*) AC_CHECK_PROG(WINE, wine64, wine64) ;; esac - - AS_IF([test x"$WINE" != x""], [ - AC_SUBST(WRAPPER, "$WINE") - ]) + AS_IF([test x"$WINE" != x""], [AC_SUBST(WRAPPER, "$WINE")]) AS_IF([test x"$with_wii" = x"yes"], [ dnl Keep this lowercase, as WIILOAD is a variable used by dnl wiiload and thus likely already set by the user to something dnl that is not the path of the wiiload binary. @@ -2266,21 +2357,10 @@ AC_SUBST(WRAPPER, "$wiiload") ]) ]) ]) -AC_ARG_WITH(fish_completions, - AS_HELP_STRING([--with-fish-completions], - [install completions for the fish shell])) -AS_IF([test x"$with_fish_completions" = x""], [ - AC_CHECK_PROG(FISH, fish, fish) - AS_IF([test x"$FISH" != x""], [with_fish_completions="yes"]) -]) -AS_IF([test x"$with_fish_completions" = x"yes"], [ - AC_SUBST(FISH_COMPLETIONS, fish) -]) - dnl We don't call AC_PROG_CPP, but only AC_PROG_OBJCPP and set CPP to OBJCPP dnl and add OBJCPPFLAGS to CPPFLAGS, thus we need to AC_SUBST these ourself. AC_SUBST(CPP) AC_SUBST(CPPFLAGS) dnl We use the ObjC compiler as our assembler Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -30,11 +30,10 @@ ENCODINGS_LIB_A = @ENCODINGS_LIB_A@ ENCODINGS_SRCS = @ENCODINGS_SRCS@ EXCEPTIONS_A = @EXCEPTIONS_A@ EXCEPTIONS_AMIGALIB_A = @EXCEPTIONS_AMIGALIB_A@ EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@ -FISH_COMPLETIONS = @FISH_COMPLETIONS@ FORWARDING_A = @FORWARDING_A@ FORWARDING_AMIGALIB_A = @FORWARDING_AMIGALIB_A@ FORWARDING_LIB_A = @FORWARDING_LIB_A@ LIBBASES_M = @LIBBASES_M@ LIBOBJFWRT_DEP = @LIBOBJFWRT_DEP@ Index: generators/library/FuncArrayGenerator.h ================================================================== --- generators/library/FuncArrayGenerator.h +++ generators/library/FuncArrayGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/FuncArrayGenerator.m ================================================================== --- generators/library/FuncArrayGenerator.m +++ generators/library/FuncArrayGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/GlueGenerator.h ================================================================== --- generators/library/GlueGenerator.h +++ generators/library/GlueGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/GlueGenerator.m ================================================================== --- generators/library/GlueGenerator.m +++ generators/library/GlueGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/LibraryGenerator.m ================================================================== --- generators/library/LibraryGenerator.m +++ generators/library/LibraryGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,11 @@ #include "config.h" #import "OFApplication.h" #import "OFFile.h" #import "OFFileManager.h" -#import "OFURI.h" +#import "OFIRI.h" #import "OFXMLElement.h" #import "FuncArrayGenerator.h" #import "GlueGenerator.h" #import "LinkLibGenerator.h" @@ -31,35 +31,35 @@ OF_APPLICATION_DELEGATE(LibraryGenerator) @implementation LibraryGenerator - (void)generateInDirectory: (OFString *)directory { - OFURI *sourcesURI = [[OFFileManager defaultManager].currentDirectoryURI - URIByAppendingPathComponent: directory]; - OFURI *libraryURI = [sourcesURI - URIByAppendingPathComponent: @"amiga-library.xml"]; - OFURI *linkLibURI = [sourcesURI - URIByAppendingPathComponent: @"linklib/linklib.m"]; - OFURI *glueHeaderURI = [sourcesURI - URIByAppendingPathComponent: @"amiga-glue.h"]; - OFURI *glueURI = [sourcesURI - URIByAppendingPathComponent: @"amiga-glue.m"]; - OFURI *funcArrayURI = [sourcesURI - URIByAppendingPathComponent: @"amiga-funcarray.inc"]; + OFIRI *sourcesIRI = [[OFFileManager defaultManager].currentDirectoryIRI + IRIByAppendingPathComponent: directory]; + OFIRI *libraryIRI = [sourcesIRI + IRIByAppendingPathComponent: @"amiga-library.xml"]; + OFIRI *linkLibIRI = [sourcesIRI + IRIByAppendingPathComponent: @"linklib/linklib.m"]; + OFIRI *glueHeaderIRI = [sourcesIRI + IRIByAppendingPathComponent: @"amiga-glue.h"]; + OFIRI *glueIRI = [sourcesIRI + IRIByAppendingPathComponent: @"amiga-glue.m"]; + OFIRI *funcArrayIRI = [sourcesIRI + IRIByAppendingPathComponent: @"amiga-funcarray.inc"]; OFXMLElement *library = [OFXMLElement elementWithStream: - [OFFile fileWithPath: libraryURI.fileSystemRepresentation + [OFFile fileWithPath: libraryIRI.fileSystemRepresentation mode: @"r"]]; OFFile *linkLib = - [OFFile fileWithPath: linkLibURI.fileSystemRepresentation + [OFFile fileWithPath: linkLibIRI.fileSystemRepresentation mode: @"w"]; OFFile *glueHeader = - [OFFile fileWithPath: glueHeaderURI.fileSystemRepresentation + [OFFile fileWithPath: glueHeaderIRI.fileSystemRepresentation mode: @"w"]; OFFile *glue = - [OFFile fileWithPath: glueURI.fileSystemRepresentation mode: @"w"]; + [OFFile fileWithPath: glueIRI.fileSystemRepresentation mode: @"w"]; OFFile *funcArray = - [OFFile fileWithPath: funcArrayURI.fileSystemRepresentation + [OFFile fileWithPath: funcArrayIRI.fileSystemRepresentation mode: @"w"]; LinkLibGenerator *linkLibGenerator = [[[LinkLibGenerator alloc] initWithLibrary: library implementation: linkLib] autorelease]; GlueGenerator *glueGenerator = [[[GlueGenerator alloc] Index: generators/library/LinkLibGenerator.h ================================================================== --- generators/library/LinkLibGenerator.h +++ generators/library/LinkLibGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/LinkLibGenerator.m ================================================================== --- generators/library/LinkLibGenerator.m +++ generators/library/LinkLibGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/library/copyright.h ================================================================== --- generators/library/copyright.h +++ generators/library/copyright.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #import "OFString.h" #define COPYRIGHT \ @"/*\n" \ - @" * Copyright (c) 2008-2022 Jonathan Schleifer \n" \ + @" * Copyright (c) 2008-2023 Jonathan Schleifer \n" \ @" *\n" \ @" * All rights reserved.\n" \ @" *\n" \ @" * This file is part of ObjFW. It may be distributed under the terms " \ @"of the\n" \ Index: generators/unicode/TableGenerator.h ================================================================== --- generators/unicode/TableGenerator.h +++ generators/unicode/TableGenerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: generators/unicode/TableGenerator.m ================================================================== --- generators/unicode/TableGenerator.m +++ generators/unicode/TableGenerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,28 +15,28 @@ #include "config.h" #include -#import "OFString.h" +#import "OFApplication.h" #import "OFArray.h" -#import "OFApplication.h" -#import "OFURI.h" +#import "OFFile.h" +#import "OFHTTPClient.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" -#import "OFHTTPClient.h" -#import "OFFile.h" +#import "OFIRI.h" #import "OFStdIOStream.h" +#import "OFString.h" #import "OFOutOfRangeException.h" #import "TableGenerator.h" #import "copyright.h" -static OFString *const unicodeDataURI = +static OFString *const unicodeDataIRI = @"http://www.unicode.org/Public/UNIDATA/UnicodeData.txt"; -static OFString *const caseFoldingURI = +static OFString *const caseFoldingIRI = @"http://www.unicode.org/Public/UNIDATA/CaseFolding.txt"; OF_APPLICATION_DELEGATE(TableGenerator) @implementation TableGenerator @@ -66,12 +66,12 @@ { OFHTTPRequest *request; [OFStdOut writeString: @"Downloading UnicodeData.txt…"]; _state = stateUnicodeData; - request = [OFHTTPRequest requestWithURI: - [OFURI URIWithString: unicodeDataURI]]; + request = [OFHTTPRequest requestWithIRI: + [OFIRI IRIWithString: unicodeDataIRI]]; [_HTTPClient asyncPerformRequest: request]; } - (void)client: (OFHTTPClient *)client didPerformRequest: (OFHTTPRequest *)request @@ -166,12 +166,12 @@ [OFStdOut writeLine: @" done"]; [OFStdOut writeString: @"Downloading CaseFolding.txt…"]; _state = stateCaseFolding; - request = [OFHTTPRequest requestWithURI: - [OFURI URIWithString: caseFoldingURI]]; + request = [OFHTTPRequest requestWithIRI: + [OFIRI IRIWithString: caseFoldingIRI]]; [_HTTPClient asyncPerformRequest: request]; } - (void)parseCaseFolding: (OFHTTPResponse *)response { @@ -268,19 +268,19 @@ } while (!done); } - (void)writeFiles { - OFURI *URI; + OFIRI *IRI; [OFStdOut writeString: @"Writing files…"]; - URI = [OFURI fileURIWithPath: @"../../src/unicode.m"]; - [self writeTablesToFile: URI.fileSystemRepresentation]; + IRI = [OFIRI fileIRIWithPath: @"../../src/unicode.m"]; + [self writeTablesToFile: IRI.fileSystemRepresentation]; - URI = [OFURI fileURIWithPath: @"../../src/unicode.h"]; - [self writeHeaderToFile: URI.fileSystemRepresentation]; + IRI = [OFIRI fileIRIWithPath: @"../../src/unicode.h"]; + [self writeHeaderToFile: IRI.fileSystemRepresentation]; [OFStdOut writeLine: @" done"]; [OFApplication terminate]; } Index: generators/unicode/copyright.h ================================================================== --- generators/unicode/copyright.h +++ generators/unicode/copyright.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #import "OFString.h" #define COPYRIGHT \ @"/*\n" \ - @" * Copyright (c) 2008-2022 Jonathan Schleifer \n" \ + @" * Copyright (c) 2008-2023 Jonathan Schleifer \n" \ @" *\n" \ @" * All rights reserved.\n" \ @" *\n" \ @" * This file is part of ObjFW. It may be distributed under the terms " \ @"of the\n" \ Index: objfw.spec ================================================================== --- objfw.spec +++ objfw.spec @@ -163,86 +163,82 @@ %post -n %{libobjfwrt_pkgname} -p /sbin/ldconfig %postun -n %{libobjfwrt_pkgname} -p /sbin/ldconfig %endif %files -%license LICENSE.QPL +%license LICENSE.GPLv2 %license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%license LICENSE.QPL %files -n %{libobjfw_pkgname} +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 +%license LICENSE.QPL %{_libdir}/libobjfw.so.%{libobjfw_major} %{_libdir}/libobjfw.so.%{libobjfw_major}.%{libobjfw_minor}.0 -%license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 %files -n %{libobjfw_pkgname}-devel -%{_libdir}/libobjfw.so -%dir %{_includedir}/ObjFW -%{_includedir}/ObjFW +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 +%license LICENSE.QPL %{_bindir}/objfw-compile %{_bindir}/objfw-config +%{_bindir}/objfw-embed %{_bindir}/objfw-new -%license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_includedir}/ObjFW +%{_libdir}/libobjfw.so %files -n %{libobjfwrt_pkgname} +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 +%license LICENSE.QPL %{_libdir}/libobjfwrt.so.%{libobjfwrt_major} %{_libdir}/libobjfwrt.so.%{libobjfwrt_major}.%{libobjfwrt_minor}.0 -%license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 %files -n %{libobjfwrt_pkgname}-devel -%{_libdir}/libobjfwrt.so -%{_includedir}/ObjFWRT/ObjFWRT.h +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_includedir}/ObjFWRT +%{_libdir}/libobjfwrt.so %files -n %{libobjfwtls_pkgname} +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 +%license LICENSE.QPL %{_libdir}/libobjfwtls.so.%{libobjfwtls_major} %{_libdir}/libobjfwtls.so.%{libobjfwtls_major}.%{libobjfwtls_minor}.0 -%license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 %files -n %{libobjfwtls_pkgname}-devel -%{_libdir}/libobjfwtls.so -%{_includedir}/ObjFWTLS/ObjFWTLS.h +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_includedir}/ObjFWTLS +%{_libdir}/libobjfwtls.so %files -n ofarc -%{_bindir}/ofarc -%{_datadir}/ofarc/lang/de.json -%{_datadir}/ofarc/lang/languages.json +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_bindir}/ofarc +%{_datadir}/ofarc %files -n ofdns -%{_bindir}/ofdns -%{_datadir}/ofdns/lang/de.json -%{_datadir}/ofdns/lang/languages.json +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_bindir}/ofdns +%{_datadir}/ofdns %files -n ofhash -%{_bindir}/ofhash -%{_datadir}/ofhash/lang/de.json -%{_datadir}/ofhash/lang/languages.json +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_bindir}/ofhash +%{_datadir}/ofhash %files -n ofhttp -%{_bindir}/ofhttp -%{_datadir}/ofhttp/lang/de.json -%{_datadir}/ofhttp/lang/languages.json +%license LICENSE.GPLv2 +%license LICENSE.GPLv3 %license LICENSE.QPL -%license LICENSE.GPLv3 -%license LICENSE.GPLv2 +%{_bindir}/ofhttp +%{_datadir}/ofhttp Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -28,47 +28,48 @@ OFData.m \ OFData+CryptographicHashing.m \ OFData+MessagePackParsing.m \ OFDate.m \ OFDictionary.m \ - OFEmbeddedURIHandler.m \ OFEnumerator.m \ OFFileManager.m \ OFGZIPStream.m \ OFHMAC.m \ OFINICategory.m \ OFINIFile.m \ + OFIRI.m \ + OFIRIHandler.m \ OFInflate64Stream.m \ OFInflateStream.m \ OFInvocation.m \ OFLHAArchive.m \ OFLHAArchiveEntry.m \ OFList.m \ OFLocale.m \ OFMD5Hash.m \ OFMapTable.m \ + OFMatrix4x4.m \ OFMemoryStream.m \ OFMessagePackExtension.m \ OFMethodSignature.m \ OFMutableArray.m \ OFMutableData.m \ OFMutableDictionary.m \ + OFMutableIRI.m \ OFMutableLHAArchiveEntry.m \ OFMutablePair.m \ OFMutableSet.m \ OFMutableString.m \ OFMutableTarArchiveEntry.m \ OFMutableTriple.m \ - OFMutableURI.m \ OFMutableZIPArchiveEntry.m \ OFNotification.m \ OFNotificationCenter.m \ OFNull.m \ OFNumber.m \ OFObject.m \ OFObject+KeyValueCoding.m \ - OFObject+Serialization.m \ OFOnce.m \ OFOptionsParser.m \ OFPBKDF2.m \ OFPair.m \ OFRIPEMD160Hash.m \ @@ -81,11 +82,10 @@ OFSHA384Or512Hash.m \ OFSHA512Hash.m \ OFScrypt.m \ OFSecureData.m \ OFSeekableStream.m \ - OFSerialization.m \ OFSet.m \ OFSettings.m \ OFSortedList.m \ OFStdIOStream.m \ OFStream.m \ @@ -92,30 +92,26 @@ OFString.m \ OFString+CryptographicHashing.m \ OFString+JSONParsing.m \ OFString+PercentEncoding.m \ OFString+PropertyListParsing.m \ - OFString+Serialization.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ ${OF_SUBPROCESS_M} \ OFSystemInfo.m \ OFTarArchive.m \ OFTarArchiveEntry.m \ OFThread.m \ OFTimer.m \ OFTriple.m \ - OFURI.m \ - OFURIHandler.m \ OFUUID.m \ OFValue.m \ OFXMLAttribute.m \ OFXMLCDATA.m \ OFXMLCharacters.m \ OFXMLComment.m \ OFXMLElement.m \ - OFXMLElement+Serialization.m \ OFXMLElementBuilder.m \ OFXMLNode.m \ OFXMLParser.m \ OFXMLProcessingInstruction.m \ OFZIPArchive.m \ @@ -140,10 +136,11 @@ OFHTTPResponse.m \ OFHTTPServer.m \ OFSequencedPacketSocket.m \ OFSocket.m \ OFStreamSocket.m \ + OFSystemInfo+NetworkInterfaces.m \ OFTCPSocket.m \ OFTLSStream.m \ OFUDPSocket.m \ ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ @@ -186,17 +183,18 @@ ${USE_INCLUDES_ATOMIC} SRCS += OFASPrintF.m \ OFAdjacentArray.m \ OFAdjacentSubarray.m \ - OFArchiveURIHandler.m \ + OFArchiveIRIHandler.m \ OFBase64.m \ OFBitSetCharacterSet.m \ OFBytesValue.m \ OFCRC16.m \ OFCRC32.m \ OFCountedMapTableSet.m \ + OFEmbeddedIRIHandler.m \ OFHuffmanTree.m \ OFINIFileSettings.m \ OFInvertedCharacterSet.m \ OFLHADecompressingStream.m \ OFMapTableDictionary.m \ @@ -218,15 +216,15 @@ OFUTF8String.m \ ${LIBBASES_M} \ ${RUNTIME_AUTORELEASE_M} \ ${RUNTIME_INSTANCE_M} \ ${UNICODE_M} -SRCS_FILES += OFFileURIHandler.m +SRCS_FILES += OFFileIRIHandler.m SRCS_SOCKETS += OFAsyncIPSocketConnector.m \ OFDNSResolverSettings.m \ ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ - OFHTTPURIHandler.m \ + OFHTTPIRIHandler.m \ OFHostAddressResolver.m \ OFKernelEventObserver.m \ ${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M} \ ${OF_POLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_SELECT_KERNEL_EVENT_OBSERVER_M} \ @@ -264,5 +262,13 @@ RCFLAGS = --use-temp-file \ -DOBJFW_LIB_MAJOR=${OBJFW_LIB_MAJOR} \ -DOBJFW_LIB_MINOR=${OBJFW_LIB_MINOR} \ -DOBJFW_LIB_VERSION=\"${OBJFW_LIB_MAJOR}.${OBJFW_LIB_MINOR}\" \ -DOBJFW_SHARED_LIB=\"${OBJFW_SHARED_LIB}\" + +uninstall-extra: + for i in platform/GCC4 platform/GCC4.7 platform/PowerPC platform/macOS \ + platform/x86 platform ""; do \ + if test -d ${DESTDIR}${includedir}/${includesubdir}/$$i; then \ + rmdir ${DESTDIR}${includedir}/${includesubdir}/$$i; \ + fi; \ + done Index: src/OFASPrintF.h ================================================================== --- src/OFASPrintF.h +++ src/OFASPrintF.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFASPrintF.m ================================================================== --- src/OFASPrintF.m +++ src/OFASPrintF.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,11 +23,11 @@ #ifdef HAVE_WCHAR_H # include #endif -#ifdef HAVE_ASPRINTF_L +#if defined(HAVE_ASPRINTF_L) || defined(HAVE_USELOCALE) # include #endif #ifdef HAVE_XLOCALE_H # include #endif @@ -81,11 +81,11 @@ lengthModifierCapitalL } lengthModifier; bool useLocale; }; -#ifdef HAVE_ASPRINTF_L +#if defined(HAVE_ASPRINTF_L) || defined(HAVE_USELOCALE) static locale_t cLocale; OF_CONSTRUCTOR() { if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) @@ -375,11 +375,11 @@ static bool formatConversionSpecifierState(struct Context *ctx) { char *tmp = NULL; int tmpLen = 0; -#ifndef HAVE_ASPRINTF_L +#if !defined(HAVE_ASPRINTF_L) && !defined(HAVE_USELOCALE) OFString *point; #endif if (!appendSubformat(ctx, ctx->format + ctx->i, 1)) return false; @@ -546,43 +546,57 @@ case 'a': case 'A': switch (ctx->lengthModifier) { case lengthModifierNone: case lengthModifierL: -#ifdef HAVE_ASPRINTF_L +#if defined(HAVE_ASPRINTF_L) if (!ctx->useLocale) tmpLen = asprintf_l(&tmp, cLocale, ctx->subformat, va_arg(ctx->arguments, double)); else +#elif defined(HAVE_USELOCALE) + if (!ctx->useLocale) { + locale_t previousLocale = uselocale(cLocale); + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, double)); + uselocale(previousLocale); + } else #endif tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, double)); break; case lengthModifierCapitalL: -#ifdef HAVE_ASPRINTF_L +#if defined(HAVE_ASPRINTF_L) if (!ctx->useLocale) tmpLen = asprintf_l(&tmp, cLocale, ctx->subformat, va_arg(ctx->arguments, long double)); else +#elif defined(HAVE_USELOCALE) + if (!ctx->useLocale) { + locale_t previousLocale = uselocale(cLocale); + tmpLen = asprintf(&tmp, ctx->subformat, + va_arg(ctx->arguments, long double)); + uselocale(previousLocale); + } else #endif tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double)); break; default: return false; } -#ifndef HAVE_ASPRINTF_L +#if !defined(HAVE_ASPRINTF_L) && !defined(HAVE_USELOCALE) if (tmpLen == -1) return false; /* - * If there's no asprintf_l, we have no other choice than to - * use this ugly hack to replace the locale's decimal point - * back to ".". + * If there's no asprintf_l and no uselocale, we have no other + * choice than to use this ugly hack to replace the locale's + * decimal point back to ".". */ point = [OFLocale decimalSeparator]; if (!ctx->useLocale && point != nil && ![point isEqual: @"."]) { void *pool = objc_autoreleasePoolPush(); Index: src/OFAdjacentArray.h ================================================================== --- src/OFAdjacentArray.h +++ src/OFAdjacentArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFAdjacentArray.m ================================================================== --- src/OFAdjacentArray.m +++ src/OFAdjacentArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,10 @@ #import "OFAdjacentArray.h" #import "OFAdjacentSubarray.h" #import "OFData.h" #import "OFMutableAdjacentArray.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" @@ -148,43 +147,10 @@ [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [self init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if ((![element.name isEqual: @"OFArray"] && - ![element.name isEqual: @"OFMutableArray"]) || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - for (OFXMLElement *child in - [element elementsForNamespace: OFSerializationNS]) { - void *pool2 = objc_autoreleasePoolPush(); - id object; - - object = child.objectByDeserializing; - [_array addItem: &object]; - [object retain]; - - objc_autoreleasePoolPop(pool2); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (size_t)count { Index: src/OFAdjacentSubarray.h ================================================================== --- src/OFAdjacentSubarray.h +++ src/OFAdjacentSubarray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFAdjacentSubarray.m ================================================================== --- src/OFAdjacentSubarray.m +++ src/OFAdjacentSubarray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFApplication.h ================================================================== --- src/OFApplication.h +++ src/OFApplication.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -163,11 +163,11 @@ * In order to create a new OFApplication, you should create a class conforming * to the optional @ref OFApplicationDelegate protocol and put * `OF_APPLICATION_DELEGATE(NameOfYourClass)` in the .m file of that class. * * When the application is about to be terminated, - * @ref OFApplicationDelegate#applicationWillTerminate will be called on the + * @ref OFApplicationDelegate#applicationWillTerminate: will be called on the * delegate and an @ref OFApplicationWillTerminateNotification will be sent. */ OF_SUBCLASSING_RESTRICTED @interface OFApplication: OFObject { Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -53,12 +53,14 @@ #elif defined(OF_WINDOWS) # include extern int _CRT_glob; extern void __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *); #elif defined(OF_AMIGAOS) +# define Class IntuitionClass # include # include +# undef Class #elif !defined(OF_IOS) extern char **environ; #endif #ifdef OF_PSP Index: src/OFArchiveEntry.h ================================================================== --- src/OFArchiveEntry.h +++ src/OFArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/OFArchiveIRIHandler.h Index: src/OFArchiveIRIHandler.h ================================================================== --- src/OFArchiveIRIHandler.h +++ src/OFArchiveIRIHandler.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRIHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFArchiveIRIHandler: OFIRIHandler +@end + +#ifdef __cplusplus +extern "C" { +#endif +extern OFIRI *OFArchiveIRIHandlerIRIForFileInArchive(OFString *, OFString *, + OFIRI *); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFArchiveIRIHandler.m Index: src/OFArchiveIRIHandler.m ================================================================== --- src/OFArchiveIRIHandler.m +++ src/OFArchiveIRIHandler.m @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFArchiveIRIHandler.h" +#import "OFCharacterSet.h" +#import "OFGZIPStream.h" +#import "OFIRI.h" +#import "OFLHAArchive.h" +#import "OFStream.h" +#import "OFTarArchive.h" +#import "OFZIPArchive.h" + +#import "OFInvalidArgumentException.h" +#import "OFOpenItemFailedException.h" + +@interface OFArchiveIRIHandlerPathAllowedCharacterSet: OFCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, OFUnichar); +} +@end + +static OFCharacterSet *pathAllowedCharacters; + +static void +initPathAllowedCharacters(void) +{ + pathAllowedCharacters = + [[OFArchiveIRIHandlerPathAllowedCharacterSet alloc] init]; +} + +@implementation OFArchiveIRIHandler +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + void *pool = objc_autoreleasePoolPush(); + OFString *scheme = IRI.scheme; + OFString *percentEncodedPath, *path; + size_t pos; + OFIRI *archiveIRI; + OFStream *stream; + + if (IRI.host != nil || IRI.port != nil || IRI.user != nil || + IRI.password != nil || IRI.query != nil || IRI.fragment != nil) + @throw [OFInvalidArgumentException exception]; + + if (![mode isEqual: @"r"]) + /* + * Writing has some implications that are not decided yet: Will + * it always append to an archive? What happens if the file + * already exists? + */ + @throw [OFInvalidArgumentException exception]; + + /* + * GZIP only compresses one file and thus has no path inside an + * archive. + */ + if ([scheme isEqual: @"gzip"]) { + stream = [OFIRIHandler openItemAtIRI: [OFIRI IRIWithString: + IRI.path] + mode: @"r"]; + stream = [OFGZIPStream streamWithStream: stream mode: @"r"]; + goto end; + } + + percentEncodedPath = IRI.percentEncodedPath; + pos = [percentEncodedPath rangeOfString: @"!"].location; + + if (pos == OFNotFound) + @throw [OFInvalidArgumentException exception]; + + archiveIRI = [OFIRI IRIWithString: + [percentEncodedPath substringWithRange: OFMakeRange(0, pos)] + .stringByRemovingPercentEncoding]; + path = [percentEncodedPath substringWithRange: + OFMakeRange(pos + 1, percentEncodedPath.length - pos - 1)] + .stringByRemovingPercentEncoding; + + if ([scheme isEqual: @"lha"]) { + OFLHAArchive *archive = [OFLHAArchive archiveWithIRI: archiveIRI + mode: @"r"]; + OFLHAArchiveEntry *entry; + + while ((entry = [archive nextEntry]) != nil) { + if ([entry.fileName isEqual: path]) { + stream = [archive streamForReadingCurrentEntry]; + goto end; + } + } + + @throw [OFOpenItemFailedException exceptionWithIRI: IRI + mode: mode + errNo: ENOENT]; + } else if ([scheme isEqual: @"tar"]) { + OFTarArchive *archive = [OFTarArchive archiveWithIRI: archiveIRI + mode: @"r"]; + OFTarArchiveEntry *entry; + + while ((entry = [archive nextEntry]) != nil) { + if ([entry.fileName isEqual: path]) { + stream = [archive streamForReadingCurrentEntry]; + goto end; + } + } + + @throw [OFOpenItemFailedException exceptionWithIRI: IRI + mode: mode + errNo: ENOENT]; + } else if ([scheme isEqual: @"zip"]) { + OFZIPArchive *archive = [OFZIPArchive archiveWithIRI: archiveIRI + mode: @"r"]; + + stream = [archive streamForReadingFile: path]; + } else + @throw [OFInvalidArgumentException exception]; + +end: + stream = [stream retain]; + + objc_autoreleasePoolPop(pool); + + return [stream autorelease]; +} +@end + +@implementation OFArchiveIRIHandlerPathAllowedCharacterSet +- (instancetype)init +{ + self = [super init]; + + @try { + _characterSet = + [[OFCharacterSet IRIPathAllowedCharacterSet] retain]; + _characterIsMember = (bool (*)(id, SEL, OFUnichar)) + [_characterSet methodForSelector: + @selector(characterIsMember:)]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_characterSet release]; + + [super dealloc]; +} + +- (bool)characterIsMember: (OFUnichar)character +{ + return (character != '!' && _characterIsMember(_characterSet, + @selector(characterIsMember:), character)); +} +@end + +OFIRI * +OFArchiveIRIHandlerIRIForFileInArchive(OFString *scheme, + OFString *pathInArchive, OFIRI *archiveIRI) +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFMutableIRI *ret = [OFMutableIRI IRIWithScheme: scheme]; + void *pool = objc_autoreleasePoolPush(); + OFString *archiveIRIString; + + OFOnce(&onceControl, initPathAllowedCharacters); + + pathInArchive = [pathInArchive + stringByAddingPercentEncodingWithAllowedCharacters: + pathAllowedCharacters]; + archiveIRIString = [archiveIRI.string + stringByAddingPercentEncodingWithAllowedCharacters: + pathAllowedCharacters]; + + ret.percentEncodedPath = [OFString + stringWithFormat: @"%@!%@", archiveIRIString, pathInArchive]; + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +} DELETED src/OFArchiveURIHandler.h Index: src/OFArchiveURIHandler.h ================================================================== --- src/OFArchiveURIHandler.h +++ src/OFArchiveURIHandler.h @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURIHandler.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFArchiveURIHandler: OFURIHandler -@end - -#ifdef __cplusplus -extern "C" { -#endif -extern OFURI *OFArchiveURIHandlerURIForFileInArchive(OFString *, OFString *, - OFURI *); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/OFArchiveURIHandler.m Index: src/OFArchiveURIHandler.m ================================================================== --- src/OFArchiveURIHandler.m +++ src/OFArchiveURIHandler.m @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "OFArchiveURIHandler.h" -#import "OFCharacterSet.h" -#import "OFGZIPStream.h" -#import "OFLHAArchive.h" -#import "OFStream.h" -#import "OFTarArchive.h" -#import "OFURI.h" -#import "OFZIPArchive.h" - -#import "OFInvalidArgumentException.h" -#import "OFOpenItemFailedException.h" - -@interface OFArchiveURIHandlerPathAllowedCharacterSet: OFCharacterSet -{ - OFCharacterSet *_characterSet; - bool (*_characterIsMember)(id, SEL, OFUnichar); -} -@end - -static OFCharacterSet *pathAllowedCharacters; - -static void -initPathAllowedCharacters(void) -{ - pathAllowedCharacters = - [[OFArchiveURIHandlerPathAllowedCharacterSet alloc] init]; -} - -@implementation OFArchiveURIHandler -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - void *pool = objc_autoreleasePoolPush(); - OFString *scheme = URI.scheme; - OFString *percentEncodedPath, *path; - size_t pos; - OFURI *archiveURI; - OFStream *stream; - - if (URI.host != nil || URI.port != nil || URI.user != nil || - URI.password != nil || URI.query != nil || URI.fragment != nil) - @throw [OFInvalidArgumentException exception]; - - if (![mode isEqual: @"r"]) - /* - * Writing has some implications that are not decided yet: Will - * it always append to an archive? What happens if the file - * already exists? - */ - @throw [OFInvalidArgumentException exception]; - - /* - * GZIP only compresses one file and thus has no path inside an - * archive. - */ - if ([scheme isEqual: @"gzip"]) { - stream = [OFURIHandler openItemAtURI: [OFURI URIWithString: - URI.path] - mode: @"r"]; - stream = [OFGZIPStream streamWithStream: stream mode: @"r"]; - goto end; - } - - percentEncodedPath = URI.percentEncodedPath; - pos = [percentEncodedPath rangeOfString: @"!"].location; - - if (pos == OFNotFound) - @throw [OFInvalidArgumentException exception]; - - archiveURI = [OFURI URIWithString: - [percentEncodedPath substringWithRange: OFMakeRange(0, pos)] - .stringByRemovingPercentEncoding]; - path = [percentEncodedPath substringWithRange: - OFMakeRange(pos + 1, percentEncodedPath.length - pos - 1)] - .stringByRemovingPercentEncoding; - - if ([scheme isEqual: @"lha"]) { - OFLHAArchive *archive = [OFLHAArchive archiveWithURI: archiveURI - mode: @"r"]; - OFLHAArchiveEntry *entry; - - while ((entry = [archive nextEntry]) != nil) { - if ([entry.fileName isEqual: path]) { - stream = [archive streamForReadingCurrentEntry]; - goto end; - } - } - - @throw [OFOpenItemFailedException exceptionWithURI: URI - mode: mode - errNo: ENOENT]; - } else if ([scheme isEqual: @"tar"]) { - OFTarArchive *archive = [OFTarArchive archiveWithURI: archiveURI - mode: @"r"]; - OFTarArchiveEntry *entry; - - while ((entry = [archive nextEntry]) != nil) { - if ([entry.fileName isEqual: path]) { - stream = [archive streamForReadingCurrentEntry]; - goto end; - } - } - - @throw [OFOpenItemFailedException exceptionWithURI: URI - mode: mode - errNo: ENOENT]; - } else if ([scheme isEqual: @"zip"]) { - OFZIPArchive *archive = [OFZIPArchive archiveWithURI: archiveURI - mode: @"r"]; - - stream = [archive streamForReadingFile: path]; - } else - @throw [OFInvalidArgumentException exception]; - -end: - stream = [stream retain]; - - objc_autoreleasePoolPop(pool); - - return [stream autorelease]; -} -@end - -@implementation OFArchiveURIHandlerPathAllowedCharacterSet -- (instancetype)init -{ - self = [super init]; - - @try { - _characterSet = - [[OFCharacterSet URIPathAllowedCharacterSet] retain]; - _characterIsMember = (bool (*)(id, SEL, OFUnichar)) - [_characterSet methodForSelector: - @selector(characterIsMember:)]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_characterSet release]; - - [super dealloc]; -} - -- (bool)characterIsMember: (OFUnichar)character -{ - return (character != '!' && _characterIsMember(_characterSet, - @selector(characterIsMember:), character)); -} -@end - -OFURI * -OFArchiveURIHandlerURIForFileInArchive(OFString *scheme, - OFString *pathInArchive, OFURI *archiveURI) -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - OFMutableURI *ret = [OFMutableURI URIWithScheme: scheme]; - void *pool = objc_autoreleasePoolPush(); - OFString *archiveURIString; - - OFOnce(&onceControl, initPathAllowedCharacters); - - pathInArchive = [pathInArchive - stringByAddingPercentEncodingWithAllowedCharacters: - pathAllowedCharacters]; - archiveURIString = [archiveURI.string - stringByAddingPercentEncodingWithAllowedCharacters: - pathAllowedCharacters]; - - ret.percentEncodedPath = [OFString - stringWithFormat: @"%@!%@", archiveURIString, pathInArchive]; - [ret makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return ret; -} Index: src/OFArray+Private.h ================================================================== --- src/OFArray+Private.h +++ src/OFArray+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,11 +23,10 @@ #include #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" -#import "OFSerialization.h" #import "OFJSONRepresentation.h" #import "OFMessagePackRepresentation.h" OF_ASSUME_NONNULL_BEGIN @@ -100,11 +99,11 @@ * @brief An abstract class for storing objects in an array. * * @note Subclasses must implement @ref count and @ref objectAtIndex:. */ @interface OFArray OF_GENERIC(ObjectType): OFObject #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif /** @@ -403,10 +402,24 @@ */ - (OFArray OF_GENERIC(ObjectType) *) sortedArrayUsingSelector: (SEL)selector options: (OFArraySortOptions)options; +/** + * @brief Returns a copy of the array sorted using the specified function and + * options. + * + * @param compare The function to use to sort the array + * @param context Context passed to the function to compare + * @param options The options to use when sorting the array + * @return A sorted copy of the array + */ +- (OFArray OF_GENERIC(ObjectType) *) + sortedArrayUsingFunction: (OFCompareFunction)compare + context: (nullable void *)context + options: (OFArraySortOptions)options; + #ifdef OF_HAVE_BLOCKS /** * @brief Returns a copy of the array sorted using the specified selector and * options. * Index: src/OFArray.m ================================================================== --- src/OFArray.m +++ src/OFArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,11 +23,10 @@ #import "OFAdjacentArray.h" #import "OFData.h" #import "OFNull.h" #import "OFString.h" #import "OFSubarray.h" -#import "OFXMLElement.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" @@ -85,15 +84,10 @@ { return (id)[[OFAdjacentArray alloc] initWithObjects: objects count: count]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFAdjacentArray alloc] initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -212,15 +206,10 @@ } - (instancetype)initWithObjects: (id const *)objects count: (size_t)count { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ OF_INVALID_INIT_METHOD } - (size_t)count { @@ -546,37 +535,10 @@ [ret makeImmutable]; return [ret autorelease]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - if ([self isKindOfClass: [OFMutableArray class]]) - element = [OFXMLElement elementWithName: @"OFMutableArray" - namespace: OFSerializationNS]; - else - element = [OFXMLElement elementWithName: @"OFArray" - namespace: OFSerializationNS]; - - for (id object in self) { - void *pool2 = objc_autoreleasePoolPush(); - - [element addChild: object.XMLElementBySerializing]; - - objc_autoreleasePoolPop(pool2); - } - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } @@ -723,10 +685,20 @@ OFMutableArray *new = [[self mutableCopy] autorelease]; [new sortUsingSelector: selector options: options]; [new makeImmutable]; return new; } + +- (OFArray *)sortedArrayUsingFunction: (OFCompareFunction)compare + context: (void *)context + options: (OFArraySortOptions)options +{ + OFMutableArray *new = [[self mutableCopy] autorelease]; + [new sortUsingFunction: compare context: context options: options]; + [new makeImmutable]; + return new; +} #ifdef OF_HAVE_BLOCKS - (OFArray *)sortedArrayUsingComparator: (OFComparator)comparator options: (OFArraySortOptions)options { Index: src/OFAsyncIPSocketConnector.h ================================================================== --- src/OFAsyncIPSocketConnector.h +++ src/OFAsyncIPSocketConnector.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFAsyncIPSocketConnector.m ================================================================== --- src/OFAsyncIPSocketConnector.m +++ src/OFAsyncIPSocketConnector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFAtomic.h ================================================================== --- src/OFAtomic.h +++ src/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -167,11 +167,11 @@ static OF_INLINE void OFReleaseMemoryBarrier(void) { /* nop */ } -#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +#elif (defined(OF_AMD64) || defined(OF_X86)) && defined(__GNUC__) # import "platform/x86/OFAtomic.h" #elif defined(OF_POWERPC) && defined(__GNUC__) && !defined(__APPLE_CC__) && \ !defined(OF_AIX) # import "platform/PowerPC/OFAtomic.h" #elif defined(OF_HAVE_ATOMIC_BUILTINS) Index: src/OFBase64.h ================================================================== --- src/OFBase64.h +++ src/OFBase64.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBase64.m ================================================================== --- src/OFBase64.m +++ src/OFBase64.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBitSetCharacterSet.h ================================================================== --- src/OFBitSetCharacterSet.h +++ src/OFBitSetCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBitSetCharacterSet.m ================================================================== --- src/OFBitSetCharacterSet.m +++ src/OFBitSetCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBlock.h ================================================================== --- src/OFBlock.h +++ src/OFBlock.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBlock.m ================================================================== --- src/OFBlock.m +++ src/OFBlock.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBytesValue.h ================================================================== --- src/OFBytesValue.h +++ src/OFBytesValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFBytesValue.m ================================================================== --- src/OFBytesValue.m +++ src/OFBytesValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCRC16.h ================================================================== --- src/OFCRC16.h +++ src/OFCRC16.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCRC16.m ================================================================== --- src/OFCRC16.m +++ src/OFCRC16.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCRC32.h ================================================================== --- src/OFCRC32.h +++ src/OFCRC32.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCRC32.m ================================================================== --- src/OFCRC32.m +++ src/OFCRC32.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCharacterSet.h ================================================================== --- src/OFCharacterSet.h +++ src/OFCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCharacterSet.m ================================================================== --- src/OFCharacterSet.m +++ src/OFCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCollection.h ================================================================== --- src/OFCollection.h +++ src/OFCollection.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFColor.h ================================================================== --- src/OFColor.h +++ src/OFColor.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,27 +12,151 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFColor.h" #import "OFOnce.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" + +@interface OFColor () ++ (instancetype)of_alloc; +@end + +@interface OFColorSingleton: OFColor +@end + +@interface OFColorPlaceholder: OFColorSingleton +@end + +#ifdef OF_OBJFW_RUNTIME +@interface OFTaggedPointerColor: OFColorSingleton +@end + +static const float allowedImprecision = 0.0000001; +#endif + +static struct { + Class isa; +} placeholder; + +#ifdef OF_OBJFW_RUNTIME +static int colorTag; +#endif + +@implementation OFColorSingleton +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OFMaxRetainCount; +} +@end + +@implementation OFColorPlaceholder +- (instancetype)initWithRed: (float)red + green: (float)green + blue: (float)blue + alpha: (float)alpha +{ +#ifdef OF_OBJFW_RUNTIME + uint8_t redInt = nearbyintf(red * 255); + uint8_t greenInt = nearbyintf(green * 255); + uint8_t blueInt = nearbyintf(blue * 255); + + if (fabsf(red * 255 - redInt) < allowedImprecision && + fabsf(green * 255 - greenInt) < allowedImprecision && + fabsf(blue * 255 - blueInt) < allowedImprecision && alpha == 1) { + id ret = objc_createTaggedPointer(colorTag, + (uintptr_t)redInt << 16 | (uintptr_t)greenInt << 8 | + (uintptr_t)blueInt); + + if (ret != nil) + return ret; + } +#endif + + return (id)[[OFColor of_alloc] initWithRed: red + green: green + blue: blue + alpha: alpha]; +} +@end + +#ifdef OF_OBJFW_RUNTIME +@implementation OFTaggedPointerColor +- (void)getRed: (float *)red + green: (float *)green + blue: (float *)blue + alpha: (float *)alpha +{ + uintptr_t value = object_getTaggedPointerValue(self); + + *red = (float)(value >> 16) / 255; + *green = (float)((value >> 8) & 0xFF) / 255; + *blue = (float)(value & 0xFF) / 255; + + if (alpha != NULL) + *alpha = 1; +} +@end +#endif @implementation OFColor ++ (void)initialize +{ + if (self != [OFColor class]) + return; + + placeholder.isa = [OFColorPlaceholder class]; +#ifdef OF_OBJFW_RUNTIME + colorTag = + objc_registerTaggedPointerClass([OFTaggedPointerColor class]); +#endif +} + ++ (instancetype)of_alloc +{ + return [super alloc]; +} + ++ (instancetype)alloc +{ + if (self == [OFColor class]) + return (id)&placeholder; + + return [super alloc]; +} + #define PREDEFINED_COLOR(name, redValue, greenValue, blueValue) \ static OFColor *name##Color = nil; \ \ static void \ initPredefinedColor_##name(void) \ { \ - name##Color = [[OFColor alloc] initWithRed: redValue \ - green: greenValue \ - blue: blueValue \ - alpha: 1]; \ + name##Color = [[OFColorSingleton alloc] \ + initWithRed: redValue \ + green: greenValue \ + blue: blueValue \ + alpha: 1]; \ } \ \ + (OFColor *)name \ { \ static OFOnceControl onceControl = OFOnceControlInitValue; \ @@ -157,6 +281,17 @@ *blue = _blue; if (alpha != NULL) *alpha = _alpha; } + +- (OFString *)description +{ + float red, green, blue, alpha; + + [self getRed: &red green: &green blue: &blue alpha: &alpha]; + + return [OFString stringWithFormat: + @"<%@ red=%f green=%f blue=%f alpha=%f>", + self.class, red, green, blue, alpha]; +} @end Index: src/OFCondition.h ================================================================== --- src/OFCondition.h +++ src/OFCondition.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCondition.m ================================================================== --- src/OFCondition.m +++ src/OFCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFConstantString.h ================================================================== --- src/OFConstantString.h +++ src/OFConstantString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -583,20 +583,20 @@ [self finishInitialization]; [self writeToFile: path encoding: encoding]; } #endif -- (void)writeToURI: (OFURI *)URI +- (void)writeToIRI: (OFIRI *)IRI { [self finishInitialization]; - [self writeToURI: URI]; + [self writeToIRI: IRI]; } -- (void)writeToURI: (OFURI *)URI encoding: (OFStringEncoding)encoding +- (void)writeToIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { [self finishInitialization]; - [self writeToURI: URI encoding: encoding]; + [self writeToIRI: IRI encoding: encoding]; } #ifdef OF_HAVE_BLOCKS - (void)enumerateLinesUsingBlock: (OFStringLineEnumerationBlock)block { Index: src/OFCountedMapTableSet.h ================================================================== --- src/OFCountedMapTableSet.h +++ src/OFCountedMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCountedMapTableSet.m ================================================================== --- src/OFCountedMapTableSet.m +++ src/OFCountedMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,11 +19,10 @@ #import "OFArray.h" #import "OFMapTable.h" #import "OFMutableMapTableSet.h" #import "OFString.h" #import "OFXMLAttribute.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFEnumerationMutationException.h" #import "OFOutOfRangeException.h" @@ -112,56 +111,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [self init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: @"OFCountedSet"] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - for (OFXMLElement *objectElement in - [element elementsForName: @"object" - namespace: OFSerializationNS]) { - void *pool2 = objc_autoreleasePoolPush(); - OFXMLElement *object; - OFXMLAttribute *countAttribute; - unsigned long long count; - - object = [objectElement elementsForNamespace: - OFSerializationNS].firstObject; - countAttribute = - [objectElement attributeForName: @"count"]; - - if (object == nil || countAttribute == nil) - @throw [OFInvalidFormatException exception]; - - count = countAttribute.unsignedLongLongValue; - if (count > SIZE_MAX || count > UINTPTR_MAX) - @throw [OFOutOfRangeException exception]; - - [_mapTable setObject: (void *)(uintptr_t)count - forKey: object.objectByDeserializing]; - - objc_autoreleasePoolPop(pool2); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (size_t)countForObject: (id)object { Index: src/OFCountedSet.h ================================================================== --- src/OFCountedSet.h +++ src/OFCountedSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFCountedSet.m ================================================================== --- src/OFCountedSet.m +++ src/OFCountedSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,11 +19,10 @@ #import "OFCountedSet.h" #import "OFCountedMapTableSet.h" #import "OFNumber.h" #import "OFString.h" -#import "OFXMLElement.h" static struct { Class isa; } placeholder; @@ -69,16 +68,10 @@ { return (id)[[OFCountedMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFCountedMapTableSet alloc] - initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -175,46 +168,10 @@ - (id)mutableCopy { return [[OFCountedSet alloc] initWithSet: self]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: @"OFCountedSet" - namespace: OFSerializationNS]; - - for (id object in self) { - void *pool2 = objc_autoreleasePoolPush(); - - OFXMLElement *objectElement; - OFString *count; - - count = - [OFString stringWithFormat: @"%zu", - [self countForObject: object]]; - - objectElement = [OFXMLElement - elementWithName: @"object" - namespace: OFSerializationNS]; - [objectElement addAttributeWithName: @"count" - stringValue: count]; - [objectElement addChild: object.XMLElementBySerializing]; - [element addChild: objectElement]; - - objc_autoreleasePoolPop(pool2); - } - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - #ifdef OF_HAVE_BLOCKS - (void)enumerateObjectsAndCountUsingBlock: (OFCountedSetEnumerationBlock)block { [self enumerateObjectsUsingBlock: ^ (id object, bool *stop) { block(object, [self countForObject: object], stop); Index: src/OFCryptographicHash.h ================================================================== --- src/OFCryptographicHash.h +++ src/OFCryptographicHash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDDPSocket.h ================================================================== --- src/OFDDPSocket.h +++ src/OFDDPSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,10 +16,11 @@ #import "OFDatagramSocket.h" OF_ASSUME_NONNULL_BEGIN @class OFString; +@class OFDictionary OF_GENERIC(KeyType, ObjectType); /** * @protocol OFDDPSocketDelegate OFDDPSocket.h ObjFW/OFDDPSocket.h * * @brief A delegate for OFDDPSocket. @@ -41,11 +42,11 @@ * socket number). * * @note On some systems, packets received with the wrong protocol type just * get filtered by the kernel, however, on other systems, the packet is * queued up and will raise an @ref OFReadFailedException with the - * @ref errNo set to `ENOMSG` when being received. + * @ref OFReadFailedException#errNo set to `ENOMSG` when being received. * * @warning Even though the OFCopying protocol is implemented, it does *not* * return an independent copy of the socket, but instead retains it. * This is so that the socket can be used as a key for a dictionary, * so context can be associated with a socket. Using a socket in more @@ -79,14 +80,14 @@ * @param protocolType The DDP protocol type to use. Must not be 0. If you want * to use DDP directly and not a protocol built on top of * it, use 11 for compatibility with Open Transport. * @return The address on which this socket can be reached * @throw OFBindDDPSockeFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @throw OFAlreadyOpenException The socket is already bound */ - (OFSocketAddress)bindToNetwork: (uint16_t)network node: (uint8_t)node port: (uint8_t)port protocolType: (uint8_t)protocolType; @end OF_ASSUME_NONNULL_END Index: src/OFDDPSocket.m ================================================================== --- src/OFDDPSocket.m +++ src/OFDDPSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,19 +20,32 @@ #ifdef HAVE_FCNTL_H # include #endif #import "OFDDPSocket.h" +#import "OFDictionary.h" +#import "OFNumber.h" +#import "OFPair.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindDDPSocketFailedException.h" +#import "OFGetOptionFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" +#import "OFOutOfRangeException.h" #import "OFReadFailedException.h" +#import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" + +#ifdef HAVE_NET_IF_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #ifdef OF_HAVE_NETAT_APPLETALK_H # include # include @@ -65,11 +78,11 @@ if (protocolType == 0) @throw [OFInvalidArgumentException exception]; if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeAppleTalk(network, node, port); #if defined(OF_MACOS) if ((_socket = socket(address.sockaddr.at.sat_family, Index: src/OFDNSQuery.h ================================================================== --- src/OFDNSQuery.h +++ src/OFDNSQuery.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDNSQuery.m ================================================================== --- src/OFDNSQuery.m +++ src/OFDNSQuery.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -41,11 +41,11 @@ void *pool = objc_autoreleasePoolPush(); if (![domainName hasSuffix: @"."]) domainName = [domainName stringByAppendingString: @"."]; - _domainName = [domainName copy]; + _domainName = [domainName.lowercaseString copy]; _DNSClass = DNSClass; _recordType = recordType; objc_autoreleasePoolPop(pool); } @catch (id e) { Index: src/OFDNSResolver.h ================================================================== --- src/OFDNSResolver.h +++ src/OFDNSResolver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -178,13 +178,13 @@ * @brief The minimum number of dots for a name to be considered absolute. */ @property (nonatomic) unsigned int minNumberOfDotsInAbsoluteName; /** - * @brief Whether the resolver uses TCP to talk to a name server. + * @brief Whether the resolver forces TCP to talk to a name server. */ -@property (nonatomic) bool usesTCP; +@property (nonatomic) bool forcesTCP; /** * @brief The interval in seconds in which the config should be reloaded. * * Setting this to 0 disables config reloading. Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -421,11 +421,11 @@ OFEnumerator OF_GENERIC(OFMutableArray *) *objectEnumerator; OFMutableArray *array; for (uint_fast16_t j = 0; j < count; j++) { OFString *name = parseName(buffer, length, i, - maxAllowedPointers); + maxAllowedPointers).lowercaseString; OFDNSClass DNSClass; OFDNSRecordType recordType; uint32_t TTL; uint16_t dataLength; OFDNSResourceRecord *record; @@ -676,18 +676,18 @@ { _settings->_minNumberOfDotsInAbsoluteName = minNumberOfDotsInAbsoluteName; } -- (bool)usesTCP +- (bool)forcesTCP { - return _settings->_usesTCP; + return _settings->_forcesTCP; } -- (void)setUsesTCP: (bool)usesTCP +- (void)setForcesTCP: (bool)forcesTCP { - _settings->_usesTCP = usesTCP; + _settings->_forcesTCP = forcesTCP; } - (OFTimeInterval)configReloadInterval { return _settings->_configReloadInterval; @@ -721,11 +721,11 @@ forMode: runLoopMode]; nameServer = [context->_settings->_nameServers objectAtIndex: context->_nameServersIndex]; - if (context->_settings->_usesTCP) { + if (context->_settings->_forcesTCP) { OFEnsure(context->_TCPSocket == nil); context->_TCPSocket = [[OFTCPSocket alloc] init]; [_TCPQueries setObject: context forKey: context->_TCPSocket]; @@ -946,14 +946,14 @@ /* TC */ if (buffer[2] & 0x02) { OFRunLoopMode runLoopMode; - if (context->_settings->_usesTCP) + if (context->_settings->_forcesTCP) @throw [OFTruncatedDataException exception]; - context->_settings->_usesTCP = true; + context->_settings->_forcesTCP = true; runLoopMode = [OFRunLoop currentRunLoop].currentMode; [self of_sendQueryForContext: context runLoopMode: runLoopMode]; return false; } Index: src/OFDNSResolverSettings.h ================================================================== --- src/OFDNSResolverSettings.h +++ src/OFDNSResolverSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -29,15 +29,15 @@ OFArray OF_GENERIC(OFString *) *_nameServers; OFString *_Nullable _localDomain; OFArray OF_GENERIC(OFString *) *_searchDomains; OFTimeInterval _timeout; unsigned int _maxAttempts, _minNumberOfDotsInAbsoluteName; - bool _usesTCP; + bool _forcesTCP; OFTimeInterval _configReloadInterval; @protected OFDate *_lastConfigReload; } - (void)reload; @end OF_ASSUME_NONNULL_END Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -30,12 +30,16 @@ # import "OFWindowsRegistryKey.h" #endif #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" +#ifdef OF_WINDOWS +# import "OFOpenWindowsRegistryKeyFailedException.h" +#endif #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" +#import "OFUndefinedKeyException.h" #ifdef OF_WINDOWS # define interface struct # include # undef interface @@ -211,11 +215,11 @@ copy->_searchDomains = [_searchDomains copy]; copy->_timeout = _timeout; copy->_maxAttempts = _maxAttempts; copy->_minNumberOfDotsInAbsoluteName = _minNumberOfDotsInAbsoluteName; - copy->_usesTCP = _usesTCP; + copy->_forcesTCP = _forcesTCP; copy->_configReloadInterval = _configReloadInterval; copy->_lastConfigReload = [_lastConfigReload copy]; } @catch (id e) { [copy release]; @throw e; @@ -239,11 +243,11 @@ _searchDomains = nil; _timeout = 2; _maxAttempts = 3; _minNumberOfDotsInAbsoluteName = 1; - _usesTCP = false; + _forcesTCP = false; #ifndef OF_NINTENDO_3DS _configReloadInterval = 2; #else _configReloadInterval = 0; #endif @@ -288,12 +292,14 @@ address = components.firstObject; hosts = [components objectsInRange: OFMakeRange(1, components.count - 1)]; for (OFString *host in hosts) { - OFMutableArray *addresses = - [staticHosts objectForKey: host]; + OFMutableArray *addresses; + + host = host.lowercaseString; + addresses = [staticHosts objectForKey: host]; if (addresses == nil) { addresses = [OFMutableArray array]; [staticHosts setObject: addresses forKey: host]; } @@ -341,11 +347,11 @@ } else if ([option hasPrefix: @"reload-period:"]) { option = [option substringFromIndex: 14]; _configReloadInterval = option.unsignedLongLongValue; } else if ([option isEqual: @"tcp"]) - _usesTCP = true; + _forcesTCP = true; } @catch (OFInvalidFormatException *e) { } } - (void)parseResolvConf: (OFString *)path @@ -445,14 +451,19 @@ if (GetNetworkParams(fixedInfo, &length) != ERROR_SUCCESS) return; nameServers = [OFMutableArray array]; - for (iter = &fixedInfo->DnsServerList; iter != NULL; iter = iter->Next) - [nameServers addObject: + for (iter = &fixedInfo->DnsServerList; iter != NULL; + iter = iter->Next) { + OFString *nameServer = [OFString stringWithCString: iter->IpAddress.String - encoding: encoding]]; + encoding: encoding]; + + if (nameServer.length > 0) + [nameServers addObject: nameServer]; + } if (nameServers.count > 0) { [nameServers makeImmutable]; _nameServers = [nameServers copy]; } @@ -491,12 +502,14 @@ address = components.firstObject; hosts = [components objectsInRange: OFMakeRange(1, components.count - 1)]; for (OFString *host in hosts) { - OFMutableArray *addresses = - [staticHosts objectForKey: host]; + OFMutableArray *addresses; + + host = host.lowercaseString; + addresses = [staticHosts objectForKey: host]; if (addresses == nil) { addresses = [OFMutableArray array]; [staticHosts setObject: addresses forKey: host]; } @@ -600,14 +613,14 @@ } #endif - (void)reload { - void *pool; #ifdef OF_WINDOWS - OFString *path; + OFString *path = nil; #endif + void *pool; /* * TODO: Rather than reparsing every time, check what actually changed * (mtime) and only reset those. */ @@ -620,18 +633,26 @@ [self setDefaults]; #if defined(OF_WINDOWS) # ifdef OF_HAVE_FILES - OFWindowsRegistryKey *key = [[OFWindowsRegistryKey localMachineKey] - openSubkeyAtPath: @"SYSTEM\\CurrentControlSet\\Services\\" - @"Tcpip\\Parameters" - accessRights: KEY_QUERY_VALUE - options: 0]; - path = [[[key stringForValueNamed: @"DataBasePath"] - stringByAppendingPathComponent: @"hosts"] - stringByExpandingWindowsEnvironmentStrings]; + @try { + OFWindowsRegistryKey *key; + + key = [[OFWindowsRegistryKey localMachineKey] + openSubkeyAtPath: @"SYSTEM\\CurrentControlSet\\Services\\" + @"Tcpip\\Parameters" + accessRights: KEY_QUERY_VALUE + options: 0]; + path = [[[key stringForValueNamed: @"DataBasePath"] + stringByAppendingPathComponent: @"hosts"] + stringByExpandingWindowsEnvironmentStrings]; + } @catch (OFOpenWindowsRegistryKeyFailedException *e) { + /* Ignore */ + } @catch (OFUndefinedKeyException *e) { + /* Ignore */ + } if (path != nil) [self parseHosts: path]; # endif Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDNSResponse.h ================================================================== --- src/OFDNSResponse.h +++ src/OFDNSResponse.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDNSResponse.m ================================================================== --- src/OFDNSResponse.m +++ src/OFDNSResponse.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFData+CryptographicHashing.h ================================================================== --- src/OFData+CryptographicHashing.h +++ src/OFData+CryptographicHashing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFData+CryptographicHashing.m ================================================================== --- src/OFData+CryptographicHashing.m +++ src/OFData+CryptographicHashing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFData+MessagePackParsing.h ================================================================== --- src/OFData+MessagePackParsing.h +++ src/OFData+MessagePackParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFData+MessagePackParsing.m ================================================================== --- src/OFData+MessagePackParsing.m +++ src/OFData+MessagePackParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,19 +12,18 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFSerialization.h" #import "OFMessagePackRepresentation.h" /*! @file */ OF_ASSUME_NONNULL_BEGIN +@class OFIRI; @class OFString; -@class OFURI; /** * @brief Options for searching in data. * * This is a bit mask. @@ -36,16 +35,13 @@ /** * @class OFData OFData.h ObjFW/OFData.h * * @brief A class for storing arbitrary data in an array. - * - * For security reasons, serialization and deserialization is only implemented - * for OFData with item size 1. */ @interface OFData: OFObject + OFMessagePackRepresentation> { unsigned char *_Nullable _items; size_t _count, _itemSize; bool _freeWhenDone; @private @@ -165,16 +161,16 @@ + (instancetype)dataWithContentsOfFile: (OFString *)path; #endif /** * @brief Creates a new OFData with an item size of 1, containing the data of - * the specified URI. + * the specified IRI. * - * @param URI The URI to the contents for the OFData + * @param IRI The IRI to the contents for the OFData * @return A new autoreleased OFData */ -+ (instancetype)dataWithContentsOfURI: (OFURI *)URI; ++ (instancetype)dataWithContentsOfIRI: (OFIRI *)IRI; /** * @brief Creates a new OFData with an item size of 1, containing the data of * the hex string representation. * @@ -268,16 +264,16 @@ - (instancetype)initWithContentsOfFile: (OFString *)path; #endif /** * @brief Initializes an already allocated OFData with an item size of 1, - * containing the data of the specified URI. + * containing the data of the specified IRI. * - * @param URI The URI to the contents for the OFData + * @param IRI The IRI to the contents for the OFData * @return A new autoreleased OFData */ -- (instancetype)initWithContentsOfURI: (OFURI *)URI; +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI; /** * @brief Initializes an already allocated OFData with an item size of 1, * containing the data of the hex string representation. * @@ -344,17 +340,17 @@ */ - (void)writeToFile: (OFString *)path; #endif /** - * @brief Writes the OFData to the specified URI. + * @brief Writes the OFData to the specified IRI. * - * @param URI The URI to write to + * @param IRI The IRI to write to */ -- (void)writeToURI: (OFURI *)URI; +- (void)writeToIRI: (OFIRI *)IRI; @end OF_ASSUME_NONNULL_END #import "OFMutableData.h" #import "OFData+CryptographicHashing.h" #import "OFData+MessagePackParsing.h" Index: src/OFData.m ================================================================== --- src/OFData.m +++ src/OFData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,16 +24,15 @@ #import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" # import "OFFileManager.h" #endif +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFStream.h" #import "OFString.h" #import "OFSystemInfo.h" -#import "OFURI.h" -#import "OFURIHandler.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFOutOfMemoryException.h" @@ -91,13 +90,13 @@ { return [[[self alloc] initWithContentsOfFile: path] autorelease]; } #endif -+ (instancetype)dataWithContentsOfURI: (OFURI *)URI ++ (instancetype)dataWithContentsOfIRI: (OFIRI *)IRI { - return [[[self alloc] initWithContentsOfURI: URI] autorelease]; + return [[[self alloc] initWithContentsOfIRI: IRI] autorelease]; } + (instancetype)dataWithStringRepresentation: (OFString *)string { return [[[self alloc] @@ -209,17 +208,17 @@ return self; } #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); - OFStream *stream = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFStream *stream = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; size_t pageSize; unsigned char *buffer; _count = 0; _itemSize = 1; @@ -332,33 +331,10 @@ } if (!mutable) [(OFMutableData *)self makeImmutable]; - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool = objc_autoreleasePoolPush(); - OFString *stringValue; - - @try { - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - stringValue = element.stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithBase64EncodedString: stringValue]; - - objc_autoreleasePoolPop(pool); - return self; } - (void)dealloc { @@ -585,39 +561,17 @@ [file release]; } } #endif -- (void)writeToURI: (OFURI *)URI +- (void)writeToIRI: (OFIRI *)IRI { void *pool = objc_autoreleasePoolPush(); - [[OFURIHandler openItemAtURI: URI mode: @"w"] writeData: self]; - - objc_autoreleasePoolPop(pool); -} - -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool; - OFXMLElement *element; - - if (_itemSize != 1) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; - - pool = objc_autoreleasePoolPush(); - element = [OFXMLElement - elementWithName: self.className - namespace: OFSerializationNS - stringValue: OFBase64Encode(_items, _count * _itemSize)]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; + [[OFIRIHandler openItemAtIRI: IRI mode: @"w"] writeData: self]; + + objc_autoreleasePoolPop(pool); } - (OFData *)messagePackRepresentation { OFMutableData *data; Index: src/OFDatagramSocket.h ================================================================== --- src/OFDatagramSocket.h +++ src/OFDatagramSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDatagramSocket.m ================================================================== --- src/OFDatagramSocket.m +++ src/OFDatagramSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -13,11 +13,10 @@ * file. */ #import "OFObject.h" #import "OFMessagePackRepresentation.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN @class OFString; @class OFConstantString; @@ -28,11 +27,11 @@ * @brief A class for storing, accessing and comparing dates. */ #ifndef OF_DATE_M OF_SUBCLASSING_RESTRICTED #endif -@interface OFDate: OFObject { OFTimeInterval _seconds; } Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -32,11 +32,10 @@ #endif #import "OFStrPTime.h" #import "OFString.h" #import "OFSystemInfo.h" #import "OFXMLAttribute.h" -#import "OFXMLElement.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" @@ -494,43 +493,10 @@ objc_autoreleasePoolPop(pool); return [self initWithTimeIntervalSince1970: seconds]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - OFTimeInterval seconds; - - @try { - void *pool = objc_autoreleasePoolPush(); - unsigned long long value; - - if (![element.name isEqual: @"OFDate"] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - if (![[element attributeForName: @"encoding"].stringValue - isEqual: @"hex"]) - @throw [OFInvalidFormatException exception]; - - value = [element unsignedLongLongValueWithBase: 16]; - - if (value > UINT64_MAX) - @throw [OFOutOfRangeException exception]; - - seconds = OFFromBigEndianDouble(OFRawUInt64ToDouble( - OFToBigEndian64(value))); - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return [self initWithTimeIntervalSince1970: seconds]; -} - - (bool)isEqual: (id)object { OFDate *otherDate; if (object == self) @@ -585,30 +551,10 @@ - (OFString *)description { return [self dateStringWithFormat: @"%Y-%m-%dT%H:%M:%SZ"]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: @"OFDate" - namespace: OFSerializationNS]; - - [element addAttributeWithName: @"encoding" stringValue: @"hex"]; - element.stringValue = [OFString stringWithFormat: @"%016" PRIx64, - OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( - self.timeIntervalSince1970)))]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFData *)messagePackRepresentation { void *pool = objc_autoreleasePoolPush(); OFTimeInterval timeInterval = self.timeIntervalSince1970; int64_t seconds = (int64_t)timeInterval; Index: src/OFDictionary.h ================================================================== --- src/OFDictionary.h +++ src/OFDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,11 +23,10 @@ #include #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" -#import "OFSerialization.h" #import "OFJSONRepresentation.h" #import "OFMessagePackRepresentation.h" OF_ASSUME_NONNULL_BEGIN @@ -75,11 +74,11 @@ * * @note Subclasses must implement @ref objectForKey:, @ref count and * @ref keyEnumerator. */ @interface OFDictionary OF_GENERIC(KeyType, ObjectType): OFObject #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define KeyType id # define ObjectType id #endif Index: src/OFDictionary.m ================================================================== --- src/OFDictionary.m +++ src/OFDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,22 +22,19 @@ #import "OFCharacterSet.h" #import "OFData.h" #import "OFEnumerator.h" #import "OFMapTableDictionary.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" #import "OFUndefinedKeyException.h" static struct { Class isa; } placeholder; -static OFCharacterSet *URIQueryPartAllowedCharacterSet = nil; - @interface OFDictionary () - (OFString *) of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth; @end @@ -53,15 +50,10 @@ } - (instancetype)initWithDictionary: (OFDictionary *)dictionary; @end -OF_DIRECT_MEMBERS -@interface OFURIQueryPartAllowedCharacterSet: OFCharacterSet -+ (OFCharacterSet *)URIQueryPartAllowedCharacterSet; -@end - @implementation OFDictionaryPlaceholder - (instancetype)init { return (id)[[OFMapTableDictionary alloc] init]; } @@ -111,16 +103,10 @@ { return (id)[[OFMapTableDictionary alloc] initWithKey: firstKey arguments: arguments]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMapTableDictionary alloc] - initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -135,70 +121,10 @@ - (void)dealloc { OF_DEALLOC_UNSUPPORTED } -@end - -@implementation OFURIQueryPartAllowedCharacterSet -+ (void)initialize -{ - if (self != [OFURIQueryPartAllowedCharacterSet class]) - return; - - URIQueryPartAllowedCharacterSet = - [[OFURIQueryPartAllowedCharacterSet alloc] init]; -} - -+ (OFCharacterSet *)URIQueryPartAllowedCharacterSet -{ - return URIQueryPartAllowedCharacterSet; -} - -- (instancetype)autorelease -{ - return self; -} - -- (instancetype)retain -{ - return self; -} - -- (void)release -{ -} - -- (unsigned int)retainCount -{ - return OFMaxRetainCount; -} - -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - return true; - default: - return false; - } -} @end @implementation OFDictionary + (void)initialize { @@ -328,15 +254,10 @@ return ret; } - (instancetype)initWithKey: (id)firstKey arguments: (va_list)arguments { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ OF_INVALID_INIT_METHOD } - (id)objectForKey: (id)key { @@ -635,54 +556,10 @@ objc_autoreleasePoolPop(pool); return ret; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - OFEnumerator *keyEnumerator, *objectEnumerator; - id key, object; - - if ([self isKindOfClass: [OFMutableDictionary class]]) - element = [OFXMLElement elementWithName: @"OFMutableDictionary" - namespace: OFSerializationNS]; - else - element = [OFXMLElement elementWithName: @"OFDictionary" - namespace: OFSerializationNS]; - - keyEnumerator = [self keyEnumerator]; - objectEnumerator = [self objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); - OFXMLElement *keyElement, *objectElement; - - keyElement = [OFXMLElement - elementWithName: @"key" - namespace: OFSerializationNS]; - [keyElement addChild: key.XMLElementBySerializing]; - - objectElement = [OFXMLElement - elementWithName: @"object" - namespace: OFSerializationNS]; - [objectElement addChild: object.XMLElementBySerializing]; - - [element addChild: keyElement]; - [element addChild: objectElement]; - - objc_autoreleasePoolPop(pool2); - } - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } ADDED src/OFEmbeddedIRIHandler.h Index: src/OFEmbeddedIRIHandler.h ================================================================== --- src/OFEmbeddedIRIHandler.h +++ src/OFEmbeddedIRIHandler.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRIHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFEmbeddedIRIHandler: OFIRIHandler +@end + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Register a file for the `embedded:` IRI scheme. + * + * Usually, you should not use the directly, but rather generate a source file + * for a file to be embedded using the `objfw-embed` tool. + * + * @param path The path to the file under the `embedded:` scheme. This is not + * retained, so you must either pass a constant string or pass a + * string that is already retained! + * @param bytes The raw bytes for the file + * @param size The size of the file + */ +extern void OFRegisterEmbeddedFile(OFString *path, const uint8_t *bytes, + size_t size); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END ADDED src/OFEmbeddedIRIHandler.m Index: src/OFEmbeddedIRIHandler.m ================================================================== --- src/OFEmbeddedIRIHandler.m +++ src/OFEmbeddedIRIHandler.m @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include +#include +#include + +#import "OFEmbeddedIRIHandler.h" +#import "OFIRI.h" +#import "OFMemoryStream.h" + +#import "OFInvalidArgumentException.h" +#import "OFOpenItemFailedException.h" + +#ifdef OF_HAVE_THREADS +# import "OFOnce.h" +# import "OFPlainMutex.h" +#endif + +struct EmbeddedFile { + OFString *path; + const uint8_t *bytes; + size_t size; +} *embeddedFiles = NULL; +size_t numEmbeddedFiles = 0; +#ifdef OF_HAVE_THREADS +static OFPlainMutex mutex; +static OFOnceControl mutexOnceControl = OFOnceControlInitValue; + +static void +initMutex(void) +{ + OFEnsure(OFPlainMutexNew(&mutex) == 0); +} +#endif + +void +OFRegisterEmbeddedFile(OFString *path, const uint8_t *bytes, size_t size) +{ +#ifdef OF_HAVE_THREADS + OFOnce(&mutexOnceControl, initMutex); + + OFEnsure(OFPlainMutexLock(&mutex) == 0); +#endif + + embeddedFiles = realloc(embeddedFiles, + sizeof(*embeddedFiles) * (numEmbeddedFiles + 1)); + OFEnsure(embeddedFiles != NULL); + + embeddedFiles[numEmbeddedFiles].path = path; + embeddedFiles[numEmbeddedFiles].bytes = bytes; + embeddedFiles[numEmbeddedFiles].size = size; + numEmbeddedFiles++; + +#ifdef OF_HAVE_THREADS + OFEnsure(OFPlainMutexUnlock(&mutex) == 0); +#endif +} + +@implementation OFEmbeddedIRIHandler +#ifdef OF_HAVE_THREADS ++ (void)initialize +{ + if (self == [OFEmbeddedIRIHandler class]) + OFOnce(&mutexOnceControl, initMutex); +} +#endif + +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + OFString *path; + + if (![IRI.scheme isEqual: @"embedded"] || IRI.host.length > 0 || + IRI.port != nil || IRI.user != nil || IRI.password != nil || + IRI.query != nil || IRI.fragment != nil) + @throw [OFInvalidArgumentException exception]; + + if (![mode isEqual: @"r"]) + @throw [OFOpenItemFailedException exceptionWithIRI: IRI + mode: mode + errNo: EROFS]; + + if ((path = IRI.path) == nil) { + @throw [OFInvalidArgumentException exception]; + } + +#ifdef OF_HAVE_THREADS + OFEnsure(OFPlainMutexLock(&mutex) == 0); + @try { +#endif + for (size_t i = 0; i < numEmbeddedFiles; i++) { + if (![embeddedFiles[i].path isEqual: path]) + continue; + + return [OFMemoryStream + streamWithMemoryAddress: (void *) + embeddedFiles[i].bytes + size: embeddedFiles[i].size + writable: false]; + } +#ifdef OF_HAVE_THREADS + } @finally { + OFEnsure(OFPlainMutexUnlock(&mutex) == 0); + } +#endif + + @throw [OFOpenItemFailedException exceptionWithIRI: IRI + mode: mode + errNo: ENOENT]; +} +@end DELETED src/OFEmbeddedURIHandler.h Index: src/OFEmbeddedURIHandler.h ================================================================== --- src/OFEmbeddedURIHandler.h +++ src/OFEmbeddedURIHandler.h @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURIHandler.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFEmbeddedURIHandler: OFURIHandler -@end - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief Register a file for the `embedded:` URI scheme. - * - * Usually, you should not use the directly, but rather generate a source file - * for a file to be embedded using the `objfw-embed` tool. - * - * @param path The path to the file under the `embedded:` scheme. This is not - * retained, so you must either pass a constant string or pass a - * string that is already retained! - * @param bytes The raw bytes for the file - * @param size The size of the file - */ -extern void OFRegisterEmbeddedFile(OFString *path, const uint8_t *bytes, - size_t size); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/OFEmbeddedURIHandler.m Index: src/OFEmbeddedURIHandler.m ================================================================== --- src/OFEmbeddedURIHandler.m +++ src/OFEmbeddedURIHandler.m @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include -#include -#include - -#import "OFEmbeddedURIHandler.h" -#import "OFMemoryStream.h" -#import "OFURI.h" - -#import "OFInvalidArgumentException.h" -#import "OFOpenItemFailedException.h" - -#ifdef OF_HAVE_THREADS -# import "OFOnce.h" -# import "OFPlainMutex.h" -#endif - -struct EmbeddedFile { - OFString *path; - const uint8_t *bytes; - size_t size; -} *embeddedFiles = NULL; -size_t numEmbeddedFiles = 0; -#ifdef OF_HAVE_THREADS -static OFPlainMutex mutex; - -static void -init(void) -{ - OFEnsure(OFPlainMutexNew(&mutex) == 0); -} -#endif - -void -OFRegisterEmbeddedFile(OFString *path, const uint8_t *bytes, size_t size) -{ -#ifdef OF_HAVE_THREADS - static OFOnceControl onceControl = OFOnceControlInitValue; - OFOnce(&onceControl, init); - - OFEnsure(OFPlainMutexLock(&mutex) == 0); -#endif - - embeddedFiles = realloc(embeddedFiles, - sizeof(*embeddedFiles) * (numEmbeddedFiles + 1)); - OFEnsure(embeddedFiles != NULL); - - embeddedFiles[numEmbeddedFiles].path = path; - embeddedFiles[numEmbeddedFiles].bytes = bytes; - embeddedFiles[numEmbeddedFiles].size = size; - numEmbeddedFiles++; - -#ifdef OF_HAVE_THREADS - OFEnsure(OFPlainMutexUnlock(&mutex) == 0); -#endif -} - -@implementation OFEmbeddedURIHandler -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - OFString *path; - - if (![URI.scheme isEqual: @"embedded"] || URI.host.length > 0 || - URI.port != nil || URI.user != nil || URI.password != nil || - URI.query != nil || URI.fragment != nil) - @throw [OFInvalidArgumentException exception]; - - if (![mode isEqual: @"r"]) - @throw [OFOpenItemFailedException exceptionWithURI: URI - mode: mode - errNo: EROFS]; - - if ((path = URI.path) == nil) { - @throw [OFInvalidArgumentException exception]; - } - -#ifdef OF_HAVE_THREADS - OFEnsure(OFPlainMutexLock(&mutex) == 0); - @try { -#endif - for (size_t i = 0; i < numEmbeddedFiles; i++) { - if (![embeddedFiles[i].path isEqual: path]) - continue; - - return [OFMemoryStream - streamWithMemoryAddress: (void *) - embeddedFiles[i].bytes - size: embeddedFiles[i].size - writable: false]; - } -#ifdef OF_HAVE_THREADS - } @finally { - OFEnsure(OFPlainMutexUnlock(&mutex) == 0); - } -#endif - - @throw [OFOpenItemFailedException exceptionWithURI: URI - mode: mode - errNo: ENOENT]; -} -@end Index: src/OFEnumerator.h ================================================================== --- src/OFEnumerator.h +++ src/OFEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFEnumerator.m ================================================================== --- src/OFEnumerator.m +++ src/OFEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFEpollKernelEventObserver.h ================================================================== --- src/OFEpollKernelEventObserver.h +++ src/OFEpollKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFEpollKernelEventObserver.m ================================================================== --- src/OFEpollKernelEventObserver.m +++ src/OFEpollKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -25,12 +25,10 @@ static const OFFileHandle OFInvalidFileHandle = NULL; #endif OF_ASSUME_NONNULL_BEGIN -@class OFURI; - /** * @class OFFile OFFile.h ObjFW/OFFile.h * * @brief A class which provides methods to read and write files. */ Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -13,11 +13,13 @@ * file. */ #include "config.h" -#define _LARGEFILE64_SOURCE +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +#endif #include #ifdef HAVE_FCNTL_H # include @@ -30,11 +32,10 @@ #import "OFFile.h" #import "OFLocale.h" #import "OFString.h" #import "OFSystemInfo.h" -#import "OFURI.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotOpenException.h" #import "OFOpenItemFailedException.h" @@ -47,12 +48,14 @@ #ifdef OF_WINDOWS # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include +# undef Class #endif #ifdef OF_WII # include #endif ADDED src/OFFileIRIHandler.h Index: src/OFFileIRIHandler.h ================================================================== --- src/OFFileIRIHandler.h +++ src/OFFileIRIHandler.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRIHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFFileIRIHandler: OFIRIHandler ++ (bool)of_directoryExistsAtPath: (OFString *)path OF_DIRECT; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFFileIRIHandler.m Index: src/OFFileIRIHandler.m ================================================================== --- src/OFFileIRIHandler.m +++ src/OFFileIRIHandler.m @@ -0,0 +1,1679 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +#endif + +#include +#include + +#ifdef HAVE_DIRENT_H +# include +#endif +#include "unistd_wrapper.h" + +#include "platform.h" +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include +#if defined(OF_LINUX) || defined(OF_MACOS) +# include +#endif +#ifdef OF_WINDOWS +# include +#endif +#ifdef OF_DJGPP +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_PWD_H +# include +#endif +#ifdef HAVE_GRP_H +# include +#endif + +#import "OFFileIRIHandler.h" +#import "OFArray.h" +#import "OFData.h" +#import "OFDate.h" +#import "OFFile.h" +#import "OFFileManager.h" +#import "OFIRI.h" +#import "OFLocale.h" +#import "OFNumber.h" +#import "OFSystemInfo.h" + +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif + +#import "OFCreateDirectoryFailedException.h" +#import "OFCreateSymbolicLinkFailedException.h" +#import "OFGetItemAttributesFailedException.h" +#import "OFInitializationFailedException.h" +#import "OFInvalidArgumentException.h" +#import "OFLinkItemFailedException.h" +#import "OFMoveItemFailedException.h" +#import "OFNotImplementedException.h" +#import "OFOpenItemFailedException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" +#import "OFRemoveItemFailedException.h" +#import "OFSetItemAttributesFailedException.h" + +#ifdef OF_WINDOWS +# include +# include +# include +# include +#endif + +#ifdef OF_AMIGAOS +# define Class IntuitionClass +# include +# include +# include +# undef Class +# ifdef OF_AMIGAOS4 +# define DeleteFile(path) Delete(path) +# endif +#endif + +#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) +typedef struct { + OFStreamOffset st_size; + unsigned int st_mode; + OFTimeInterval st_atime, st_mtime, st_ctime; +# ifdef OF_WINDOWS +# define HAVE_STRUCT_STAT_ST_BIRTHTIME + OFTimeInterval st_birthtime; + DWORD fileAttributes; +# endif +} Stat; +#elif defined(HAVE_STAT64) +typedef struct stat64 Stat; +#else +typedef struct stat Stat; +#endif + +#ifdef OF_WINDOWS +# define S_IFLNK 0x10000 +# define S_ISLNK(mode) (mode & S_IFLNK) +#endif + +#if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) +static OFMutex *passwdMutex; + +static void +releasePasswdMutex(void) +{ + [passwdMutex release]; +} +#endif +#if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) && !defined(OF_WINDOWS) +static OFMutex *readdirMutex; + +static void +releaseReaddirMutex(void) +{ + [readdirMutex release]; +} +#endif + +#ifdef OF_WINDOWS +static int (*_wutime64FuncPtr)(const wchar_t *, struct __utimbuf64 *); +static WINAPI BOOLEAN (*createSymbolicLinkWFuncPtr)(LPCWSTR, LPCWSTR, DWORD); +static WINAPI BOOLEAN (*createHardLinkWFuncPtr)(LPCWSTR, LPCWSTR, + LPSECURITY_ATTRIBUTES); +#endif + +#ifdef OF_WINDOWS +static OFTimeInterval +filetimeToTimeInterval(const FILETIME *filetime) +{ + return (double)((int64_t)filetime->dwHighDateTime << 32 | + filetime->dwLowDateTime) / 10000000.0 - 11644473600.0; +} + +static int +lastError(void) +{ + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NO_MORE_FILES: + return ENOENT; + case ERROR_ACCESS_DENIED: + return EACCES; + case ERROR_DIRECTORY: + return ENOTDIR; + case ERROR_NOT_READY: + return EBUSY; + default: + return EIO; + } +} +#endif + +#ifdef OF_AMIGAOS +static int +lastError(void) +{ + switch (IoErr()) { + case ERROR_DELETE_PROTECTED: + case ERROR_READ_PROTECTED: + case ERROR_WRITE_PROTECTED: + return EACCES; + case ERROR_DISK_NOT_VALIDATED: + case ERROR_OBJECT_IN_USE: + return EBUSY; + case ERROR_OBJECT_EXISTS: + return EEXIST; + case ERROR_DIR_NOT_FOUND: + case ERROR_NO_MORE_ENTRIES: + case ERROR_OBJECT_NOT_FOUND: + return ENOENT; + case ERROR_NO_FREE_STORE: + return ENOMEM; + case ERROR_DISK_FULL: + return ENOSPC; + case ERROR_DIRECTORY_NOT_EMPTY: + return ENOTEMPTY; + case ERROR_DISK_WRITE_PROTECTED: + return EROFS; + case ERROR_RENAME_ACROSS_DEVICES: + return EXDEV; + default: + return EIO; + } +} +#endif + +static int +statWrapper(OFString *path, Stat *buffer) +{ +#if defined(OF_WINDOWS) + WIN32_FILE_ATTRIBUTE_DATA data; + bool success; + + if ([OFSystemInfo isWindowsNT]) + success = GetFileAttributesExW(path.UTF16String, + GetFileExInfoStandard, &data); + else + success = GetFileAttributesExA( + [path cStringWithEncoding: [OFLocale encoding]], + GetFileExInfoStandard, &data); + + if (!success) + return lastError(); + + buffer->st_size = (uint64_t)data.nFileSizeHigh << 32 | + data.nFileSizeLow; + + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + buffer->st_mode = S_IFDIR; + else if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + /* + * No need to use A functions in this branch: This is only + * available on NTFS (and hence Windows NT) anyway. + */ + WIN32_FIND_DATAW findData; + HANDLE findHandle; + + if ((findHandle = FindFirstFileW(path.UTF16String, + &findData)) == INVALID_HANDLE_VALUE) + return lastError(); + + @try { + if (!(findData.dwFileAttributes & + FILE_ATTRIBUTE_REPARSE_POINT)) + /* Race? Indicate to try again. */ + return EAGAIN; + + buffer->st_mode = + (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK + ? S_IFLNK : S_IFREG); + } @finally { + FindClose(findHandle); + } + } else + buffer->st_mode = S_IFREG; + + buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY + ? (S_IRUSR | S_IXUSR) : (S_IRUSR | S_IWUSR | S_IXUSR)); + + buffer->st_atime = filetimeToTimeInterval(&data.ftLastAccessTime); + buffer->st_mtime = filetimeToTimeInterval(&data.ftLastWriteTime); + buffer->st_ctime = buffer->st_birthtime = + filetimeToTimeInterval(&data.ftCreationTime); + buffer->fileAttributes = data.dwFileAttributes; + + return 0; +#elif defined(OF_AMIGAOS) + BPTR lock; +# ifdef OF_AMIGAOS4 + struct ExamineData *ed; +# else + struct FileInfoBlock fib; +# endif + OFTimeInterval timeInterval; + struct Locale *locale; + struct DateStamp *date; + + if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], + SHARED_LOCK)) == 0) + return lastError(); + +# if defined(OF_MORPHOS) + if (!Examine64(lock, &fib, TAG_DONE)) { +# elif defined(OF_AMIGAOS4) + if ((ed = ExamineObjectTags(EX_FileLockInput, lock, TAG_END)) == NULL) { +# else + if (!Examine(lock, &fib)) { +# endif + int error = lastError(); + UnLock(lock); + return error; + } + + UnLock(lock); + +# if defined(OF_MORPHOS) + buffer->st_size = fib.fib_Size64; +# elif defined(OF_AMIGAOS4) + buffer->st_size = ed->FileSize; +# else + buffer->st_size = fib.fib_Size; +# endif +# ifdef OF_AMIGAOS4 + buffer->st_mode = (EXD_IS_DIRECTORY(ed) ? S_IFDIR : S_IFREG); +# else + buffer->st_mode = (fib.fib_DirEntryType > 0 ? S_IFDIR : S_IFREG); +# endif + + timeInterval = 252460800; /* 1978-01-01 */ + + locale = OpenLocale(NULL); + /* + * FIXME: This does not take DST into account. But unfortunately, there + * is no way to figure out if DST was in effect when the file was + * modified. + */ + timeInterval += locale->loc_GMTOffset * 60.0; + CloseLocale(locale); + +# ifdef OF_AMIGAOS4 + date = &ed->Date; +# else + date = &fib.fib_Date; +# endif + timeInterval += date->ds_Days * 86400.0; + timeInterval += date->ds_Minute * 60.0; + timeInterval += date->ds_Tick / (OFTimeInterval)TICKS_PER_SECOND; + + buffer->st_atime = buffer->st_mtime = buffer->st_ctime = timeInterval; + +# ifdef OF_AMIGAOS4 + FreeDosObject(DOS_EXAMINEDATA, ed); +# endif + + return 0; +#elif defined(HAVE_STAT64) + if (stat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; + + return 0; +#else + if (stat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; + + return 0; +#endif +} + +static int +lstatWrapper(OFString *path, Stat *buffer) +{ +#if defined(HAVE_LSTAT) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && \ + !defined(OF_NINTENDO_3DS) && !defined(OF_WII) +# ifdef HAVE_LSTAT64 + if (lstat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; +# else + if (lstat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; +# endif + + return 0; +#else + return statWrapper(path, buffer); +#endif +} + +static void +setTypeAttribute(OFMutableFileAttributes attributes, Stat *s) +{ + if (S_ISREG(s->st_mode)) + [attributes setObject: OFFileTypeRegular forKey: OFFileType]; + else if (S_ISDIR(s->st_mode)) + [attributes setObject: OFFileTypeDirectory forKey: OFFileType]; +#ifdef S_ISLNK + else if (S_ISLNK(s->st_mode)) + [attributes setObject: OFFileTypeSymbolicLink + forKey: OFFileType]; +#endif +#ifdef S_ISFIFO + else if (S_ISFIFO(s->st_mode)) + [attributes setObject: OFFileTypeFIFO forKey: OFFileType]; +#endif +#ifdef S_ISCHR + else if (S_ISCHR(s->st_mode)) + [attributes setObject: OFFileTypeCharacterSpecial + forKey: OFFileType]; +#endif +#ifdef S_ISBLK + else if (S_ISBLK(s->st_mode)) + [attributes setObject: OFFileTypeBlockSpecial + forKey: OFFileType]; +#endif +#ifdef S_ISSOCK + else if (S_ISSOCK(s->st_mode)) + [attributes setObject: OFFileTypeSocket forKey: OFFileType]; +#endif + else + [attributes setObject: OFFileTypeUnknown forKey: OFFileType]; +} + +static void +setDateAttributes(OFMutableFileAttributes attributes, Stat *s) +{ + /* FIXME: We could be more precise on some OSes */ + [attributes + setObject: [OFDate dateWithTimeIntervalSince1970: s->st_atime] + forKey: OFFileLastAccessDate]; + [attributes + setObject: [OFDate dateWithTimeIntervalSince1970: s->st_mtime] + forKey: OFFileModificationDate]; + [attributes + setObject: [OFDate dateWithTimeIntervalSince1970: s->st_ctime] + forKey: OFFileStatusChangeDate]; +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + [attributes + setObject: [OFDate dateWithTimeIntervalSince1970: s->st_birthtime] + forKey: OFFileCreationDate]; +#endif +} + +static void +setOwnerAndGroupAttributes(OFMutableFileAttributes attributes, Stat *s) +{ +#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER + [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_uid] + forKey: OFFileOwnerAccountID]; + [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_gid] + forKey: OFFileGroupOwnerAccountID]; + +# ifdef OF_HAVE_THREADS + [passwdMutex lock]; + @try { +# endif + OFStringEncoding encoding = [OFLocale encoding]; + struct passwd *passwd = getpwuid(s->st_uid); + struct group *group_ = getgrgid(s->st_gid); + + if (passwd != NULL) { + OFString *owner = [OFString + stringWithCString: passwd->pw_name + encoding: encoding]; + + [attributes setObject: owner + forKey: OFFileOwnerAccountName]; + } + + if (group_ != NULL) { + OFString *group = [OFString + stringWithCString: group_->gr_name + encoding: encoding]; + + [attributes setObject: group + forKey: OFFileGroupOwnerAccountName]; + } +# ifdef OF_HAVE_THREADS + } @finally { + [passwdMutex unlock]; + } +# endif +#endif +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS +static void +setSymbolicLinkDestinationAttribute(OFMutableFileAttributes attributes, + OFIRI *IRI) +{ + OFString *path = IRI.fileSystemRepresentation; +# ifdef OF_WINDOWS + HANDLE handle; + OFString *destination; + + if (createSymbolicLinkWFuncPtr == NULL) + return; + + if ((handle = CreateFileW(path.UTF16String, 0, (FILE_SHARE_READ | + FILE_SHARE_WRITE), NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, NULL)) == INVALID_HANDLE_VALUE) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: lastError()]; + + @try { + union { + char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER data; + } buffer; + DWORD size; + wchar_t *tmp; + + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, + buffer.bytes, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, + NULL)) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: lastError()]; + + if (buffer.data.ReparseTag != IO_REPARSE_TAG_SYMLINK) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: lastError()]; + +# define slrb buffer.data.SymbolicLinkReparseBuffer + tmp = slrb.PathBuffer + + (slrb.SubstituteNameOffset / sizeof(wchar_t)); + + destination = [OFString + stringWithUTF16String: tmp + length: slrb.SubstituteNameLength / + sizeof(wchar_t)]; + + [attributes setObject: OFFileTypeSymbolicLink + forKey: OFFileType]; + [attributes setObject: destination + forKey: OFFileSymbolicLinkDestination]; +# undef slrb + } @finally { + CloseHandle(handle); + } +# elif defined(OF_HURD) + OFStringEncoding encoding = [OFLocale encoding]; + int fd; + OFMutableData *destinationData; + OFString *destination; + + fd = open([path cStringWithEncoding: encoding], O_RDONLY | O_NOLINK); + if (fd == -1) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: errno]; + + @try { + char buffer[512]; + ssize_t length; + + destinationData = [OFMutableData data]; + while ((length = read(fd, buffer, 512)) > 0) + [destinationData addItems: buffer count: length]; + } @finally { + close(fd); + } + + destination = [OFString stringWithCString: destinationData.items + encoding: encoding + length: destinationData.count]; + + [attributes setObject: destination + forKey: OFFileSymbolicLinkDestination]; +# else + OFStringEncoding encoding = [OFLocale encoding]; + char destinationC[PATH_MAX]; + ssize_t length; + OFString *destination; + + length = readlink([path cStringWithEncoding: encoding], destinationC, + PATH_MAX); + + if (length < 0) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: errno]; + + destination = [OFString stringWithCString: destinationC + encoding: encoding + length: length]; + + [attributes setObject: destination + forKey: OFFileSymbolicLinkDestination]; +# endif +} +#endif + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +static void +setExtendedAttributes(OFMutableFileAttributes attributes, OFIRI *IRI) +{ + OFString *path = IRI.fileSystemRepresentation; + OFStringEncoding encoding = [OFLocale encoding]; + const char *cPath = [path cStringWithEncoding: encoding]; +# if defined(OF_LINUX) + ssize_t size = llistxattr(cPath, NULL, 0); +# elif defined(OF_MACOS) + ssize_t size = listxattr(cPath, NULL, 0, XATTR_NOFOLLOW); +# endif + char *list = OFAllocMemory(1, size); + OFMutableArray *names = nil; + + @try { + char *name; + +# if defined(OF_LINUX) + if ((size = llistxattr(cPath, list, size)) < 0) +# elif defined(OF_MACOS) + if ((size = listxattr(cPath, list, size, XATTR_NOFOLLOW)) < 0) +# endif + return; + + names = [OFMutableArray array]; + name = list; + + while (size > 0) { + size_t length = strlen(name); + + [names addObject: [OFString stringWithCString: name + encoding: encoding + length: length]]; + + name += length + 1; + size -= length + 1; + } + } @finally { + OFFreeMemory(list); + } + + [attributes setObject: names forKey: OFFileExtendedAttributesNames]; +} +#endif + +@implementation OFFileIRIHandler ++ (void)initialize +{ +#ifdef OF_WINDOWS + HMODULE module; +#endif + + if (self != [OFFileIRIHandler class]) + return; + +#if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) + passwdMutex = [[OFMutex alloc] init]; + atexit(releasePasswdMutex); +#endif +#if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) + readdirMutex = [[OFMutex alloc] init]; + atexit(releaseReaddirMutex); +#endif + +#ifdef OF_WINDOWS + if ((module = LoadLibrary("msvcrt.dll")) != NULL) + _wutime64FuncPtr = (int (*)(const wchar_t *, + struct __utimbuf64 *))GetProcAddress(module, "_wutime64"); + + if ((module = LoadLibrary("kernel32.dll")) != NULL) { + createSymbolicLinkWFuncPtr = + (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD)) + GetProcAddress(module, "CreateSymbolicLinkW"); + createHardLinkWFuncPtr = + (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, + LPSECURITY_ATTRIBUTES)) + GetProcAddress(module, "CreateHardLinkW"); + } +#endif + + /* + * Make sure OFFile is initialized. + * On some systems, this is needed to initialize the file system driver. + */ + [OFFile class]; +} + ++ (bool)of_directoryExistsAtPath: (OFString *)path +{ + Stat s; + + if (statWrapper(path, &s) != 0) + return false; + + return S_ISDIR(s.st_mode); +} + +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + void *pool = objc_autoreleasePoolPush(); + OFFile *file = [[OFFile alloc] + initWithPath: IRI.fileSystemRepresentation + mode: mode]; + + objc_autoreleasePoolPop(pool); + + return [file autorelease]; +} + +- (OFFileAttributes)attributesOfItemAtIRI: (OFIRI *)IRI +{ + OFMutableFileAttributes ret = [OFMutableDictionary dictionary]; + void *pool = objc_autoreleasePoolPush(); + OFString *path; + int error; + Stat s; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![[IRI scheme] isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + path = IRI.fileSystemRepresentation; + + if ((error = lstatWrapper(path, &s)) != 0) + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: error]; + + if (s.st_size < 0) + @throw [OFOutOfRangeException exception]; + + [ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size] + forKey: OFFileSize]; + + setTypeAttribute(ret, &s); + + [ret setObject: [NSNumber numberWithUnsignedLong: s.st_mode] + forKey: OFFilePOSIXPermissions]; + + setOwnerAndGroupAttributes(ret, &s); + setDateAttributes(ret, &s); + +#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS + if (S_ISLNK(s.st_mode)) + setSymbolicLinkDestinationAttribute(ret, IRI); +#endif + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES + setExtendedAttributes(ret, IRI); +#endif + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (void)of_setLastAccessDate: (OFDate *)lastAccessDate + andModificationDate: (OFDate *)modificationDate + ofItemAtIRI: (OFIRI *)IRI + attributes: (OFFileAttributes)attributes OF_DIRECT +{ + OFString *path = IRI.fileSystemRepresentation; + OFFileAttributeKey attributeKey = (modificationDate != nil + ? OFFileModificationDate : OFFileLastAccessDate); + + if (lastAccessDate == nil) + lastAccessDate = modificationDate; + if (modificationDate == nil) + modificationDate = lastAccessDate; + +#if defined(OF_WINDOWS) + if (_wutime64FuncPtr != NULL) { + struct __utimbuf64 times = { + .actime = + (__time64_t)lastAccessDate.timeIntervalSince1970, + .modtime = + (__time64_t)modificationDate.timeIntervalSince1970 + }; + + if (_wutime64FuncPtr([path UTF16String], ×) != 0) { + int errNo = errno; + + if (errNo == EACCES && [self directoryExistsAtIRI: IRI]) + errNo = EISDIR; + + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errNo]; + } + } else { + struct _utimbuf times = { + .actime = (time_t)lastAccessDate.timeIntervalSince1970, + .modtime = + (time_t)modificationDate.timeIntervalSince1970 + }; + int status; + + if ([OFSystemInfo isWindowsNT]) + status = _wutime([path UTF16String], ×); + else + status = _utime( + [path cStringWithEncoding: [OFLocale encoding]], + ×); + + if (status != 0) { + int errNo = errno; + + if (errNo == EACCES && [self directoryExistsAtIRI: IRI]) + errNo = EISDIR; + + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errNo]; + } + } +#elif defined(OF_AMIGAOS) + /* AmigaOS does not support access time. */ + OFTimeInterval modificationTime = + modificationDate.timeIntervalSince1970; + struct Locale *locale; + struct DateStamp date; + + modificationTime -= 252460800; /* 1978-01-01 */ + + if (modificationTime < 0) + @throw [OFOutOfRangeException exception]; + + locale = OpenLocale(NULL); + /* + * FIXME: This does not take DST into account. But unfortunately, there + * is no way to figure out if DST should be in effect for the + * timestamp. + */ + modificationTime -= locale->loc_GMTOffset * 60.0; + CloseLocale(locale); + + date.ds_Days = modificationTime / 86400; + date.ds_Minute = ((LONG)modificationTime % 86400) / 60; + date.ds_Tick = fmod(modificationTime, 60) * TICKS_PER_SECOND; + +# ifdef OF_AMIGAOS4 + if (!SetDate([path cStringWithEncoding: [OFLocale encoding]], + &date) != 0) +# else + if (!SetFileDate([path cStringWithEncoding: [OFLocale encoding]], + &date) != 0) +# endif + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: lastError()]; +#else + OFTimeInterval lastAccessTime = lastAccessDate.timeIntervalSince1970; + OFTimeInterval modificationTime = + modificationDate.timeIntervalSince1970; + struct timeval times[2] = { + { + .tv_sec = (time_t)lastAccessTime, + .tv_usec = + (int)((lastAccessTime - times[0].tv_sec) * 1000000) + }, + { + .tv_sec = (time_t)modificationTime, + .tv_usec = (int)((modificationTime - times[1].tv_sec) * + 1000000) + }, + }; + + if (utimes([path cStringWithEncoding: [OFLocale encoding]], times) != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; +#endif +} + +- (void)of_setPOSIXPermissions: (OFNumber *)permissions + ofItemAtIRI: (OFIRI *)IRI + attributes: (OFFileAttributes)attributes OF_DIRECT +{ +#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS + mode_t mode = (mode_t)permissions.unsignedLongValue; + OFString *path = IRI.fileSystemRepresentation; + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wchmod(path.UTF16String, mode); + else +# endif + status = chmod( + [path cStringWithEncoding: [OFLocale encoding]], mode); + + if (status != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: OFFilePOSIXPermissions + errNo: errno]; +#else + OF_UNRECOGNIZED_SELECTOR +#endif +} + +- (void)of_setOwnerAccountName: (OFString *)owner + andGroupOwnerAccountName: (OFString *)group + ofItemAtIRI: (OFIRI *)IRI + attributeKey: (OFFileAttributeKey)attributeKey + attributes: (OFFileAttributes)attributes OF_DIRECT +{ +#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER + OFString *path = IRI.fileSystemRepresentation; + uid_t uid = -1; + gid_t gid = -1; + OFStringEncoding encoding; + + if (owner == nil && group == nil) + @throw [OFInvalidArgumentException exception]; + + encoding = [OFLocale encoding]; + +# ifdef OF_HAVE_THREADS + [passwdMutex lock]; + @try { +# endif + if (owner != nil) { + struct passwd *passwd; + + if ((passwd = getpwnam([owner + cStringWithEncoding: encoding])) == NULL) + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; + + uid = passwd->pw_uid; + } + + if (group != nil) { + struct group *group_; + + if ((group_ = getgrnam([group + cStringWithEncoding: encoding])) == NULL) + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; + + gid = group_->gr_gid; + } +# ifdef OF_HAVE_THREADS + } @finally { + [passwdMutex unlock]; + } +# endif + + if (chown([path cStringWithEncoding: encoding], uid, gid) != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; +#else + OF_UNRECOGNIZED_SELECTOR +#endif +} + +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFEnumerator OF_GENERIC(OFFileAttributeKey) *keyEnumerator; + OFEnumerator *objectEnumerator; + OFFileAttributeKey key; + id object; + OFDate *lastAccessDate, *modificationDate; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + keyEnumerator = [attributes keyEnumerator]; + objectEnumerator = [attributes objectEnumerator]; + + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + if ([key isEqual: OFFileModificationDate] || + [key isEqual: OFFileLastAccessDate]) + continue; + else if ([key isEqual: OFFilePOSIXPermissions]) + [self of_setPOSIXPermissions: object + ofItemAtIRI: IRI + attributes: attributes]; + else if ([key isEqual: OFFileOwnerAccountName]) + [self of_setOwnerAccountName: object + andGroupOwnerAccountName: nil + ofItemAtIRI: IRI + attributeKey: key + attributes: attributes]; + else if ([key isEqual: OFFileGroupOwnerAccountName]) + [self of_setOwnerAccountName: nil + andGroupOwnerAccountName: object + ofItemAtIRI: IRI + attributeKey: key + attributes: attributes]; + else + @throw [OFNotImplementedException + exceptionWithSelector: _cmd + object: self]; + } + + lastAccessDate = [attributes objectForKey: OFFileLastAccessDate]; + modificationDate = [attributes objectForKey: OFFileModificationDate]; + + if (lastAccessDate != nil || modificationDate != nil) + [self of_setLastAccessDate: lastAccessDate + andModificationDate: modificationDate + ofItemAtIRI: IRI + attributes: attributes]; + + objc_autoreleasePoolPop(pool); +} + +- (bool)fileExistsAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + Stat s; + bool ret; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + if (statWrapper(IRI.fileSystemRepresentation, &s) != 0) { + objc_autoreleasePoolPop(pool); + return false; + } + + ret = S_ISREG(s.st_mode); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (bool)directoryExistsAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + Stat s; + bool ret; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + if (statWrapper(IRI.fileSystemRepresentation, &s) != 0) { + objc_autoreleasePoolPop(pool); + return false; + } + + ret = S_ISDIR(s.st_mode); + + objc_autoreleasePoolPop(pool); + + return ret; +} + +- (void)createDirectoryAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + path = IRI.fileSystemRepresentation; + +#if defined(OF_WINDOWS) + int status; + + if ([OFSystemInfo isWindowsNT]) + status = _wmkdir(path.UTF16String); + else + status = _mkdir( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) + @throw [OFCreateDirectoryFailedException + exceptionWithIRI: IRI + errNo: errno]; +#elif defined(OF_AMIGAOS) + BPTR lock; + + if ((lock = CreateDir( + [path cStringWithEncoding: [OFLocale encoding]])) == 0) + @throw [OFCreateDirectoryFailedException + exceptionWithIRI: IRI + errNo: lastError()]; + + UnLock(lock); +#else + if (mkdir([path cStringWithEncoding: [OFLocale encoding]], 0777) != 0) + @throw [OFCreateDirectoryFailedException + exceptionWithIRI: IRI + errNo: errno]; +#endif + + objc_autoreleasePoolPop(pool); +} + +- (OFArray OF_GENERIC(OFIRI *) *)contentsOfDirectoryAtIRI: (OFIRI *)IRI +{ + OFMutableArray *IRIs = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + OFString *path; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + path = IRI.fileSystemRepresentation; + +#if defined(OF_WINDOWS) + HANDLE handle; + + path = [path stringByAppendingString: @"\\*"]; + + if ([OFSystemInfo isWindowsNT]) { + WIN32_FIND_DATAW fd; + + if ((handle = FindFirstFileW(path.UTF16String, + &fd)) == INVALID_HANDLE_VALUE) + @throw [OFOpenItemFailedException + exceptionWithIRI: IRI + mode: nil + errNo: lastError()]; + + @try { + do { + OFString *file; + + if (wcscmp(fd.cFileName, L".") == 0 || + wcscmp(fd.cFileName, L"..") == 0) + continue; + + file = [[OFString alloc] + initWithUTF16String: fd.cFileName]; + @try { + [IRIs addObject: [IRI + IRIByAppendingPathComponent: file]]; + } @finally { + [file release]; + } + } while (FindNextFileW(handle, &fd)); + + if (GetLastError() != ERROR_NO_MORE_FILES) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: lastError()]; + } @finally { + FindClose(handle); + } + } else { + OFStringEncoding encoding = [OFLocale encoding]; + WIN32_FIND_DATA fd; + + if ((handle = FindFirstFileA( + [path cStringWithEncoding: encoding], &fd)) == + INVALID_HANDLE_VALUE) + @throw [OFOpenItemFailedException + exceptionWithIRI: IRI + mode: nil + errNo: lastError()]; + + @try { + do { + OFString *file; + + if (strcmp(fd.cFileName, ".") == 0 || + strcmp(fd.cFileName, "..") == 0) + continue; + + file = [[OFString alloc] + initWithCString: fd.cFileName + encoding: encoding]; + @try { + [IRIs addObject: [IRI + IRIByAppendingPathComponent: file]]; + } @finally { + [file release]; + } + } while (FindNextFileA(handle, &fd)); + + if (GetLastError() != ERROR_NO_MORE_FILES) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: lastError()]; + } @finally { + FindClose(handle); + } + } +#elif defined(OF_AMIGAOS) + OFStringEncoding encoding = [OFLocale encoding]; + BPTR lock; + + if ((lock = Lock([path cStringWithEncoding: encoding], + SHARED_LOCK)) == 0) + @throw [OFOpenItemFailedException + exceptionWithIRI: IRI + mode: nil + errNo: lastError()]; + + @try { +# ifdef OF_AMIGAOS4 + struct ExamineData *ed; + APTR context; + + if ((context = ObtainDirContextTags(EX_FileLockInput, lock, + EX_DoCurrentDir, TRUE, EX_DataFields, EXF_NAME, + TAG_END)) == NULL) + @throw [OFOpenItemFailedException + exceptionWithIRI: IRI + mode: nil + errNo: lastError()]; + + @try { + while ((ed = ExamineDir(context)) != NULL) { + OFString *file = [[OFString alloc] + initWithCString: ed->Name + encoding: encoding]; + + @try { + [IRIs addObject: [IRI + IRIByAppendingPathComponent: file]]; + } @finally { + [file release]; + } + } + } @finally { + ReleaseDirContext(context); + } +# else + struct FileInfoBlock fib; + + if (!Examine(lock, &fib)) + @throw [OFOpenItemFailedException + exceptionWithIRI: IRI + mode: nil + errNo: lastError()]; + + while (ExNext(lock, &fib)) { + OFString *file = [[OFString alloc] + initWithCString: fib.fib_FileName + encoding: encoding]; + @try { + [IRIs addObject: + [IRI IRIByAppendingPathComponent: file]]; + } @finally { + [file release]; + } + } +# endif + + if (IoErr() != ERROR_NO_MORE_ENTRIES) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: lastError()]; + } @finally { + UnLock(lock); + } +#else + OFStringEncoding encoding = [OFLocale encoding]; + DIR *dir; + if ((dir = opendir([path cStringWithEncoding: encoding])) == NULL) + @throw [OFOpenItemFailedException exceptionWithIRI: IRI + mode: nil + errNo: errno]; + +# if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) + @try { + [readdirMutex lock]; + } @catch (id e) { + closedir(dir); + @throw e; + } +# endif + + @try { + for (;;) { + struct dirent *dirent; +# ifdef HAVE_READDIR_R + struct dirent buffer; +# endif + OFString *file; + +# ifdef HAVE_READDIR_R + if (readdir_r(dir, &buffer, &dirent) != 0) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: errno]; + + if (dirent == NULL) + break; +# else + errno = 0; + if ((dirent = readdir(dir)) == NULL) { + if (errno == 0) + break; + else + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: 0 + errNo: errno]; + } +# endif + + if (strcmp(dirent->d_name, ".") == 0 || + strcmp(dirent->d_name, "..") == 0) + continue; + + file = [[OFString alloc] initWithCString: dirent->d_name + encoding: encoding]; + @try { + [IRIs addObject: + [IRI IRIByAppendingPathComponent: file]]; + } @finally { + [file release]; + } + } + } @finally { + closedir(dir); +# if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) + [readdirMutex unlock]; +# endif + } +#endif + + [IRIs makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return IRIs; +} + +- (void)removeItemAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + int error; + Stat s; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + path = IRI.fileSystemRepresentation; + + if ((error = lstatWrapper(path, &s)) != 0) + @throw [OFRemoveItemFailedException exceptionWithIRI: IRI + errNo: error]; + + if (S_ISDIR(s.st_mode)) { + OFArray OF_GENERIC(OFIRI *) *contents; + + @try { + contents = [self contentsOfDirectoryAtIRI: IRI]; + } @catch (id e) { + /* + * Only convert exceptions to + * OFRemoveItemFailedException that have an errNo + * property. This covers all I/O related exceptions + * from the operations used to remove an item, all + * others should be left as is. + */ + if ([e respondsToSelector: @selector(errNo)]) + @throw [OFRemoveItemFailedException + exceptionWithIRI: IRI + errNo: [e errNo]]; + + @throw e; + } + + for (OFIRI *item in contents) { + void *pool2 = objc_autoreleasePoolPush(); + + [self removeItemAtIRI: item]; + + objc_autoreleasePoolPop(pool2); + } + +#ifndef OF_AMIGAOS + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wrmdir(path.UTF16String); + else +# endif + status = rmdir( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) + @throw [OFRemoveItemFailedException + exceptionWithIRI: IRI + errNo: errno]; + } else { + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wunlink(path.UTF16String); + else +# endif + status = unlink( + [path cStringWithEncoding: [OFLocale encoding]]); + + if (status != 0) + @throw [OFRemoveItemFailedException + exceptionWithIRI: IRI + errNo: errno]; +#endif + } + +#ifdef OF_AMIGAOS + if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) + @throw [OFRemoveItemFailedException + exceptionWithIRI: IRI + errNo: lastError()]; +#endif + + objc_autoreleasePoolPop(pool); +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_LINKS +- (void)linkItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination +{ + void *pool = objc_autoreleasePoolPush(); + OFString *sourcePath, *destinationPath; + + if (source == nil || destination == nil) + @throw [OFInvalidArgumentException exception]; + + if (![source.scheme isEqual: _scheme] || + ![destination.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + sourcePath = source.fileSystemRepresentation; + destinationPath = destination.fileSystemRepresentation; + +# ifndef OF_WINDOWS + OFStringEncoding encoding = [OFLocale encoding]; + + if (link([sourcePath cStringWithEncoding: encoding], + [destinationPath cStringWithEncoding: encoding]) != 0) + @throw [OFLinkItemFailedException + exceptionWithSourceIRI: source + destinationIRI: destination + errNo: errno]; +# else + if (createHardLinkWFuncPtr == NULL) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + if (!createHardLinkWFuncPtr(destinationPath.UTF16String, + sourcePath.UTF16String, NULL)) + @throw [OFLinkItemFailedException + exceptionWithSourceIRI: source + destinationIRI: destination + errNo: lastError()]; +# endif + + objc_autoreleasePoolPop(pool); +} +#endif + +#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS +- (void)createSymbolicLinkAtIRI: (OFIRI *)IRI + withDestinationPath: (OFString *)target +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + + if (IRI == nil || target == nil) + @throw [OFInvalidArgumentException exception]; + + if (![IRI.scheme isEqual: _scheme]) + @throw [OFInvalidArgumentException exception]; + + path = IRI.fileSystemRepresentation; + +# ifndef OF_WINDOWS + OFStringEncoding encoding = [OFLocale encoding]; + + if (symlink([target cStringWithEncoding: encoding], + [path cStringWithEncoding: encoding]) != 0) + @throw [OFCreateSymbolicLinkFailedException + exceptionWithIRI: IRI + target: target + errNo: errno]; +# else + if (createSymbolicLinkWFuncPtr == NULL) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + if (!createSymbolicLinkWFuncPtr(path.UTF16String, target.UTF16String, + 0)) + @throw [OFCreateSymbolicLinkFailedException + exceptionWithIRI: IRI + target: target + errNo: lastError()]; +# endif + + objc_autoreleasePoolPop(pool); +} +#endif + +- (bool)moveItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination +{ + void *pool; + + if (![source.scheme isEqual: _scheme] || + ![destination.scheme isEqual: _scheme]) + return false; + + if ([self fileExistsAtIRI: destination]) + @throw [OFMoveItemFailedException + exceptionWithSourceIRI: source + destinationIRI: destination + errNo: EEXIST]; + + pool = objc_autoreleasePoolPush(); + +#ifdef OF_AMIGAOS + OFStringEncoding encoding = [OFLocale encoding]; + + if (!Rename([source.fileSystemRepresentation + cStringWithEncoding: encoding], + [destination.fileSystemRepresentation + cStringWithEncoding: encoding])) + @throw [OFMoveItemFailedException + exceptionWithSourceIRI: source + destinationIRI: destination + errNo: lastError()]; +#else + int status; + +# ifdef OF_WINDOWS + if ([OFSystemInfo isWindowsNT]) + status = _wrename(source.fileSystemRepresentation.UTF16String, + destination.fileSystemRepresentation.UTF16String); + else { +# endif + OFStringEncoding encoding = [OFLocale encoding]; + + status = rename([source.fileSystemRepresentation + cStringWithEncoding: encoding], + [destination.fileSystemRepresentation + cStringWithEncoding: encoding]); +# ifdef OF_WINDOWS + } +# endif + + if (status != 0) + @throw [OFMoveItemFailedException + exceptionWithSourceIRI: source + destinationIRI: destination + errNo: errno]; +#endif + + objc_autoreleasePoolPop(pool); + + return true; +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path = IRI.fileSystemRepresentation; + OFStringEncoding encoding = [OFLocale encoding]; + const char *cPath = [path cStringWithEncoding: encoding]; + const char *cName = [name cStringWithEncoding: encoding]; +# if defined(OF_LINUX) + ssize_t size = lgetxattr(cPath, cName, NULL, 0); +# elif defined(OF_MACOS) + ssize_t size = getxattr(cPath, cName, NULL, 0, 0, XATTR_NOFOLLOW); +# endif + void *value = OFAllocMemory(1, size); + OFData *data; + + @try { +# if defined(OF_LINUX) + if ((size = lgetxattr(cPath, cName, value, size)) < 0) +# elif defined(OF_MACOS) + if ((size = getxattr(cPath, cName, value, size, 0, + XATTR_NOFOLLOW)) < 0) +# endif + @throw [OFGetItemAttributesFailedException + exceptionWithIRI: IRI + errNo: errno]; + + data = [OFData dataWithItems: value count: size]; + } @finally { + OFFreeMemory(value); + } + + [data retain]; + + objc_autoreleasePoolPop(pool); + + return [data autorelease]; +} + +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path = IRI.fileSystemRepresentation; + OFStringEncoding encoding = [OFLocale encoding]; + +# if defined(OF_LINUX) + if (lsetxattr([path cStringWithEncoding: encoding], + [name cStringWithEncoding: encoding], data.items, + data.count * data.itemSize, 0) != 0) { +# elif defined(OF_MACOS) + if (setxattr([path cStringWithEncoding: encoding], + [name cStringWithEncoding: encoding], data.items, + data.count * data.itemSize, 0, XATTR_NOFOLLOW) != 0) { +# endif + int errNo = errno; + + /* TODO: Add an attribute (prefix?) for extended attributes? */ + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: [OFDictionary dictionary] + failedAttribute: @"" + errNo: errNo]; + } + + objc_autoreleasePoolPop(pool); +} + +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path = IRI.fileSystemRepresentation; + OFStringEncoding encoding = [OFLocale encoding]; + +# if defined(OF_LINUX) + if (lremovexattr([path cStringWithEncoding: encoding], + [name cStringWithEncoding: encoding]) != 0) { +# elif defined(OF_MACOS) + if (removexattr([path cStringWithEncoding: encoding], + [name cStringWithEncoding: encoding], XATTR_NOFOLLOW) != 0) { +# endif + int errNo = errno; + + /* TODO: Add an attribute (prefix?) for extended attributes? */ + @throw [OFSetItemAttributesFailedException + exceptionWithIRI: IRI + attributes: [OFDictionary dictionary] + failedAttribute: @"" + errNo: errNo]; + } + + objc_autoreleasePoolPop(pool); +} +#endif +@end Index: src/OFFileManager.h ================================================================== --- src/OFFileManager.h +++ src/OFFileManager.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -31,22 +31,25 @@ # define OF_FILE_MANAGER_SUPPORTS_LINKS # endif # if (defined(OF_HAVE_SYMLINK) && !defined(OF_AMIGAOS)) || defined(OF_WINDOWS) # define OF_FILE_MANAGER_SUPPORTS_SYMLINKS # endif +# if defined(OF_LINUX) || defined(OF_MACOS) +# define OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +# endif #endif @class OFArray OF_GENERIC(ObjectType); @class OFConstantString; @class OFDate; +@class OFIRI; @class OFString; -@class OFURI; /** * @brief A key for a file attribute in the file attributes dictionary. * - * Possible keys for file URIs are: + * Possible keys for file IRIs are: * * * @ref OFFileSize * * @ref OFFileType * * @ref OFFilePOSIXPermissions * * @ref OFFileOwnerAccountID @@ -56,19 +59,20 @@ * * @ref OFFileLastAccessDate * * @ref OFFileModificationDate * * @ref OFFileStatusChangeDate * * @ref OFFileCreationDate * * @ref OFFileSymbolicLinkDestination + * * @ref OFFileExtendedAttributesNames * - * Other URI schemes might not have all keys and might have keys not listed. + * Other IRI schemes might not have all keys and might have keys not listed. */ typedef OFConstantString *OFFileAttributeKey; /** * @brief The type of a file. * - * Possibles values for file URIs are: + * Possibles values for file IRIs are: * * * @ref OFFileTypeRegular * * @ref OFFileTypeDirectory * * @ref OFFileTypeSymbolicLink * * @ref OFFileTypeFIFO @@ -75,11 +79,11 @@ * * @ref OFFileTypeCharacterSpecial * * @ref OFFileTypeBlockSpecial * * @ref OFFileTypeSocket * * @ref OFFileTypeUnknown * - * Other URI schemes might not have all types and might have types not listed. + * Other IRI schemes might not have all types and might have types not listed. */ typedef OFConstantString *OFFileAttributeType; /** * @brief A dictionary mapping keys of type @ref OFFileAttributeKey to their @@ -186,17 +190,26 @@ * via @ref OFDictionary#fileCreationDate. */ extern const OFFileAttributeKey OFFileCreationDate; /** - * @brief The destination of a symbolic link as an OFString. + * @brief The destination of a symbolic link as an @ref OFString. * * For convenience, a category on @ref OFDictionary is provided to access this * via @ref OFDictionary#fileSymbolicLinkDestination. */ extern const OFFileAttributeKey OFFileSymbolicLinkDestination; +/** + * @brief The names of the extended attributes as an @ref OFArray of + * @ref OFString. + * + * For convenience, a category on @ref OFDictionary is provided to access this + * via @ref OFDictionary#fileExtendedAttributesNames. + */ +extern const OFFileAttributeKey OFFileExtendedAttributesNames; + /** * @brief A regular file. */ extern const OFFileAttributeType OFFileTypeRegular; @@ -263,15 +276,15 @@ * @throw OFGetCurrentDirectoryFailedException Couldn't get current directory */ @property (readonly, nonatomic) OFString *currentDirectoryPath; /** - * @brief The URI of the current working directory. + * @brief The IRI of the current working directory. * * @throw OFGetCurrentDirectoryFailedException Couldn't get current directory */ -@property (readonly, nonatomic) OFURI *currentDirectoryURI; +@property (readonly, nonatomic) OFIRI *currentDirectoryIRI; #endif /** * @brief Returns the default file manager. */ @@ -289,21 +302,21 @@ */ - (OFFileAttributes)attributesOfItemAtPath: (OFString *)path; #endif /** - * @brief Returns the attributes for the item at the specified URI. + * @brief Returns the attributes for the item at the specified IRI. * - * @param URI The URI to return the attributes for - * @return A dictionary of attributes for the specified URI, with the keys of + * @param IRI The IRI to return the attributes for + * @return A dictionary of attributes for the specified IRI, with the keys of * type @ref OFFileAttributeKey * @throw OFGetItemAttributesFailedException Failed to get the attributes of * the item - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (OFFileAttributes)attributesOfItemAtURI: (OFURI *)URI; +- (OFFileAttributes)attributesOfItemAtIRI: (OFIRI *)IRI; #ifdef OF_HAVE_FILES /** * @brief Sets the attributes for the item at the specified path. * @@ -320,25 +333,25 @@ - (void)setAttributes: (OFFileAttributes)attributes ofItemAtPath: (OFString *)path; #endif /** - * @brief Sets the attributes for the item at the specified URI. + * @brief Sets the attributes for the item at the specified IRI. * * All attributes not part of the dictionary are left unchanged. * - * @param attributes The attributes to set for the specified URI - * @param URI The URI of the item to set the attributes for + * @param attributes The attributes to set for the specified IRI + * @param IRI The IRI of the item to set the attributes for * @throw OFSetItemAttributesFailedException Failed to set the attributes of * the item - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme * @throw OFNotImplementedException Setting one or more of the specified * attributes is not implemented for the * specified item */ -- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURI: (OFURI *)URI; +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtIRI: (OFIRI *)IRI; #ifdef OF_HAVE_FILES /** * @brief Checks whether a file exists at the specified path. * @@ -347,18 +360,18 @@ */ - (bool)fileExistsAtPath: (OFString *)path; #endif /** - * @brief Checks whether a file exists at the specified URI. + * @brief Checks whether a file exists at the specified IRI. * - * @param URI The URI to check - * @return A boolean whether there is a file at the specified URI - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @param IRI The IRI to check + * @return A boolean whether there is a file at the specified IRI + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (bool)fileExistsAtURI: (OFURI *)URI; +- (bool)fileExistsAtIRI: (OFIRI *)IRI; #ifdef OF_HAVE_FILES /** * @brief Checks whether a directory exists at the specified path. * @@ -367,18 +380,18 @@ */ - (bool)directoryExistsAtPath: (OFString *)path; #endif /** - * @brief Checks whether a directory exists at the specified URI. + * @brief Checks whether a directory exists at the specified IRI. * - * @param URI The URI to check - * @return A boolean whether there is a directory at the specified URI - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @param IRI The IRI to check + * @return A boolean whether there is a directory at the specified IRI + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (bool)directoryExistsAtURI: (OFURI *)URI; +- (bool)directoryExistsAtIRI: (OFIRI *)IRI; #ifdef OF_HAVE_FILES /** * @brief Creates a directory at the specified path. * @@ -398,30 +411,30 @@ - (void)createDirectoryAtPath: (OFString *)path createParents: (bool)createParents; #endif /** - * @brief Creates a directory at the specified URI. + * @brief Creates a directory at the specified IRI. * - * @param URI The URI of the directory to create + * @param IRI The IRI of the directory to create * @throw OFCreateDirectoryFailedException Creating the directory failed - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (void)createDirectoryAtURI: (OFURI *)URI; +- (void)createDirectoryAtIRI: (OFIRI *)IRI; /** - * @brief Creates a directory at the specified URI. + * @brief Creates a directory at the specified IRI. * - * @param URI The URI of the directory to create + * @param IRI The IRI of the directory to create * @param createParents Whether to create the parents of the directory * @throw OFCreateDirectoryFailedException Creating the directory or one of its * parents failed - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (void)createDirectoryAtURI: (OFURI *)URI createParents: (bool)createParents; +- (void)createDirectoryAtIRI: (OFIRI *)IRI createParents: (bool)createParents; #ifdef OF_HAVE_FILES /** * @brief Returns an array with the items in the specified directory. * @@ -434,23 +447,23 @@ */ - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtPath: (OFString *)path; #endif /** - * @brief Returns an array with the URIs of the items in the specified + * @brief Returns an array with the IRIs of the items in the specified * directory. * * @note `.` and `..` are not part of the returned array. * - * @param URI The URI to the directory whose items should be returned - * @return An array with the URIs of the items in the specified directory + * @param IRI The IRI to the directory whose items should be returned + * @return An array with the IRIs of the items in the specified directory * @throw OFOpenItemFailedException Opening the directory failed * @throw OFReadFailedException Reading from the directory failed - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (OFArray OF_GENERIC(OFURI *) *)contentsOfDirectoryAtURI: (OFURI *)URI; +- (OFArray OF_GENERIC(OFIRI *) *)contentsOfDirectoryAtIRI: (OFIRI *)IRI; #ifdef OF_HAVE_FILES /** * @brief Returns an array with all subpaths of the specified directory. * @@ -472,15 +485,15 @@ - (void)changeCurrentDirectoryPath: (OFString *)path; /** * @brief Changes the current working directory. * - * @param URI The new directory to change to + * @param IRI The new directory to change to * @throw OFChangeCurrentDirectoryFailedException Changing the current working * directory failed */ -- (void)changeCurrentDirectoryURI: (OFURI *)URI; +- (void)changeCurrentDirectoryIRI: (OFIRI *)IRI; /** * @brief Copies a file, directory or symbolic link (if supported by the OS). * * The destination path must be a full path, which means it must include the @@ -500,26 +513,26 @@ #endif /** * @brief Copies a file, directory or symbolic link (if supported by the OS). * - * The destination URI must have a full path, which means it must include the + * The destination IRI must have a full path, which means it must include the * name of the item. * * If an item already exists, the copy operation fails. This is also the case * if a directory is copied and an item already exists in the destination * directory. * * @param source The file, directory or symbolic link to copy - * @param destination The destination URI + * @param destination The destination IRI * @throw OFCopyItemFailedException Copying failed * @throw OFCreateDirectoryFailedException Creating a destination directory * failed * @throw OFUnsupportedProtocolException No handler is registered for either of - * the URI's scheme + * the IRI's scheme */ -- (void)copyItemAtURI: (OFURI *)source toURI: (OFURI *)destination; +- (void)copyItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; #ifdef OF_HAVE_FILES /** * @brief Moves an item. * @@ -545,16 +558,16 @@ #endif /** * @brief Moves an item. * - * The destination URI must have a full path, which means it must include the + * The destination IRI must have a full path, which means it must include the * name of the item. * * If the destination is on a different logical device or uses a different * scheme, the source will be copied to the destination using - * @ref copyItemAtURI:toURI: and the source removed using @ref removeItemAtURI:. + * @ref copyItemAtIRI:toIRI: and the source removed using @ref removeItemAtIRI:. * * @param source The item to rename * @param destination The new name for the item * @throw OFMoveItemFailedException Moving failed * @throw OFCopyItemFailedException Copying (to move between different devices) @@ -563,13 +576,13 @@ * destination (to move between different * devices) failed * @throw OFCreateDirectoryFailedException Creating a destination directory * failed * @throw OFUnsupportedProtocolException No handler is registered for either of - * the URI's scheme + * the IRI's scheme */ -- (void)moveItemAtURI: (OFURI *)source toURI: (OFURI *)destination; +- (void)moveItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; #ifdef OF_HAVE_FILES /** * @brief Removes the item at the specified path. * @@ -580,20 +593,20 @@ */ - (void)removeItemAtPath: (OFString *)path; #endif /** - * @brief Removes the item at the specified URI. + * @brief Removes the item at the specified IRI. * - * If the item at the specified URI is a directory, it is removed recursively. + * If the item at the specified IRI is a directory, it is removed recursively. * - * @param URI The URI to the item which should be removed + * @param IRI The IRI to the item which should be removed * @throw OFRemoveItemFailedException Removing the item failed - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (void)removeItemAtURI: (OFURI *)URI; +- (void)removeItemAtIRI: (OFIRI *)IRI; #ifdef OF_FILE_MANAGER_SUPPORTS_LINKS /** * @brief Creates a hard link for the specified item. * @@ -604,32 +617,32 @@ * * @param source The path to the item for which a link should be created * @param destination The path to the item which should link to the source * @throw OFLinkItemFailedException Linking the item failed * @throw OFNotImplementedException Hardlinks are not implemented for the - * specified URI + * specified IRI */ - (void)linkItemAtPath: (OFString *)source toPath: (OFString *)destination; #endif /** * @brief Creates a hard link for the specified item. * - * The destination URI must have a full path, which means it must include the + * The destination IRI must have a full path, which means it must include the * name of the item. * - * This method is not available for all URIs. + * This method is not available for all IRIs. * - * @param source The URI to the item for which a link should be created - * @param destination The URI to the item which should link to the source + * @param source The IRI to the item for which a link should be created + * @param destination The IRI to the item which should link to the source * @throw OFLinkItemFailedException Linking the item failed - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme * @throw OFNotImplementedException Hardlinks are not implemented for the - * specified URI + * specified IRI */ -- (void)linkItemAtURI: (OFURI *)source toURI: (OFURI *)destination; +- (void)linkItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS /** * @brief Creates a symbolic link for an item. * @@ -643,34 +656,147 @@ * * @param path The path to the item which should symbolically link to the target * @param target The target of the symbolic link * @throw OFCreateSymbolicLinkFailedException Creating the symbolic link failed * @throw OFNotImplementedException Symbolic links are not implemented for the - * specified URI + * specified IRI */ - (void)createSymbolicLinkAtPath: (OFString *)path withDestinationPath: (OFString *)target; #endif /** * @brief Creates a symbolic link for an item. * - * The destination URI must have a full path, which means it must include the + * The destination IRI must have a full path, which means it must include the * name of the item. * - * This method is not available for all URIs. + * This method is not available for all IRIs. * - * @note On Windows, this requires at least Windows Vista and administrator - * privileges! + * @note For file IRIs on Windows, this requires at least Windows Vista and + * administrator privileges! * - * @param URI The URI to the item which should symbolically link to the target + * @param IRI The IRI to the item which should symbolically link to the target * @param target The target of the symbolic link - * @throw OFUnsupportedProtocolException No handler is registered for the URI's + * @throw OFOFCreateSymbolicLinkFailedException Creating a symbolic link failed + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's * scheme */ -- (void)createSymbolicLinkAtURI: (OFURI *)URI +- (void)createSymbolicLinkAtIRI: (OFIRI *)IRI withDestinationPath: (OFString *)target; + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +/** + * @brief Returns the extended attribute data for the specified name of the + * item at the specified path. + * + * This method is not available on some systems. + * + * @param name The name of the extended attribute + * @param path The path of the item to return the extended attribute from + * @throw OFGetItemAttributesFailedException Getting the extended attribute + * failed + * @throw OFNotImplementedException Getting extended attributes is not + * implemented for the specified item + */ +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtPath: (OFString *)path; +#endif + +/** + * @brief Returns the extended attribute data for the specified name of the + * item at the specified IRI. + * + * This method is not available for all IRIs. + * + * @param name The name of the extended attribute + * @param IRI The IRI of the item to return the extended attribute from + * @throw OFGetItemAttributesFailedException Getting the extended attribute + * failed + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's + * scheme + * @throw OFNotImplementedException Getting extended attributes is not + * implemented for the specified item + */ +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +/** + * @brief Sets the extended attribute data for the specified name of the item + * at the specified path. + * + * This method is not available on some systems. + * + * @param data The data for the extended attribute + * @param name The name of the extended attribute + * @param path The path of the item to set the extended attribute on + * @throw OFSetItemAttributesFailedException Setting the extended attribute + * failed + * @throw OFNotImplementedException Setting extended attributes is not + * implemented for the specified item + */ +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtPath: (OFString *)path; +#endif + +/** + * @brief Sets the extended attribute data for the specified name of the item + * at the specified IRI. + * + * This method is not available for all IRIs. + * + * @param data The data for the extended attribute + * @param name The name of the extended attribute + * @param IRI The IRI of the item to set the extended attribute on + * @throw OFSetItemAttributesFailedException Setting the extended attribute + * failed + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's + * scheme + * @throw OFNotImplementedException Setting extended attributes is not + * implemented for the specified item + */ +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +/** + * @brief Removes the extended attribute for the specified name wof the item at + * the specified path. + * + * This method is not available on some systems. + * + * @param name The name of the extended attribute to remove + * @param path The path of the item to remove the extended attribute from + * @throw OFSetItemAttributesFailedException Removing the extended attribute + * failed + * @throw OFNotImplementedException Removing extended attributes is not + * implemented for the specified item + */ +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtPath: (OFString *)path; +#endif + +/** + * @brief Removes the extended attribute for the specified name wof the item at + * the specified IRI. + * + * This method is not available for all IRIs. + * + * @param name The name of the extended attribute to remove + * @param IRI The IRI of the item to remove the extended attribute from + * @throw OFSetItemAttributesFailedException Removing the extended attribute + * failed + * @throw OFUnsupportedProtocolException No handler is registered for the IRI's + * scheme + * @throw OFNotImplementedException Removing extended attributes is not + * implemented for the specified item + */ +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; @end @interface OFDictionary (FileAttributes) /** * @brief The @ref OFFileSize key from the dictionary. @@ -753,8 +879,16 @@ * @brief The @ref OFFileSymbolicLinkDestination key from the dictionary. * * @throw OFUndefinedKeyException The key is missing */ @property (readonly, nonatomic) OFString *fileSymbolicLinkDestination; + +/** + * @brief The @ref OFFileExtendedAttributesNames key from the dictionary. + * + * @throw OFUndefinedKeyException The key is missing + */ +@property (readonly, nonatomic) + OFArray OF_GENERIC(OFString *) *fileExtendedAttributesNames; @end OF_ASSUME_NONNULL_END Index: src/OFFileManager.m ================================================================== --- src/OFFileManager.m +++ src/OFFileManager.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -21,28 +21,32 @@ #include #include "unistd_wrapper.h" #include "platform.h" +#ifdef OF_DJGPP +# include +#endif #ifdef OF_PSP # include #endif #import "OFArray.h" +#import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" #endif #import "OFFileManager.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFStream.h" #import "OFString.h" #import "OFSystemInfo.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFChangeCurrentDirectoryFailedException.h" #import "OFCopyItemFailedException.h" #import "OFCreateDirectoryFailedException.h" #import "OFGetCurrentDirectoryFailedException.h" @@ -62,12 +66,14 @@ # include # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include +# undef Class #endif #ifdef OF_MINT # include #endif @@ -165,10 +171,26 @@ return nil; } return [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; +# elif defined(OF_GLIBC) + char *buffer; + OFString *path; + + if ((buffer = getcwd(NULL, 0)) == NULL) + @throw [OFGetCurrentDirectoryFailedException + exceptionWithErrNo: errno]; + + @try { + path = [OFString stringWithCString: buffer + encoding: [OFLocale encoding]]; + } @finally { + free(buffer); + } + + return path; # else char buffer[PATH_MAX]; if ((getcwd(buffer, PATH_MAX)) == NULL) @throw [OFGetCurrentDirectoryFailedException @@ -187,157 +209,156 @@ return [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; # endif } -- (OFURI *)currentDirectoryURI +- (OFIRI *)currentDirectoryIRI { void *pool = objc_autoreleasePoolPush(); - OFURI *ret; + OFIRI *ret; - ret = [OFURI fileURIWithPath: self.currentDirectoryPath]; + ret = [OFIRI fileIRIWithPath: self.currentDirectoryPath]; + ret = [ret retain]; - [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } #endif -- (OFFileAttributes)attributesOfItemAtURI: (OFURI *)URI +- (OFFileAttributes)attributesOfItemAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - return [URIHandler attributesOfItemAtURI: URI]; + return [IRIHandler attributesOfItemAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (OFFileAttributes)attributesOfItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFFileAttributes ret; - ret = [self attributesOfItemAtURI: [OFURI fileURIWithPath: path]]; - - [ret retain]; + ret = [self attributesOfItemAtIRI: [OFIRI fileIRIWithPath: path]]; + ret = [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } #endif -- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURI: (OFURI *)URI +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - [URIHandler setAttributes: attributes ofItemAtURI: URI]; + [IRIHandler setAttributes: attributes ofItemAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (void)setAttributes: (OFFileAttributes)attributes ofItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); [self setAttributes: attributes - ofItemAtURI: [OFURI fileURIWithPath: path]]; + ofItemAtIRI: [OFIRI fileIRIWithPath: path]]; objc_autoreleasePoolPop(pool); } #endif -- (bool)fileExistsAtURI: (OFURI *)URI +- (bool)fileExistsAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - return [URIHandler fileExistsAtURI: URI]; + return [IRIHandler fileExistsAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (bool)fileExistsAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); bool ret; - ret = [self fileExistsAtURI: [OFURI fileURIWithPath: path]]; + ret = [self fileExistsAtIRI: [OFIRI fileIRIWithPath: path]]; objc_autoreleasePoolPop(pool); return ret; } #endif -- (bool)directoryExistsAtURI: (OFURI *)URI +- (bool)directoryExistsAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - return [URIHandler directoryExistsAtURI: URI]; + return [IRIHandler directoryExistsAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (bool)directoryExistsAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); bool ret; - ret = [self directoryExistsAtURI: [OFURI fileURIWithPath: path]]; + ret = [self directoryExistsAtIRI: [OFIRI fileIRIWithPath: path]]; objc_autoreleasePoolPop(pool); return ret; } #endif -- (void)createDirectoryAtURI: (OFURI *)URI +- (void)createDirectoryAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - [URIHandler createDirectoryAtURI: URI]; + [IRIHandler createDirectoryAtIRI: IRI]; } -- (void)createDirectoryAtURI: (OFURI *)URI createParents: (bool)createParents +- (void)createDirectoryAtIRI: (OFIRI *)IRI createParents: (bool)createParents { void *pool = objc_autoreleasePoolPush(); - OFMutableURI *mutableURI; + OFMutableIRI *mutableIRI; OFArray OF_GENERIC(OFString *) *components; - OFMutableArray OF_GENERIC(OFURI *) *componentURIs; - size_t componentURIsCount; + OFMutableArray OF_GENERIC(OFIRI *) *componentIRIs; + size_t componentIRIsCount; ssize_t i; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; if (!createParents) { - [self createDirectoryAtURI: URI]; + [self createDirectoryAtIRI: IRI]; return; } /* * Try blindly creating the directory first. @@ -344,15 +365,15 @@ * * The reason for this is that we might be sandboxed, so attempting to * create any of the parent directories will fail, while creating the * directory itself will work. */ - if ([self directoryExistsAtURI: URI]) + if ([self directoryExistsAtIRI: IRI]) return; @try { - [self createDirectoryAtURI: URI]; + [self createDirectoryAtIRI: IRI]; return; } @catch (OFCreateDirectoryFailedException *e) { /* * If we didn't fail because any of the parents is missing, * there is no point in trying to create the parents. @@ -360,101 +381,101 @@ if (e.errNo != ENOENT) @throw e; } /* - * Because we might be sandboxed (and for remote URIs don't even know - * anything at all), we generate the URI for every component. We then + * Because we might be sandboxed (and for remote IRIs don't even know + * anything at all), we generate the IRI for every component. We then * iterate them in reverse order until we find the first existing * directory, and then create subdirectories from there. */ - mutableURI = [[URI mutableCopy] autorelease]; - mutableURI.percentEncodedPath = @"/"; - components = URI.pathComponents; - componentURIs = [OFMutableArray arrayWithCapacity: components.count]; + mutableIRI = [[IRI mutableCopy] autorelease]; + mutableIRI.percentEncodedPath = @"/"; + components = IRI.pathComponents; + componentIRIs = [OFMutableArray arrayWithCapacity: components.count]; for (OFString *component in components) { - [mutableURI appendPathComponent: component]; + [mutableIRI appendPathComponent: component]; - if (![mutableURI.percentEncodedPath isEqual: @"/"]) - [componentURIs addObject: - [[mutableURI copy] autorelease]]; + if (![mutableIRI.percentEncodedPath isEqual: @"/"]) + [componentIRIs addObject: + [[mutableIRI copy] autorelease]]; } - componentURIsCount = componentURIs.count; - for (i = componentURIsCount - 1; i > 0; i--) { - if ([self directoryExistsAtURI: - [componentURIs objectAtIndex: i]]) + componentIRIsCount = componentIRIs.count; + for (i = componentIRIsCount - 1; i > 0; i--) { + if ([self directoryExistsAtIRI: + [componentIRIs objectAtIndex: i]]) break; } - if (++i == (ssize_t)componentURIsCount) { + if (++i == (ssize_t)componentIRIsCount) { /* - * The URI exists, even though before we made sure it did not. + * The IRI exists, even though before we made sure it did not. * That means it was created in the meantime by something else, * so we're done here. */ objc_autoreleasePoolPop(pool); return; } - for (; i < (ssize_t)componentURIsCount; i++) - [self createDirectoryAtURI: [componentURIs objectAtIndex: i]]; + for (; i < (ssize_t)componentIRIsCount; i++) + [self createDirectoryAtIRI: [componentIRIs objectAtIndex: i]]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_FILES - (void)createDirectoryAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - [self createDirectoryAtURI: [OFURI fileURIWithPath: path]]; + [self createDirectoryAtIRI: [OFIRI fileIRIWithPath: path]]; objc_autoreleasePoolPop(pool); } - (void)createDirectoryAtPath: (OFString *)path createParents: (bool)createParents { void *pool = objc_autoreleasePoolPush(); - [self createDirectoryAtURI: [OFURI fileURIWithPath: path] + [self createDirectoryAtIRI: [OFIRI fileIRIWithPath: path] createParents: createParents]; objc_autoreleasePoolPop(pool); } #endif -- (OFArray OF_GENERIC(OFURI *) *)contentsOfDirectoryAtURI: (OFURI *)URI +- (OFArray OF_GENERIC(OFIRI *) *)contentsOfDirectoryAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - return [URIHandler contentsOfDirectoryAtURI: URI]; + return [IRIHandler contentsOfDirectoryAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (OFArray OF_GENERIC(OFString *) *)contentsOfDirectoryAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - OFArray OF_GENERIC(OFURI *) *URIs; + OFArray OF_GENERIC(OFIRI *) *IRIs; OFMutableArray OF_GENERIC(OFString *) *ret; - URIs = [self contentsOfDirectoryAtURI: [OFURI fileURIWithPath: path]]; - ret = [OFMutableArray arrayWithCapacity: URIs.count]; + IRIs = [self contentsOfDirectoryAtIRI: [OFIRI fileIRIWithPath: path]]; + ret = [OFMutableArray arrayWithCapacity: IRIs.count]; - for (OFURI *URI in URIs) - [ret addObject: URI.lastPathComponent]; + for (OFIRI *IRI in IRIs) + [ret addObject: IRI.lastPathComponent]; [ret makeImmutable]; - [ret retain]; + ret = [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @@ -480,11 +501,11 @@ objc_autoreleasePoolPop(pool2); } [ret makeImmutable]; - [ret retain]; + ret = [ret retain]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @@ -543,71 +564,71 @@ exceptionWithPath: path errNo: errno]; # endif } -- (void)changeCurrentDirectoryURI: (OFURI *)URI +- (void)changeCurrentDirectoryIRI: (OFIRI *)IRI { void *pool = objc_autoreleasePoolPush(); - [self changeCurrentDirectoryPath: URI.fileSystemRepresentation]; + [self changeCurrentDirectoryPath: IRI.fileSystemRepresentation]; objc_autoreleasePoolPop(pool); } - (void)copyItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); - [self copyItemAtURI: [OFURI fileURIWithPath: source] - toURI: [OFURI fileURIWithPath: destination]]; + [self copyItemAtIRI: [OFIRI fileIRIWithPath: source] + toIRI: [OFIRI fileIRIWithPath: destination]]; objc_autoreleasePoolPop(pool); } #endif -- (void)copyItemAtURI: (OFURI *)source toURI: (OFURI *)destination +- (void)copyItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination { void *pool; - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; OFFileAttributes attributes; OFFileAttributeType type; if (source == nil || destination == nil) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); - if ((URIHandler = [OFURIHandler handlerForURI: source]) == nil) + if ((IRIHandler = [OFIRIHandler handlerForIRI: source]) == nil) @throw [OFUnsupportedProtocolException - exceptionWithURI: source]; + exceptionWithIRI: source]; - if ([URIHandler copyItemAtURI: source toURI: destination]) + if ([IRIHandler copyItemAtIRI: source toIRI: destination]) return; - if ([self fileExistsAtURI: destination]) + if ([self fileExistsAtIRI: destination]) @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: EEXIST]; @try { - attributes = [self attributesOfItemAtURI: source]; + attributes = [self attributesOfItemAtIRI: source]; } @catch (OFGetItemAttributesFailedException *e) { @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: e.errNo]; } type = attributes.fileType; if ([type isEqual: OFFileTypeDirectory]) { - OFArray OF_GENERIC(OFURI *) *contents; + OFArray OF_GENERIC(OFIRI *) *contents; @try { - [self createDirectoryAtURI: destination]; + [self createDirectoryAtIRI: destination]; @try { OFFileAttributeKey key = OFFilePOSIXPermissions; OFNumber *permissions = [attributes objectForKey: key]; @@ -617,39 +638,39 @@ destinationAttributes = [OFDictionary dictionaryWithObject: permissions forKey: key]; [self setAttributes: destinationAttributes - ofItemAtURI: destination]; + ofItemAtIRI: destination]; } } @catch (OFNotImplementedException *e) { } - contents = [self contentsOfDirectoryAtURI: source]; + contents = [self contentsOfDirectoryAtIRI: source]; } @catch (id e) { /* * Only convert exceptions to OFCopyItemFailedException * that have an errNo property. This covers all I/O * related exceptions from the operations used to copy * an item, all others should be left as is. */ if ([e respondsToSelector: @selector(errNo)]) @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: [e errNo]]; @throw e; } - for (OFURI *item in contents) { + for (OFIRI *item in contents) { void *pool2 = objc_autoreleasePoolPush(); - OFURI *destinationURI = [destination - URIByAppendingPathComponent: + OFIRI *destinationIRI = [destination + IRIByAppendingPathComponent: item.lastPathComponent]; - [self copyItemAtURI: item toURI: destinationURI]; + [self copyItemAtIRI: item toIRI: destinationIRI]; objc_autoreleasePoolPop(pool2); } } else if ([type isEqual: OFFileTypeRegular]) { size_t pageSize = [OFSystemInfo pageSize]; @@ -657,14 +678,14 @@ OFStream *destinationStream = nil; char *buffer; buffer = OFAllocMemory(1, pageSize); @try { - sourceStream = [OFURIHandler openItemAtURI: source + sourceStream = [OFIRIHandler openItemAtIRI: source mode: @"r"]; - destinationStream = [OFURIHandler - openItemAtURI: destination + destinationStream = [OFIRIHandler + openItemAtIRI: destination mode: @"w"]; while (!sourceStream.atEndOfStream) { size_t length; @@ -685,11 +706,11 @@ destinationAttributes = [OFDictionary dictionaryWithObject: permissions forKey: key]; [self setAttributes: destinationAttributes - ofItemAtURI: destination]; + ofItemAtIRI: destination]; } } @catch (OFNotImplementedException *e) { } } @catch (id e) { /* @@ -698,12 +719,12 @@ * related exceptions from the operations used to copy * an item, all others should be left as is. */ if ([e respondsToSelector: @selector(errNo)]) @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: [e errNo]]; @throw e; } @finally { [sourceStream close]; @@ -713,11 +734,11 @@ } else if ([type isEqual: OFFileTypeSymbolicLink]) { @try { OFString *linkDestination = attributes.fileSymbolicLinkDestination; - [self createSymbolicLinkAtURI: destination + [self createSymbolicLinkAtIRI: destination withDestinationPath: linkDestination]; } @catch (id e) { /* * Only convert exceptions to OFCopyItemFailedException * that have an errNo property. This covers all I/O @@ -724,169 +745,256 @@ * related exceptions from the operations used to copy * an item, all others should be left as is. */ if ([e respondsToSelector: @selector(errNo)]) @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: [e errNo]]; @throw e; } } else @throw [OFCopyItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: EINVAL]; objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_FILES - (void)moveItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); - [self moveItemAtURI: [OFURI fileURIWithPath: source] - toURI: [OFURI fileURIWithPath: destination]]; + [self moveItemAtIRI: [OFIRI fileIRIWithPath: source] + toIRI: [OFIRI fileIRIWithPath: destination]]; objc_autoreleasePoolPop(pool); } #endif -- (void)moveItemAtURI: (OFURI *)source toURI: (OFURI *)destination +- (void)moveItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination { void *pool; - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; if (source == nil || destination == nil) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); - if ((URIHandler = [OFURIHandler handlerForURI: source]) == nil) + if ((IRIHandler = [OFIRIHandler handlerForIRI: source]) == nil) @throw [OFUnsupportedProtocolException - exceptionWithURI: source]; + exceptionWithIRI: source]; @try { - if ([URIHandler moveItemAtURI: source toURI: destination]) + if ([IRIHandler moveItemAtIRI: source toIRI: destination]) return; } @catch (OFMoveItemFailedException *e) { if (e.errNo != EXDEV) @throw e; } - if ([self fileExistsAtURI: destination]) + if ([self fileExistsAtIRI: destination]) @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: EEXIST]; @try { - [self copyItemAtURI: source toURI: destination]; + [self copyItemAtIRI: source toIRI: destination]; } @catch (OFCopyItemFailedException *e) { - [self removeItemAtURI: destination]; + [self removeItemAtIRI: destination]; @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: e.errNo]; } @try { - [self removeItemAtURI: source]; + [self removeItemAtIRI: source]; } @catch (OFRemoveItemFailedException *e) { @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination + exceptionWithSourceIRI: source + destinationIRI: destination errNo: e.errNo]; } objc_autoreleasePoolPop(pool); } -- (void)removeItemAtURI: (OFURI *)URI +- (void)removeItemAtIRI: (OFIRI *)IRI { - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil) + if (IRI == nil) @throw [OFInvalidArgumentException exception]; - if ((URIHandler = [OFURIHandler handlerForURI: URI]) == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - [URIHandler removeItemAtURI: URI]; + [IRIHandler removeItemAtIRI: IRI]; } #ifdef OF_HAVE_FILES - (void)removeItemAtPath: (OFString *)path { void *pool = objc_autoreleasePoolPush(); - [self removeItemAtURI: [OFURI fileURIWithPath: path]]; + [self removeItemAtIRI: [OFIRI fileIRIWithPath: path]]; objc_autoreleasePoolPop(pool); } #endif -- (void)linkItemAtURI: (OFURI *)source toURI: (OFURI *)destination +- (void)linkItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination { void *pool = objc_autoreleasePoolPush(); - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; if (source == nil || destination == nil) @throw [OFInvalidArgumentException exception]; if (![destination.scheme isEqual: source.scheme]) @throw [OFInvalidArgumentException exception]; - URIHandler = [OFURIHandler handlerForURI: source]; + IRIHandler = [OFIRIHandler handlerForIRI: source]; - if (URIHandler == nil) + if (IRIHandler == nil) @throw [OFUnsupportedProtocolException - exceptionWithURI: source]; + exceptionWithIRI: source]; - [URIHandler linkItemAtURI: source toURI: destination]; + [IRIHandler linkItemAtIRI: source toIRI: destination]; objc_autoreleasePoolPop(pool); } #ifdef OF_FILE_MANAGER_SUPPORTS_LINKS - (void)linkItemAtPath: (OFString *)source toPath: (OFString *)destination { void *pool = objc_autoreleasePoolPush(); - [self linkItemAtURI: [OFURI fileURIWithPath: source] - toURI: [OFURI fileURIWithPath: destination]]; + [self linkItemAtIRI: [OFIRI fileIRIWithPath: source] + toIRI: [OFIRI fileIRIWithPath: destination]]; objc_autoreleasePoolPop(pool); } #endif -- (void)createSymbolicLinkAtURI: (OFURI *)URI +- (void)createSymbolicLinkAtIRI: (OFIRI *)IRI withDestinationPath: (OFString *)target { void *pool = objc_autoreleasePoolPush(); - OFURIHandler *URIHandler; + OFIRIHandler *IRIHandler; - if (URI == nil || target == nil) + if (IRI == nil || target == nil) @throw [OFInvalidArgumentException exception]; - URIHandler = [OFURIHandler handlerForURI: URI]; + IRIHandler = [OFIRIHandler handlerForIRI: IRI]; - if (URIHandler == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + if (IRIHandler == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; - [URIHandler createSymbolicLinkAtURI: URI withDestinationPath: target]; + [IRIHandler createSymbolicLinkAtIRI: IRI withDestinationPath: target]; objc_autoreleasePoolPop(pool); } #ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS - (void)createSymbolicLinkAtPath: (OFString *)path withDestinationPath: (OFString *)target { void *pool = objc_autoreleasePoolPush(); - [self createSymbolicLinkAtURI: [OFURI fileURIWithPath: path] + [self createSymbolicLinkAtIRI: [OFIRI fileIRIWithPath: path] withDestinationPath: target]; objc_autoreleasePoolPop(pool); } #endif + +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OFIRIHandler *IRIHandler; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; + + return [IRIHandler extendedAttributeDataForName: name ofItemAtIRI: IRI]; +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFData *ret; + + ret = [self + extendedAttributeDataForName: name + ofItemAtIRI: [OFIRI fileIRIWithPath: path]]; + ret = [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} +#endif + +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OFIRIHandler *IRIHandler; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; + + [IRIHandler setExtendedAttributeData: data + forName: name + ofItemAtIRI: IRI]; +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + [self setExtendedAttributeData: data + forName: name + ofItemAtIRI: [OFIRI fileIRIWithPath: path]]; + objc_autoreleasePoolPop(pool); +} +#endif + +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OFIRIHandler *IRIHandler; + + if (IRI == nil) + @throw [OFInvalidArgumentException exception]; + + if ((IRIHandler = [OFIRIHandler handlerForIRI: IRI]) == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; + + [IRIHandler removeExtendedAttributeForName: name ofItemAtIRI: IRI]; +} + +#ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + [self removeExtendedAttributeForName: name + ofItemAtIRI: [OFIRI fileIRIWithPath: path]]; + objc_autoreleasePoolPop(pool); +} +#endif @end @implementation OFDefaultFileManager - (instancetype)autorelease { @@ -970,6 +1078,11 @@ - (OFString *)fileSymbolicLinkDestination { return attributeForKeyOrException(self, OFFileSymbolicLinkDestination); } + +- (OFArray OF_GENERIC(OFString *) *)fileExtendedAttributesNames +{ + return attributeForKeyOrException(self, OFFileExtendedAttributesNames); +} @end Index: src/OFFileManagerConstants.inc ================================================================== --- src/OFFileManagerConstants.inc +++ src/OFFileManagerConstants.inc @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -26,10 +26,12 @@ const OFFileAttributeKey OFFileModificationDate = @"OFFileModificationDate"; const OFFileAttributeKey OFFileStatusChangeDate = @"OFFileStatusChangeDate"; const OFFileAttributeKey OFFileCreationDate = @"OFFileCreationDate"; const OFFileAttributeKey OFFileSymbolicLinkDestination = @"OFFileSymbolicLinkDestination"; +const OFFileAttributeKey OFFileExtendedAttributesNames = + @"OFFileExtendedAttributesNames"; const OFFileAttributeType OFFileTypeRegular = @"OFFileTypeRegular"; const OFFileAttributeType OFFileTypeDirectory = @"OFFileTypeDirectory"; const OFFileAttributeType OFFileTypeSymbolicLink = @"OFFileTypeSymbolicLink"; const OFFileAttributeType OFFileTypeFIFO = @"OFFileTypeFIFO"; DELETED src/OFFileURIHandler.h Index: src/OFFileURIHandler.h ================================================================== --- src/OFFileURIHandler.h +++ src/OFFileURIHandler.h @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURIHandler.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFFileURIHandler: OFURIHandler -+ (bool)of_directoryExistsAtPath: (OFString *)path OF_DIRECT; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFFileURIHandler.m Index: src/OFFileURIHandler.m ================================================================== --- src/OFFileURIHandler.m +++ src/OFFileURIHandler.m @@ -1,1476 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#define _LARGEFILE64_SOURCE - -#include -#include - -#ifdef HAVE_DIRENT_H -# include -#endif -#include "unistd_wrapper.h" - -#include "platform.h" -#ifdef HAVE_SYS_STAT_H -# include -#endif -#include -#ifdef OF_WINDOWS -# include -#endif - -#ifdef HAVE_PWD_H -# include -#endif -#ifdef HAVE_GRP_H -# include -#endif - -#import "OFFileURIHandler.h" -#import "OFArray.h" -#import "OFDate.h" -#import "OFFile.h" -#import "OFFileManager.h" -#import "OFLocale.h" -#import "OFNumber.h" -#import "OFSystemInfo.h" -#import "OFURI.h" - -#ifdef OF_HAVE_THREADS -# import "OFMutex.h" -#endif - -#import "OFCreateDirectoryFailedException.h" -#import "OFCreateSymbolicLinkFailedException.h" -#import "OFGetItemAttributesFailedException.h" -#import "OFInitializationFailedException.h" -#import "OFInvalidArgumentException.h" -#import "OFLinkItemFailedException.h" -#import "OFMoveItemFailedException.h" -#import "OFNotImplementedException.h" -#import "OFOpenItemFailedException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" -#import "OFRemoveItemFailedException.h" -#import "OFSetItemAttributesFailedException.h" - -#ifdef OF_WINDOWS -# include -# include -# include -# include -#endif - -#ifdef OF_AMIGAOS -# include -# include -# include -# ifdef OF_AMIGAOS4 -# define DeleteFile(path) Delete(path) -# endif -#endif - -#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) -typedef struct { - OFStreamOffset st_size; - unsigned int st_mode; - OFTimeInterval st_atime, st_mtime, st_ctime; -# ifdef OF_WINDOWS -# define HAVE_STRUCT_STAT_ST_BIRTHTIME - OFTimeInterval st_birthtime; - DWORD fileAttributes; -# endif -} Stat; -#elif defined(HAVE_STAT64) -typedef struct stat64 Stat; -#else -typedef struct stat Stat; -#endif - -#ifdef OF_WINDOWS -# define S_IFLNK 0x10000 -# define S_ISLNK(mode) (mode & S_IFLNK) -#endif - -#if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) -static OFMutex *passwdMutex; - -static void -releasePasswdMutex(void) -{ - [passwdMutex release]; -} -#endif -#if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) && !defined(OF_WINDOWS) -static OFMutex *readdirMutex; - -static void -releaseReaddirMutex(void) -{ - [readdirMutex release]; -} -#endif - -#ifdef OF_WINDOWS -static int (*_wutime64FuncPtr)(const wchar_t *, struct __utimbuf64 *); -static WINAPI BOOLEAN (*createSymbolicLinkWFuncPtr)(LPCWSTR, LPCWSTR, DWORD); -static WINAPI BOOLEAN (*createHardLinkWFuncPtr)(LPCWSTR, LPCWSTR, - LPSECURITY_ATTRIBUTES); -#endif - -#ifdef OF_WINDOWS -static OFTimeInterval -filetimeToTimeInterval(const FILETIME *filetime) -{ - return (double)((int64_t)filetime->dwHighDateTime << 32 | - filetime->dwLowDateTime) / 10000000.0 - 11644473600.0; -} - -static int -lastError(void) -{ - switch (GetLastError()) { - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - case ERROR_NO_MORE_FILES: - return ENOENT; - case ERROR_ACCESS_DENIED: - return EACCES; - case ERROR_DIRECTORY: - return ENOTDIR; - case ERROR_NOT_READY: - return EBUSY; - default: - return EIO; - } -} -#endif - -#ifdef OF_AMIGAOS -static int -lastError(void) -{ - switch (IoErr()) { - case ERROR_DELETE_PROTECTED: - case ERROR_READ_PROTECTED: - case ERROR_WRITE_PROTECTED: - return EACCES; - case ERROR_DISK_NOT_VALIDATED: - case ERROR_OBJECT_IN_USE: - return EBUSY; - case ERROR_OBJECT_EXISTS: - return EEXIST; - case ERROR_DIR_NOT_FOUND: - case ERROR_NO_MORE_ENTRIES: - case ERROR_OBJECT_NOT_FOUND: - return ENOENT; - case ERROR_NO_FREE_STORE: - return ENOMEM; - case ERROR_DISK_FULL: - return ENOSPC; - case ERROR_DIRECTORY_NOT_EMPTY: - return ENOTEMPTY; - case ERROR_DISK_WRITE_PROTECTED: - return EROFS; - case ERROR_RENAME_ACROSS_DEVICES: - return EXDEV; - default: - return EIO; - } -} -#endif - -static int -statWrapper(OFString *path, Stat *buffer) -{ -#if defined(OF_WINDOWS) - WIN32_FILE_ATTRIBUTE_DATA data; - bool success; - - if ([OFSystemInfo isWindowsNT]) - success = GetFileAttributesExW(path.UTF16String, - GetFileExInfoStandard, &data); - else - success = GetFileAttributesExA( - [path cStringWithEncoding: [OFLocale encoding]], - GetFileExInfoStandard, &data); - - if (!success) - return lastError(); - - buffer->st_size = (uint64_t)data.nFileSizeHigh << 32 | - data.nFileSizeLow; - - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - buffer->st_mode = S_IFDIR; - else if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - /* - * No need to use A functions in this branch: This is only - * available on NTFS (and hence Windows NT) anyway. - */ - WIN32_FIND_DATAW findData; - HANDLE findHandle; - - if ((findHandle = FindFirstFileW(path.UTF16String, - &findData)) == INVALID_HANDLE_VALUE) - return lastError(); - - @try { - if (!(findData.dwFileAttributes & - FILE_ATTRIBUTE_REPARSE_POINT)) - /* Race? Indicate to try again. */ - return EAGAIN; - - buffer->st_mode = - (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK - ? S_IFLNK : S_IFREG); - } @finally { - FindClose(findHandle); - } - } else - buffer->st_mode = S_IFREG; - - buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY - ? (S_IRUSR | S_IXUSR) : (S_IRUSR | S_IWUSR | S_IXUSR)); - - buffer->st_atime = filetimeToTimeInterval(&data.ftLastAccessTime); - buffer->st_mtime = filetimeToTimeInterval(&data.ftLastWriteTime); - buffer->st_ctime = buffer->st_birthtime = - filetimeToTimeInterval(&data.ftCreationTime); - buffer->fileAttributes = data.dwFileAttributes; - - return 0; -#elif defined(OF_AMIGAOS) - BPTR lock; -# ifdef OF_AMIGAOS4 - struct ExamineData *ed; -# else - struct FileInfoBlock fib; -# endif - OFTimeInterval timeInterval; - struct Locale *locale; - struct DateStamp *date; - - if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], - SHARED_LOCK)) == 0) - return lastError(); - -# if defined(OF_MORPHOS) - if (!Examine64(lock, &fib, TAG_DONE)) { -# elif defined(OF_AMIGAOS4) - if ((ed = ExamineObjectTags(EX_FileLockInput, lock, TAG_END)) == NULL) { -# else - if (!Examine(lock, &fib)) { -# endif - int error = lastError(); - UnLock(lock); - return error; - } - - UnLock(lock); - -# if defined(OF_MORPHOS) - buffer->st_size = fib.fib_Size64; -# elif defined(OF_AMIGAOS4) - buffer->st_size = ed->FileSize; -# else - buffer->st_size = fib.fib_Size; -# endif -# ifdef OF_AMIGAOS4 - buffer->st_mode = (EXD_IS_DIRECTORY(ed) ? S_IFDIR : S_IFREG); -# else - buffer->st_mode = (fib.fib_DirEntryType > 0 ? S_IFDIR : S_IFREG); -# endif - - timeInterval = 252460800; /* 1978-01-01 */ - - locale = OpenLocale(NULL); - /* - * FIXME: This does not take DST into account. But unfortunately, there - * is no way to figure out if DST was in effect when the file was - * modified. - */ - timeInterval += locale->loc_GMTOffset * 60.0; - CloseLocale(locale); - -# ifdef OF_AMIGAOS4 - date = &ed->Date; -# else - date = &fib.fib_Date; -# endif - timeInterval += date->ds_Days * 86400.0; - timeInterval += date->ds_Minute * 60.0; - timeInterval += date->ds_Tick / (OFTimeInterval)TICKS_PER_SECOND; - - buffer->st_atime = buffer->st_mtime = buffer->st_ctime = timeInterval; - -# ifdef OF_AMIGAOS4 - FreeDosObject(DOS_EXAMINEDATA, ed); -# endif - - return 0; -#elif defined(HAVE_STAT64) - if (stat64([path cStringWithEncoding: [OFLocale encoding]], - buffer) != 0) - return errno; - - return 0; -#else - if (stat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) - return errno; - - return 0; -#endif -} - -static int -lstatWrapper(OFString *path, Stat *buffer) -{ -#if defined(HAVE_LSTAT) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && \ - !defined(OF_NINTENDO_3DS) && !defined(OF_WII) -# ifdef HAVE_LSTAT64 - if (lstat64([path cStringWithEncoding: [OFLocale encoding]], - buffer) != 0) - return errno; -# else - if (lstat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) - return errno; -# endif - - return 0; -#else - return statWrapper(path, buffer); -#endif -} - -static void -setTypeAttribute(OFMutableFileAttributes attributes, Stat *s) -{ - if (S_ISREG(s->st_mode)) - [attributes setObject: OFFileTypeRegular forKey: OFFileType]; - else if (S_ISDIR(s->st_mode)) - [attributes setObject: OFFileTypeDirectory forKey: OFFileType]; -#ifdef S_ISLNK - else if (S_ISLNK(s->st_mode)) - [attributes setObject: OFFileTypeSymbolicLink - forKey: OFFileType]; -#endif -#ifdef S_ISFIFO - else if (S_ISFIFO(s->st_mode)) - [attributes setObject: OFFileTypeFIFO forKey: OFFileType]; -#endif -#ifdef S_ISCHR - else if (S_ISCHR(s->st_mode)) - [attributes setObject: OFFileTypeCharacterSpecial - forKey: OFFileType]; -#endif -#ifdef S_ISBLK - else if (S_ISBLK(s->st_mode)) - [attributes setObject: OFFileTypeBlockSpecial - forKey: OFFileType]; -#endif -#ifdef S_ISSOCK - else if (S_ISSOCK(s->st_mode)) - [attributes setObject: OFFileTypeSocket forKey: OFFileType]; -#endif - else - [attributes setObject: OFFileTypeUnknown forKey: OFFileType]; -} - -static void -setDateAttributes(OFMutableFileAttributes attributes, Stat *s) -{ - /* FIXME: We could be more precise on some OSes */ - [attributes - setObject: [OFDate dateWithTimeIntervalSince1970: s->st_atime] - forKey: OFFileLastAccessDate]; - [attributes - setObject: [OFDate dateWithTimeIntervalSince1970: s->st_mtime] - forKey: OFFileModificationDate]; - [attributes - setObject: [OFDate dateWithTimeIntervalSince1970: s->st_ctime] - forKey: OFFileStatusChangeDate]; -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME - [attributes - setObject: [OFDate dateWithTimeIntervalSince1970: s->st_birthtime] - forKey: OFFileCreationDate]; -#endif -} - -static void -setOwnerAndGroupAttributes(OFMutableFileAttributes attributes, Stat *s) -{ -#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_uid] - forKey: OFFileOwnerAccountID]; - [attributes setObject: [NSNumber numberWithUnsignedLong: s->st_gid] - forKey: OFFileGroupOwnerAccountID]; - -# ifdef OF_HAVE_THREADS - [passwdMutex lock]; - @try { -# endif - OFStringEncoding encoding = [OFLocale encoding]; - struct passwd *passwd = getpwuid(s->st_uid); - struct group *group_ = getgrgid(s->st_gid); - - if (passwd != NULL) { - OFString *owner = [OFString - stringWithCString: passwd->pw_name - encoding: encoding]; - - [attributes setObject: owner - forKey: OFFileOwnerAccountName]; - } - - if (group_ != NULL) { - OFString *group = [OFString - stringWithCString: group_->gr_name - encoding: encoding]; - - [attributes setObject: group - forKey: OFFileGroupOwnerAccountName]; - } -# ifdef OF_HAVE_THREADS - } @finally { - [passwdMutex unlock]; - } -# endif -#endif -} - -#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS -static void -setSymbolicLinkDestinationAttribute(OFMutableFileAttributes attributes, - OFURI *URI) -{ - OFString *path = URI.fileSystemRepresentation; -# ifndef OF_WINDOWS - OFStringEncoding encoding = [OFLocale encoding]; - char destinationC[PATH_MAX]; - ssize_t length; - OFString *destination; - - length = readlink([path cStringWithEncoding: encoding], destinationC, - PATH_MAX); - - if (length < 0) - @throw [OFGetItemAttributesFailedException - exceptionWithURI: URI - errNo: errno]; - - destination = [OFString stringWithCString: destinationC - encoding: encoding - length: length]; - - [attributes setObject: destination - forKey: OFFileSymbolicLinkDestination]; -# else - HANDLE handle; - OFString *destination; - - if (createSymbolicLinkWFuncPtr == NULL) - return; - - if ((handle = CreateFileW(path.UTF16String, 0, (FILE_SHARE_READ | - FILE_SHARE_WRITE), NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT, NULL)) == INVALID_HANDLE_VALUE) - @throw [OFGetItemAttributesFailedException - exceptionWithURI: URI - errNo: lastError()]; - - @try { - union { - char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - REPARSE_DATA_BUFFER data; - } buffer; - DWORD size; - wchar_t *tmp; - - if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, - buffer.bytes, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, - NULL)) - @throw [OFGetItemAttributesFailedException - exceptionWithURI: URI - errNo: lastError()]; - - if (buffer.data.ReparseTag != IO_REPARSE_TAG_SYMLINK) - @throw [OFGetItemAttributesFailedException - exceptionWithURI: URI - errNo: lastError()]; - -# define slrb buffer.data.SymbolicLinkReparseBuffer - tmp = slrb.PathBuffer + - (slrb.SubstituteNameOffset / sizeof(wchar_t)); - - destination = [OFString - stringWithUTF16String: tmp - length: slrb.SubstituteNameLength / - sizeof(wchar_t)]; - - [attributes setObject: OFFileTypeSymbolicLink - forKey: OFFileType]; - [attributes setObject: destination - forKey: OFFileSymbolicLinkDestination]; -# undef slrb - } @finally { - CloseHandle(handle); - } -# endif -} -#endif - -@implementation OFFileURIHandler -+ (void)initialize -{ -#ifdef OF_WINDOWS - HMODULE module; -#endif - - if (self != [OFFileURIHandler class]) - return; - -#if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) - passwdMutex = [[OFMutex alloc] init]; - atexit(releasePasswdMutex); -#endif -#if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) - readdirMutex = [[OFMutex alloc] init]; - atexit(releaseReaddirMutex); -#endif - -#ifdef OF_WINDOWS - if ((module = LoadLibrary("msvcrt.dll")) != NULL) - _wutime64FuncPtr = (int (*)(const wchar_t *, - struct __utimbuf64 *))GetProcAddress(module, "_wutime64"); - - if ((module = LoadLibrary("kernel32.dll")) != NULL) { - createSymbolicLinkWFuncPtr = - (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD)) - GetProcAddress(module, "CreateSymbolicLinkW"); - createHardLinkWFuncPtr = - (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, - LPSECURITY_ATTRIBUTES)) - GetProcAddress(module, "CreateHardLinkW"); - } -#endif - - /* - * Make sure OFFile is initialized. - * On some systems, this is needed to initialize the file system driver. - */ - [OFFile class]; -} - -+ (bool)of_directoryExistsAtPath: (OFString *)path -{ - Stat s; - - if (statWrapper(path, &s) != 0) - return false; - - return S_ISDIR(s.st_mode); -} - -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - void *pool = objc_autoreleasePoolPush(); - OFFile *file = [[OFFile alloc] - initWithPath: URI.fileSystemRepresentation - mode: mode]; - - objc_autoreleasePoolPop(pool); - - return [file autorelease]; -} - -- (OFFileAttributes)attributesOfItemAtURI: (OFURI *)URI -{ - OFMutableFileAttributes ret = [OFMutableDictionary dictionary]; - void *pool = objc_autoreleasePoolPush(); - OFString *path; - int error; - Stat s; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![[URI scheme] isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - path = URI.fileSystemRepresentation; - - if ((error = lstatWrapper(path, &s)) != 0) - @throw [OFGetItemAttributesFailedException - exceptionWithURI: URI - errNo: error]; - - if (s.st_size < 0) - @throw [OFOutOfRangeException exception]; - - [ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size] - forKey: OFFileSize]; - - setTypeAttribute(ret, &s); - - [ret setObject: [NSNumber numberWithUnsignedLong: s.st_mode] - forKey: OFFilePOSIXPermissions]; - - setOwnerAndGroupAttributes(ret, &s); - setDateAttributes(ret, &s); - -#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS - if (S_ISLNK(s.st_mode)) - setSymbolicLinkDestinationAttribute(ret, URI); -#endif - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (void)of_setLastAccessDate: (OFDate *)lastAccessDate - andModificationDate: (OFDate *)modificationDate - ofItemAtURI: (OFURI *)URI - attributes: (OFFileAttributes)attributes OF_DIRECT -{ - OFString *path = URI.fileSystemRepresentation; - OFFileAttributeKey attributeKey = (modificationDate != nil - ? OFFileModificationDate : OFFileLastAccessDate); - - if (lastAccessDate == nil) - lastAccessDate = modificationDate; - if (modificationDate == nil) - modificationDate = lastAccessDate; - -#if defined(OF_WINDOWS) - if (_wutime64FuncPtr != NULL) { - struct __utimbuf64 times = { - .actime = - (__time64_t)lastAccessDate.timeIntervalSince1970, - .modtime = - (__time64_t)modificationDate.timeIntervalSince1970 - }; - - if (_wutime64FuncPtr([path UTF16String], ×) != 0) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; - } else { - struct _utimbuf times = { - .actime = (time_t)lastAccessDate.timeIntervalSince1970, - .modtime = - (time_t)modificationDate.timeIntervalSince1970 - }; - int status; - - if ([OFSystemInfo isWindowsNT]) - status = _wutime([path UTF16String], ×); - else - status = _utime( - [path cStringWithEncoding: [OFLocale encoding]], - ×); - - if (status != 0) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; - } -#elif defined(OF_AMIGAOS) - /* AmigaOS does not support access time. */ - OFTimeInterval modificationTime = - modificationDate.timeIntervalSince1970; - struct Locale *locale; - struct DateStamp date; - - modificationTime -= 252460800; /* 1978-01-01 */ - - if (modificationTime < 0) - @throw [OFOutOfRangeException exception]; - - locale = OpenLocale(NULL); - /* - * FIXME: This does not take DST into account. But unfortunately, there - * is no way to figure out if DST should be in effect for the - * timestamp. - */ - modificationTime -= locale->loc_GMTOffset * 60.0; - CloseLocale(locale); - - date.ds_Days = modificationTime / 86400; - date.ds_Minute = ((LONG)modificationTime % 86400) / 60; - date.ds_Tick = fmod(modificationTime, 60) * TICKS_PER_SECOND; - -# ifdef OF_AMIGAOS4 - if (!SetDate([path cStringWithEncoding: [OFLocale encoding]], - &date) != 0) -# else - if (!SetFileDate([path cStringWithEncoding: [OFLocale encoding]], - &date) != 0) -# endif - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: lastError()]; -#else - OFTimeInterval lastAccessTime = lastAccessDate.timeIntervalSince1970; - OFTimeInterval modificationTime = - modificationDate.timeIntervalSince1970; - struct timeval times[2] = { - { - .tv_sec = (time_t)lastAccessTime, - .tv_usec = - (int)((lastAccessTime - times[0].tv_sec) * 1000000) - }, - { - .tv_sec = (time_t)modificationTime, - .tv_usec = (int)((modificationTime - times[1].tv_sec) * - 1000000) - }, - }; - - if (utimes([path cStringWithEncoding: [OFLocale encoding]], times) != 0) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; -#endif -} - -- (void)of_setPOSIXPermissions: (OFNumber *)permissions - ofItemAtURI: (OFURI *)URI - attributes: (OFFileAttributes)attributes OF_DIRECT -{ -#ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS - mode_t mode = (mode_t)permissions.unsignedLongValue; - OFString *path = URI.fileSystemRepresentation; - int status; - -# ifdef OF_WINDOWS - if ([OFSystemInfo isWindowsNT]) - status = _wchmod(path.UTF16String, mode); - else -# endif - status = chmod( - [path cStringWithEncoding: [OFLocale encoding]], mode); - - if (status != 0) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: OFFilePOSIXPermissions - errNo: errno]; -#else - OF_UNRECOGNIZED_SELECTOR -#endif -} - -- (void)of_setOwnerAccountName: (OFString *)owner - andGroupOwnerAccountName: (OFString *)group - ofItemAtURI: (OFURI *)URI - attributeKey: (OFFileAttributeKey)attributeKey - attributes: (OFFileAttributes)attributes OF_DIRECT -{ -#ifdef OF_FILE_MANAGER_SUPPORTS_OWNER - OFString *path = URI.fileSystemRepresentation; - uid_t uid = -1; - gid_t gid = -1; - OFStringEncoding encoding; - - if (owner == nil && group == nil) - @throw [OFInvalidArgumentException exception]; - - encoding = [OFLocale encoding]; - -# ifdef OF_HAVE_THREADS - [passwdMutex lock]; - @try { -# endif - if (owner != nil) { - struct passwd *passwd; - - if ((passwd = getpwnam([owner - cStringWithEncoding: encoding])) == NULL) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; - - uid = passwd->pw_uid; - } - - if (group != nil) { - struct group *group_; - - if ((group_ = getgrnam([group - cStringWithEncoding: encoding])) == NULL) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; - - gid = group_->gr_gid; - } -# ifdef OF_HAVE_THREADS - } @finally { - [passwdMutex unlock]; - } -# endif - - if (chown([path cStringWithEncoding: encoding], uid, gid) != 0) - @throw [OFSetItemAttributesFailedException - exceptionWithURI: URI - attributes: attributes - failedAttribute: attributeKey - errNo: errno]; -#else - OF_UNRECOGNIZED_SELECTOR -#endif -} - -- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURI: (OFURI *)URI -{ - void *pool = objc_autoreleasePoolPush(); - OFEnumerator OF_GENERIC(OFFileAttributeKey) *keyEnumerator; - OFEnumerator *objectEnumerator; - OFFileAttributeKey key; - id object; - OFDate *lastAccessDate, *modificationDate; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - keyEnumerator = [attributes keyEnumerator]; - objectEnumerator = [attributes objectEnumerator]; - - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) { - if ([key isEqual: OFFileModificationDate] || - [key isEqual: OFFileLastAccessDate]) - continue; - else if ([key isEqual: OFFilePOSIXPermissions]) - [self of_setPOSIXPermissions: object - ofItemAtURI: URI - attributes: attributes]; - else if ([key isEqual: OFFileOwnerAccountName]) - [self of_setOwnerAccountName: object - andGroupOwnerAccountName: nil - ofItemAtURI: URI - attributeKey: key - attributes: attributes]; - else if ([key isEqual: OFFileGroupOwnerAccountName]) - [self of_setOwnerAccountName: nil - andGroupOwnerAccountName: object - ofItemAtURI: URI - attributeKey: key - attributes: attributes]; - else - @throw [OFNotImplementedException - exceptionWithSelector: _cmd - object: self]; - } - - lastAccessDate = [attributes objectForKey: OFFileLastAccessDate]; - modificationDate = [attributes objectForKey: OFFileModificationDate]; - - if (lastAccessDate != nil || modificationDate != nil) - [self of_setLastAccessDate: lastAccessDate - andModificationDate: modificationDate - ofItemAtURI: URI - attributes: attributes]; - - objc_autoreleasePoolPop(pool); -} - -- (bool)fileExistsAtURI: (OFURI *)URI -{ - void *pool = objc_autoreleasePoolPush(); - Stat s; - bool ret; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - if (statWrapper(URI.fileSystemRepresentation, &s) != 0) { - objc_autoreleasePoolPop(pool); - return false; - } - - ret = S_ISREG(s.st_mode); - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (bool)directoryExistsAtURI: (OFURI *)URI -{ - void *pool = objc_autoreleasePoolPush(); - Stat s; - bool ret; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - if (statWrapper(URI.fileSystemRepresentation, &s) != 0) { - objc_autoreleasePoolPop(pool); - return false; - } - - ret = S_ISDIR(s.st_mode); - - objc_autoreleasePoolPop(pool); - - return ret; -} - -- (void)createDirectoryAtURI: (OFURI *)URI -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - path = URI.fileSystemRepresentation; - -#if defined(OF_WINDOWS) - int status; - - if ([OFSystemInfo isWindowsNT]) - status = _wmkdir(path.UTF16String); - else - status = _mkdir( - [path cStringWithEncoding: [OFLocale encoding]]); - - if (status != 0) - @throw [OFCreateDirectoryFailedException - exceptionWithURI: URI - errNo: errno]; -#elif defined(OF_AMIGAOS) - BPTR lock; - - if ((lock = CreateDir( - [path cStringWithEncoding: [OFLocale encoding]])) == 0) - @throw [OFCreateDirectoryFailedException - exceptionWithURI: URI - errNo: lastError()]; - - UnLock(lock); -#else - if (mkdir([path cStringWithEncoding: [OFLocale encoding]], 0777) != 0) - @throw [OFCreateDirectoryFailedException - exceptionWithURI: URI - errNo: errno]; -#endif - - objc_autoreleasePoolPop(pool); -} - -- (OFArray OF_GENERIC(OFURI *) *)contentsOfDirectoryAtURI: (OFURI *)URI -{ - OFMutableArray *URIs = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - OFString *path; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - path = URI.fileSystemRepresentation; - -#if defined(OF_WINDOWS) - HANDLE handle; - - path = [path stringByAppendingString: @"\\*"]; - - if ([OFSystemInfo isWindowsNT]) { - WIN32_FIND_DATAW fd; - - if ((handle = FindFirstFileW(path.UTF16String, - &fd)) == INVALID_HANDLE_VALUE) - @throw [OFOpenItemFailedException - exceptionWithURI: URI - mode: nil - errNo: lastError()]; - - @try { - do { - OFString *file; - - if (wcscmp(fd.cFileName, L".") == 0 || - wcscmp(fd.cFileName, L"..") == 0) - continue; - - file = [[OFString alloc] - initWithUTF16String: fd.cFileName]; - @try { - [URIs addObject: [URI - URIByAppendingPathComponent: file]]; - } @finally { - [file release]; - } - } while (FindNextFileW(handle, &fd)); - - if (GetLastError() != ERROR_NO_MORE_FILES) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: 0 - errNo: lastError()]; - } @finally { - FindClose(handle); - } - } else { - OFStringEncoding encoding = [OFLocale encoding]; - WIN32_FIND_DATA fd; - - if ((handle = FindFirstFileA( - [path cStringWithEncoding: encoding], &fd)) == - INVALID_HANDLE_VALUE) - @throw [OFOpenItemFailedException - exceptionWithURI: URI - mode: nil - errNo: lastError()]; - - @try { - do { - OFString *file; - - if (strcmp(fd.cFileName, ".") == 0 || - strcmp(fd.cFileName, "..") == 0) - continue; - - file = [[OFString alloc] - initWithCString: fd.cFileName - encoding: encoding]; - @try { - [URIs addObject: [URI - URIByAppendingPathComponent: file]]; - } @finally { - [file release]; - } - } while (FindNextFileA(handle, &fd)); - - if (GetLastError() != ERROR_NO_MORE_FILES) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: 0 - errNo: lastError()]; - } @finally { - FindClose(handle); - } - } -#elif defined(OF_AMIGAOS) - OFStringEncoding encoding = [OFLocale encoding]; - BPTR lock; - - if ((lock = Lock([path cStringWithEncoding: encoding], - SHARED_LOCK)) == 0) - @throw [OFOpenItemFailedException - exceptionWithURI: URI - mode: nil - errNo: lastError()]; - - @try { -# ifdef OF_AMIGAOS4 - struct ExamineData *ed; - APTR context; - - if ((context = ObtainDirContextTags(EX_FileLockInput, lock, - EX_DoCurrentDir, TRUE, EX_DataFields, EXF_NAME, - TAG_END)) == NULL) - @throw [OFOpenItemFailedException - exceptionWithURI: URI - mode: nil - errNo: lastError()]; - - @try { - while ((ed = ExamineDir(context)) != NULL) { - OFString *file = [[OFString alloc] - initWithCString: ed->Name - encoding: encoding]; - - @try { - [URIs addObject: [URI - URIByAppendingPathComponent: file]]; - } @finally { - [file release]; - } - } - } @finally { - ReleaseDirContext(context); - } -# else - struct FileInfoBlock fib; - - if (!Examine(lock, &fib)) - @throw [OFOpenItemFailedException - exceptionWithURI: URI - mode: nil - errNo: lastError()]; - - while (ExNext(lock, &fib)) { - OFString *file = [[OFString alloc] - initWithCString: fib.fib_FileName - encoding: encoding]; - @try { - [URIs addObject: - [URI URIByAppendingPathComponent: file]]; - } @finally { - [file release]; - } - } -# endif - - if (IoErr() != ERROR_NO_MORE_ENTRIES) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: 0 - errNo: lastError()]; - } @finally { - UnLock(lock); - } -#else - OFStringEncoding encoding = [OFLocale encoding]; - DIR *dir; - if ((dir = opendir([path cStringWithEncoding: encoding])) == NULL) - @throw [OFOpenItemFailedException exceptionWithURI: URI - mode: nil - errNo: errno]; - -# if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) - @try { - [readdirMutex lock]; - } @catch (id e) { - closedir(dir); - @throw e; - } -# endif - - @try { - for (;;) { - struct dirent *dirent; -# ifdef HAVE_READDIR_R - struct dirent buffer; -# endif - OFString *file; - -# ifdef HAVE_READDIR_R - if (readdir_r(dir, &buffer, &dirent) != 0) - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: 0 - errNo: errno]; - - if (dirent == NULL) - break; -# else - errno = 0; - if ((dirent = readdir(dir)) == NULL) { - if (errno == 0) - break; - else - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: 0 - errNo: errno]; - } -# endif - - if (strcmp(dirent->d_name, ".") == 0 || - strcmp(dirent->d_name, "..") == 0) - continue; - - file = [[OFString alloc] initWithCString: dirent->d_name - encoding: encoding]; - @try { - [URIs addObject: - [URI URIByAppendingPathComponent: file]]; - } @finally { - [file release]; - } - } - } @finally { - closedir(dir); -# if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) - [readdirMutex unlock]; -# endif - } -#endif - - [URIs makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return URIs; -} - -- (void)removeItemAtURI: (OFURI *)URI -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path; - int error; - Stat s; - - if (URI == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - path = URI.fileSystemRepresentation; - - if ((error = lstatWrapper(path, &s)) != 0) - @throw [OFRemoveItemFailedException exceptionWithURI: URI - errNo: error]; - - if (S_ISDIR(s.st_mode)) { - OFArray OF_GENERIC(OFURI *) *contents; - - @try { - contents = [self contentsOfDirectoryAtURI: URI]; - } @catch (id e) { - /* - * Only convert exceptions to - * OFRemoveItemFailedException that have an errNo - * property. This covers all I/O related exceptions - * from the operations used to remove an item, all - * others should be left as is. - */ - if ([e respondsToSelector: @selector(errNo)]) - @throw [OFRemoveItemFailedException - exceptionWithURI: URI - errNo: [e errNo]]; - - @throw e; - } - - for (OFURI *item in contents) { - void *pool2 = objc_autoreleasePoolPush(); - - [self removeItemAtURI: item]; - - objc_autoreleasePoolPop(pool2); - } - -#ifndef OF_AMIGAOS - int status; - -# ifdef OF_WINDOWS - if ([OFSystemInfo isWindowsNT]) - status = _wrmdir(path.UTF16String); - else -# endif - status = rmdir( - [path cStringWithEncoding: [OFLocale encoding]]); - - if (status != 0) - @throw [OFRemoveItemFailedException - exceptionWithURI: URI - errNo: errno]; - } else { - int status; - -# ifdef OF_WINDOWS - if ([OFSystemInfo isWindowsNT]) - status = _wunlink(path.UTF16String); - else -# endif - status = unlink( - [path cStringWithEncoding: [OFLocale encoding]]); - - if (status != 0) - @throw [OFRemoveItemFailedException - exceptionWithURI: URI - errNo: errno]; -#endif - } - -#ifdef OF_AMIGAOS - if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) - @throw [OFRemoveItemFailedException - exceptionWithURI: URI - errNo: lastError()]; -#endif - - objc_autoreleasePoolPop(pool); -} - -#ifdef OF_FILE_MANAGER_SUPPORTS_LINKS -- (void)linkItemAtURI: (OFURI *)source toURI: (OFURI *)destination -{ - void *pool = objc_autoreleasePoolPush(); - OFString *sourcePath, *destinationPath; - - if (source == nil || destination == nil) - @throw [OFInvalidArgumentException exception]; - - if (![source.scheme isEqual: _scheme] || - ![destination.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - sourcePath = source.fileSystemRepresentation; - destinationPath = destination.fileSystemRepresentation; - -# ifndef OF_WINDOWS - OFStringEncoding encoding = [OFLocale encoding]; - - if (link([sourcePath cStringWithEncoding: encoding], - [destinationPath cStringWithEncoding: encoding]) != 0) - @throw [OFLinkItemFailedException - exceptionWithSourceURI: source - destinationURI: destination - errNo: errno]; -# else - if (createHardLinkWFuncPtr == NULL) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; - - if (!createHardLinkWFuncPtr(destinationPath.UTF16String, - sourcePath.UTF16String, NULL)) - @throw [OFLinkItemFailedException - exceptionWithSourceURI: source - destinationURI: destination - errNo: lastError()]; -# endif - - objc_autoreleasePoolPop(pool); -} -#endif - -#ifdef OF_FILE_MANAGER_SUPPORTS_SYMLINKS -- (void)createSymbolicLinkAtURI: (OFURI *)URI - withDestinationPath: (OFString *)target -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path; - - if (URI == nil || target == nil) - @throw [OFInvalidArgumentException exception]; - - if (![URI.scheme isEqual: _scheme]) - @throw [OFInvalidArgumentException exception]; - - path = URI.fileSystemRepresentation; - -# ifndef OF_WINDOWS - OFStringEncoding encoding = [OFLocale encoding]; - - if (symlink([target cStringWithEncoding: encoding], - [path cStringWithEncoding: encoding]) != 0) - @throw [OFCreateSymbolicLinkFailedException - exceptionWithURI: URI - target: target - errNo: errno]; -# else - if (createSymbolicLinkWFuncPtr == NULL) - @throw [OFNotImplementedException exceptionWithSelector: _cmd - object: self]; - - if (!createSymbolicLinkWFuncPtr(path.UTF16String, target.UTF16String, - 0)) - @throw [OFCreateSymbolicLinkFailedException - exceptionWithURI: URI - target: target - errNo: lastError()]; -# endif - - objc_autoreleasePoolPop(pool); -} -#endif - -- (bool)moveItemAtURI: (OFURI *)source toURI: (OFURI *)destination -{ - void *pool; - - if (![source.scheme isEqual: _scheme] || - ![destination.scheme isEqual: _scheme]) - return false; - - if ([self fileExistsAtURI: destination]) - @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination - errNo: EEXIST]; - - pool = objc_autoreleasePoolPush(); - -#ifdef OF_AMIGAOS - OFStringEncoding encoding = [OFLocale encoding]; - - if (!Rename([source.fileSystemRepresentation - cStringWithEncoding: encoding], - [destination.fileSystemRepresentation - cStringWithEncoding: encoding])) - @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination - errNo: lastError()]; -#else - int status; - -# ifdef OF_WINDOWS - if ([OFSystemInfo isWindowsNT]) - status = _wrename(source.fileSystemRepresentation.UTF16String, - destination.fileSystemRepresentation.UTF16String); - else { -# endif - OFStringEncoding encoding = [OFLocale encoding]; - - status = rename([source.fileSystemRepresentation - cStringWithEncoding: encoding], - [destination.fileSystemRepresentation - cStringWithEncoding: encoding]); -# ifdef OF_WINDOWS - } -# endif - - if (status != 0) - @throw [OFMoveItemFailedException - exceptionWithSourceURI: source - destinationURI: destination - errNo: errno]; -#endif - - objc_autoreleasePoolPop(pool); - - return true; -} -@end Index: src/OFGZIPStream.h ================================================================== --- src/OFGZIPStream.h +++ src/OFGZIPStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHMAC.h ================================================================== --- src/OFHMAC.h +++ src/OFHMAC.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHMAC.m ================================================================== --- src/OFHMAC.m +++ src/OFHMAC.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHTTPClient.h ================================================================== --- src/OFHTTPClient.h +++ src/OFHTTPClient.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,14 +23,14 @@ @class OFDictionary OF_GENERIC(KeyType, ObjectType); @class OFHTTPClient; @class OFHTTPRequest; @class OFHTTPResponse; +@class OFIRI; @class OFStream; @class OFTCPSocket; @class OFTLSStream; -@class OFURI; /** * @protocol OFHTTPClientDelegate OFHTTPClient.h ObjFW/OFHTTPClient.h * * @brief A delegate for OFHTTPClient. @@ -117,22 +117,22 @@ * This callback will only be called if the OFHTTPClient will follow a * redirect. If the maximum number of redirects has been reached already, this * callback will not be called. * * @param client The OFHTTPClient which wants to follow a redirect - * @param URI The URI to which it will follow a redirect + * @param IRI The IRI to which it will follow a redirect * @param statusCode The status code for the redirection * @param request The request for which the OFHTTPClient wants to redirect. * You are allowed to change the request's headers from this * callback and they will be used when following the redirect - * (e.g. to set the cookies for the new URI), however, keep in + * (e.g. to set the cookies for the new IRI), however, keep in * mind that this will change the request you originally passed. * @param response The response indicating the redirect * @return A boolean whether the OFHTTPClient should follow the redirect */ - (bool)client: (OFHTTPClient *)client - shouldFollowRedirectToURI: (OFURI *)URI + shouldFollowRedirectToIRI: (OFIRI *)IRI statusCode: (short)statusCode request: (OFHTTPRequest *)request response: (OFHTTPResponse *)response; @end @@ -148,11 +148,11 @@ @public #endif OFObject *_Nullable _delegate; bool _allowsInsecureRedirects, _inProgress; OFStream *_Nullable _stream; - OFURI *_Nullable _lastURI; + OFIRI *_Nullable _lastIRI; bool _lastWasHEAD; OFHTTPResponse *_Nullable _lastResponse; } /** @@ -184,11 +184,11 @@ * @return The OFHTTPResponse for the request * @throw OFHTTPRequestFailedException The HTTP request failed * @throw OFInvalidServerResponseException The server sent an invalid response * @throw OFUnsupportedVersionException The server responded in an unsupported * version - * @throw OFAlreadyConnectedException The client is already performing a request + * @throw OFAlreadyOpenException The client is already performing a request */ - (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request; /** * @brief Synchronously performs the specified HTTP request. @@ -204,20 +204,20 @@ * @return The OFHTTPResponse for the request * @throw OFHTTPRequestFailedException The HTTP request failed * @throw OFInvalidServerResponseException The server sent an invalid response * @throw OFUnsupportedVersionException The server responded in an unsupported * version - * @throw OFAlreadyConnectedException The client is already performing a request + * @throw OFAlreadyOpenException The client is already performing a request */ - (OFHTTPResponse *)performRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects; /** * @brief Asynchronously performs the specified HTTP request. * * @param request The request to perform - * @throw OFAlreadyConnectedException The client is already performing a request + * @throw OFAlreadyOpenException The client is already performing a request */ - (void)asyncPerformRequest: (OFHTTPRequest *)request; /** * @brief Asynchronously performs the specified HTTP request. @@ -224,11 +224,11 @@ * * @param request The request to perform * @param redirects The maximum number of redirects after which no further * attempt is done to follow the redirect, but instead the * redirect is treated as an OFHTTPResponse - * @throw OFAlreadyConnectedException The client is already performing a request + * @throw OFAlreadyOpenException The client is already performing a request */ - (void)asyncPerformRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects; /** Index: src/OFHTTPClient.m ================================================================== --- src/OFHTTPClient.m +++ src/OFHTTPClient.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,19 +23,19 @@ #import "OFHTTPClient.h" #import "OFData.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" +#import "OFIRI.h" #import "OFKernelEventObserver.h" #import "OFNumber.h" #import "OFRunLoop.h" #import "OFString.h" #import "OFTCPSocket.h" #import "OFTLSStream.h" -#import "OFURI.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFInvalidServerResponseException.h" @@ -115,30 +115,30 @@ static OFString * constructRequestString(OFHTTPRequest *request) { void *pool = objc_autoreleasePoolPush(); OFHTTPRequestMethod method = request.method; - OFURI *URI = request.URI; + OFIRI *IRI = request.IRI.IRIByAddingPercentEncodingForUnicodeCharacters; OFString *path; - OFString *user = URI.user, *password = URI.password; + OFString *user = IRI.user, *password = IRI.password; OFMutableString *requestString; OFMutableDictionary OF_GENERIC(OFString *, OFString *) *headers; bool hasContentLength, chunked; OFEnumerator OF_GENERIC(OFString *) *keyEnumerator, *objectEnumerator; OFString *key, *object; - if (URI.path.length > 0) - path = URI.percentEncodedPath; + if (IRI.path.length > 0) + path = IRI.percentEncodedPath; else path = @"/"; requestString = [OFMutableString stringWithFormat: @"%s %@", OFHTTPRequestMethodName(method), path]; - if (URI.query != nil) { + if (IRI.query != nil) { [requestString appendString: @"?"]; - [requestString appendString: URI.percentEncodedQuery]; + [requestString appendString: IRI.percentEncodedQuery]; } [requestString appendString: @" HTTP/"]; [requestString appendString: request.protocolVersionString]; [requestString appendString: @"\r\n"]; @@ -146,19 +146,19 @@ headers = [[request.headers mutableCopy] autorelease]; if (headers == nil) headers = [OFMutableDictionary dictionary]; if ([headers objectForKey: @"Host"] == nil) { - OFNumber *port = URI.port; + OFNumber *port = IRI.port; if (port != nil) { OFString *host = [OFString stringWithFormat: - @"%@:%@", URI.percentEncodedHost, port]; + @"%@:%@", IRI.percentEncodedHost, port]; [headers setObject: host forKey: @"Host"]; } else - [headers setObject: URI.percentEncodedHost + [headers setObject: IRI.percentEncodedHost forKey: @"Host"]; } if ((user.length > 0 || password.length > 0) && [headers objectForKey: @"Authorization"] == nil) { @@ -297,11 +297,11 @@ exception: exception]; } - (void)createResponseWithStreamOrThrow: (OFStream *)stream { - OFURI *URI = _request.URI; + OFIRI *IRI = _request.IRI; OFHTTPClientResponse *response; OFString *connectionHeader; bool keepAlive; OFString *location; id exception; @@ -328,44 +328,44 @@ if (keepAlive) { response.of_keepAlive = true; _client->_stream = [stream retain]; - _client->_lastURI = [URI copy]; + _client->_lastIRI = [IRI copy]; _client->_lastWasHEAD = (_request.method == OFHTTPRequestMethodHead); _client->_lastResponse = [response retain]; } if (_redirects > 0 && (_status == 301 || _status == 302 || _status == 303 || _status == 307) && (location = [_serverHeaders objectForKey: @"Location"]) != nil) { bool follow = true; - OFURI *newURI; - OFString *newURIScheme; + OFIRI *newIRI; + OFString *newIRIScheme; - newURI = [OFURI URIWithString: location relativeToURI: URI]; - newURIScheme = newURI.scheme; + newIRI = [OFIRI IRIWithString: location relativeToIRI: IRI]; + newIRIScheme = newIRI.scheme; - if ([newURIScheme caseInsensitiveCompare: @"http"] != + if ([newIRIScheme caseInsensitiveCompare: @"http"] != OFOrderedSame && - [newURIScheme caseInsensitiveCompare: @"https"] != + [newIRIScheme caseInsensitiveCompare: @"https"] != OFOrderedSame) follow = false; if (!_client->_allowsInsecureRedirects && - [URI.scheme caseInsensitiveCompare: @"https"] == + [IRI.scheme caseInsensitiveCompare: @"https"] == OFOrderedSame && - [newURIScheme caseInsensitiveCompare: @"http"] == + [newIRIScheme caseInsensitiveCompare: @"http"] == OFOrderedSame) follow = false; if (follow && [_client->_delegate respondsToSelector: - @selector(client:shouldFollowRedirectToURI:statusCode: + @selector(client:shouldFollowRedirectToIRI:statusCode: request:response:)]) follow = [_client->_delegate client: _client - shouldFollowRedirectToURI: newURI + shouldFollowRedirectToIRI: newIRI statusCode: _status request: _request response: response]; else if (follow) follow = defaultShouldFollow(_request.method, _status); @@ -376,11 +376,11 @@ OFHTTPRequest *newRequest = [[_request copy] autorelease]; OFMutableDictionary *newHeaders = [[headers mutableCopy] autorelease]; - if (![newURI.host isEqual: URI.host]) + if (![newIRI.host isEqual: IRI.host]) [newHeaders removeObjectForKey: @"Host"]; /* * 303 means the request should be converted to a GET * request before redirection. This also means stripping @@ -402,11 +402,11 @@ removeObjectForKey: key]; newRequest.method = OFHTTPRequestMethodGet; } - newRequest.URI = newURI; + newRequest.IRI = newIRI; newRequest.headers = newHeaders; _client->_inProgress = false; [_client asyncPerformRequest: newRequest @@ -646,19 +646,19 @@ @selector(client:didCreateTCPSocket:request:)]) [_client->_delegate client: _client didCreateTCPSocket: sock request: _request]; - if ([_request.URI.scheme caseInsensitiveCompare: @"https"] == + if ([_request.IRI.scheme caseInsensitiveCompare: @"https"] == OFOrderedSame) { OFTLSStream *stream; @try { stream = [OFTLSStream streamWithStream: sock]; } @catch (OFNotImplementedException *e) { [self raiseException: [OFUnsupportedProtocolException - exceptionWithURI: _request.URI]]; + exceptionWithIRI: _request.IRI]]; return; } if ([_client->_delegate respondsToSelector: @selector(client:didCreateTLSStream:request:)]) @@ -665,11 +665,12 @@ [_client->_delegate client: _client didCreateTLSStream: stream request: _request]; stream.delegate = self; - [stream asyncPerformClientHandshakeWithHost: _request.URI.host]; + [stream asyncPerformClientHandshakeWithHost: _request.IRI + .IRIByAddingPercentEncodingForUnicodeCharacters.host]; } else { sock.delegate = self; [self performSelector: @selector(handleStream:) withObject: sock afterDelay: 0]; @@ -690,30 +691,30 @@ afterDelay: 0]; } - (void)start { - OFURI *URI = _request.URI; + OFIRI *IRI = _request.IRI; OFStream *stream; /* Can we reuse the last socket? */ if (_client->_stream != nil && !_client->_stream.atEndOfStream && - [_client->_lastURI.scheme isEqual: URI.scheme] && - [_client->_lastURI.host isEqual: URI.host] && - (_client->_lastURI.port == URI.port || - [_client->_lastURI.port isEqual: URI.port]) && + [_client->_lastIRI.scheme isEqual: IRI.scheme] && + [_client->_lastIRI.host isEqual: IRI.host] && + (_client->_lastIRI.port == IRI.port || + [_client->_lastIRI.port isEqual: IRI.port]) && (_client->_lastWasHEAD || _client->_lastResponse.atEndOfStream)) { /* * Set _stream to nil, so that in case of an error it won't be * reused. If everything is successful, we set _stream again * at the end. */ stream = [_client->_stream autorelease]; _client->_stream = nil; - [_client->_lastURI release]; - _client->_lastURI = nil; + [_client->_lastIRI release]; + _client->_lastIRI = nil; [_client->_lastResponse release]; _client->_lastResponse = nil; stream.delegate = self; @@ -726,31 +727,32 @@ } - (void)closeAndReconnect { @try { - OFURI *URI = _request.URI; + OFIRI *IRI = + _request.IRI.IRIByAddingPercentEncodingForUnicodeCharacters; OFTCPSocket *sock; uint16_t port; - OFNumber *URIPort; + OFNumber *IRIPort; [_client close]; sock = [OFTCPSocket socket]; - if ([URI.scheme caseInsensitiveCompare: @"https"] == + if ([IRI.scheme caseInsensitiveCompare: @"https"] == OFOrderedSame) port = 443; else port = 80; - URIPort = URI.port; - if (URIPort != nil) - port = URIPort.unsignedShortValue; + IRIPort = IRI.port; + if (IRIPort != nil) + port = IRIPort.unsignedShortValue; sock.delegate = self; - [sock asyncConnectToHost: URI.host port: port]; + [sock asyncConnectToHost: IRI.host port: port]; } @catch (id e) { [self raiseException: e]; } } @end @@ -1201,19 +1203,19 @@ statusCode: statusCode request: request]; } - (bool)client: (OFHTTPClient *)client - shouldFollowRedirectToURI: (OFURI *)URI + shouldFollowRedirectToIRI: (OFIRI *)IRI statusCode: (short)statusCode request: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { if ([_delegate respondsToSelector: @selector( - client:shouldFollowRedirectToURI:statusCode:request:response:)]) + client:shouldFollowRedirectToIRI:statusCode:request:response:)]) return [_delegate client: client - shouldFollowRedirectToURI: URI + shouldFollowRedirectToIRI: IRI statusCode: statusCode request: request response: response]; else return defaultShouldFollow(request.method, statusCode); @@ -1265,19 +1267,19 @@ - (void)asyncPerformRequest: (OFHTTPRequest *)request redirects: (unsigned int)redirects { void *pool = objc_autoreleasePoolPush(); - OFURI *URI = request.URI; - OFString *scheme = URI.scheme; + OFIRI *IRI = request.IRI; + OFString *scheme = IRI.scheme; if ([scheme caseInsensitiveCompare: @"http"] != OFOrderedSame && [scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; if (_inProgress) - @throw [OFAlreadyConnectedException exception]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; _inProgress = true; [[[[OFHTTPClientRequestHandler alloc] initWithClient: self @@ -1290,12 +1292,12 @@ - (void)close { [_stream release]; _stream = nil; - [_lastURI release]; - _lastURI = nil; + [_lastIRI release]; + _lastIRI = nil; [_lastResponse release]; _lastResponse = nil; } @end Index: src/OFHTTPCookie.h ================================================================== --- src/OFHTTPCookie.h +++ src/OFHTTPCookie.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,12 +19,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); @class OFDate; @class OFDictionary OF_GENERIC(KeyType, ObjectType); +@class OFIRI; @class OFMutableArray OF_GENERIC(ObjectType); -@class OFURI; /** * @class OFHTTPCookie OFHTTPCookie.h ObjFW/OFHTTPCookie.h * * @brief A class for storing and manipulating HTTP cookies. @@ -78,22 +78,22 @@ */ @property (readonly, nonatomic) OFMutableArray OF_GENERIC(OFString *) *extensions; /** - * @brief Parses the specified response header fields for the specified URI and + * @brief Parses the specified response header fields for the specified IRI and * returns an array of cookies. * * @param headerFields The response header fields to parse - * @param URI The URI for the response header fields to parse + * @param IRI The IRI for the response header fields to parse * @return An array of cookies * @throw OFInvalidFormatException The specified response header has an invalid * format */ + (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesWithResponseHeaderFields: (OFDictionary OF_GENERIC(OFString *, OFString *) *)headerFields - forURI: (OFURI *)URI; + forIRI: (OFIRI *)IRI; /** * @brief Returns the request header fields for the specified cookies. * * @param cookies The cookies to return the request header fields for Index: src/OFHTTPCookie.m ================================================================== --- src/OFHTTPCookie.m +++ src/OFHTTPCookie.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,11 @@ #import "OFHTTPCookie.h" #import "OFArray.h" #import "OFDate.h" #import "OFDictionary.h" -#import "OFURI.h" +#import "OFIRI.h" #import "OFInvalidFormatException.h" static void handleAttribute(OFHTTPCookie *cookie, OFString *name, OFString *value) @@ -60,16 +60,17 @@ @synthesize expires = _expires, secure = _secure, HTTPOnly = _HTTPOnly; @synthesize extensions = _extensions; + (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesWithResponseHeaderFields: (OFDictionary OF_GENERIC(OFString *, OFString *) *)headerFields - forURI: (OFURI *)URI + forIRI: (OFIRI *)IRI { OFMutableArray OF_GENERIC(OFHTTPCookie *) *ret = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); OFString *string = [headerFields objectForKey: @"Set-Cookie"]; - OFString *domain = URI.host; + OFString *domain = IRI.IRIByAddingPercentEncodingForUnicodeCharacters + .host; const OFUnichar *characters = string.characters; size_t length = string.length, last = 0; enum { statePreName, stateName, Index: src/OFHTTPCookieManager.h ================================================================== --- src/OFHTTPCookieManager.h +++ src/OFHTTPCookieManager.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,12 +17,12 @@ OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); @class OFHTTPCookie; +@class OFIRI; @class OFMutableArray OF_GENERIC(ObjectType); -@class OFURI; /** * @class OFHTTPCookieManager OFHTTPCookieManager.h ObjFW/OFHTTPCookieManager.h * * @brief A class for managing cookies for multiple domains. @@ -44,42 +44,42 @@ * @return A new, autoreleased OFHTTPCookieManager */ + (instancetype)manager; /** - * @brief Adds the specified cookie for the specified URI. + * @brief Adds the specified cookie for the specified IRI. * * @warning This modifies the cookie (e.g. it sets the domain if it is unset)! * If you do not want this, pass a copy! * * @param cookie The cookie to add to the manager - * @param URI The URI for which the cookie should be added + * @param IRI The IRI for which the cookie should be added */ -- (void)addCookie: (OFHTTPCookie *)cookie forURI: (OFURI *)URI; +- (void)addCookie: (OFHTTPCookie *)cookie forIRI: (OFIRI *)IRI; /** - * @brief Adds the specified cookies for the specified URI. + * @brief Adds the specified cookies for the specified IRI. * * @warning This modifies the cookies (e.g. it sets the domain if it is unset)! * If you do not want this, pass copies! * * @param cookies An array of cookies to add to the manager - * @param URI The URI for which the cookies should be added + * @param IRI The IRI for which the cookies should be added */ - (void)addCookies: (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies - forURI: (OFURI *)URI; + forIRI: (OFIRI *)IRI; /** - * @brief Returns the cookies for the specified URI. + * @brief Returns the cookies for the specified IRI. * - * @param URI The URI for which the cookies should be returned - * @return The cookies for the specified URI + * @param IRI The IRI for which the cookies should be returned + * @return The cookies for the specified IRI */ -- (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesForURI: (OFURI *)URI; +- (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesForIRI: (OFIRI *)IRI; /** * @brief Purges all expired cookies. */ - (void)purgeExpiredCookies; @end OF_ASSUME_NONNULL_END Index: src/OFHTTPCookieManager.m ================================================================== --- src/OFHTTPCookieManager.m +++ src/OFHTTPCookieManager.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,11 @@ #import "OFHTTPCookieManager.h" #import "OFArray.h" #import "OFDate.h" #import "OFHTTPCookie.h" -#import "OFURI.h" +#import "OFIRI.h" @implementation OFHTTPCookieManager + (instancetype)manager { return [[[self alloc] init] autorelease]; @@ -51,33 +51,35 @@ - (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies { return [[_cookies copy] autorelease]; } -- (void)addCookie: (OFHTTPCookie *)cookie forURI: (OFURI *)URI +- (void)addCookie: (OFHTTPCookie *)cookie forIRI: (OFIRI *)IRI { void *pool = objc_autoreleasePoolPush(); - OFString *cookieDomain, *URIHost; + OFString *cookieDomain, *IRIHost; size_t i; + + IRI = IRI.IRIByAddingPercentEncodingForUnicodeCharacters; if (![cookie.path hasPrefix: @"/"]) cookie.path = @"/"; if (cookie.secure && - [URI.scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) { + [IRI.scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) { objc_autoreleasePoolPop(pool); return; } cookieDomain = cookie.domain.lowercaseString; cookie.domain = cookieDomain; - URIHost = URI.host.lowercaseString; - if (![cookieDomain isEqual: URIHost]) { - URIHost = [@"." stringByAppendingString: URIHost]; + IRIHost = IRI.host.lowercaseString; + if (![cookieDomain isEqual: IRIHost]) { + IRIHost = [@"." stringByAppendingString: IRIHost]; - if (![cookieDomain hasSuffix: URIHost]) { + if (![cookieDomain hasSuffix: IRIHost]) { objc_autoreleasePoolPop(pool); return; } } @@ -98,78 +100,83 @@ objc_autoreleasePoolPop(pool); } - (void)addCookies: (OFArray OF_GENERIC(OFHTTPCookie *) *)cookies - forURI: (OFURI *)URI + forIRI: (OFIRI *)IRI { for (OFHTTPCookie *cookie in cookies) - [self addCookie: cookie forURI: URI]; + [self addCookie: cookie forIRI: IRI]; } -- (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesForURI: (OFURI *)URI +- (OFArray OF_GENERIC(OFHTTPCookie *) *)cookiesForIRI: (OFIRI *)IRI { OFMutableArray *ret = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + + IRI = IRI.IRIByAddingPercentEncodingForUnicodeCharacters; for (OFHTTPCookie *cookie in _cookies) { - void *pool; + void *pool2; OFDate *expires; - OFString *cookieDomain, *URIHost, *cookiePath, *URIPath; + OFString *cookieDomain, *IRIHost, *cookiePath, *IRIPath; bool match; expires = cookie.expires; if (expires != nil && expires.timeIntervalSinceNow <= 0) continue; - if (cookie.secure && [URI.scheme caseInsensitiveCompare: + if (cookie.secure && [IRI.scheme caseInsensitiveCompare: @"https"] != OFOrderedSame) continue; - pool = objc_autoreleasePoolPush(); + pool2 = objc_autoreleasePoolPush(); cookieDomain = cookie.domain.lowercaseString; - URIHost = URI.host.lowercaseString; + IRIHost = IRI.host.lowercaseString; if ([cookieDomain hasPrefix: @"."]) { - if ([URIHost hasSuffix: cookieDomain]) + if ([IRIHost hasSuffix: cookieDomain]) match = true; else { cookieDomain = [cookieDomain substringFromIndex: 1]; - match = [cookieDomain isEqual: URIHost]; + match = [cookieDomain isEqual: IRIHost]; } } else - match = [cookieDomain isEqual: URIHost]; + match = [cookieDomain isEqual: IRIHost]; if (!match) { - objc_autoreleasePoolPop(pool); + objc_autoreleasePoolPop(pool2); continue; } cookiePath = cookie.path; - URIPath = URI.path; + IRIPath = IRI.path; if (![cookiePath isEqual: @"/"]) { - if ([cookiePath isEqual: URIPath]) + if ([cookiePath isEqual: IRIPath]) match = true; else { if (![cookiePath hasSuffix: @"/"]) cookiePath = [cookiePath stringByAppendingString: @"/"]; - match = [URIPath hasPrefix: cookiePath]; + match = [IRIPath hasPrefix: cookiePath]; } if (!match) { - objc_autoreleasePoolPop(pool); + objc_autoreleasePoolPop(pool2); continue; } } [ret addObject: cookie]; } [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); return ret; } - (void)purgeExpiredCookies ADDED src/OFHTTPIRIHandler.h Index: src/OFHTTPIRIHandler.h ================================================================== --- src/OFHTTPIRIHandler.h +++ src/OFHTTPIRIHandler.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRIHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFHTTPIRIHandler: OFIRIHandler +@end + +OF_ASSUME_NONNULL_END ADDED src/OFHTTPIRIHandler.m Index: src/OFHTTPIRIHandler.m ================================================================== --- src/OFHTTPIRIHandler.m +++ src/OFHTTPIRIHandler.m @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFHTTPIRIHandler.h" +#import "OFHTTPClient.h" +#import "OFHTTPRequest.h" +#import "OFHTTPResponse.h" + +@implementation OFHTTPIRIHandler +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + void *pool = objc_autoreleasePoolPush(); + OFHTTPClient *client = [OFHTTPClient client]; + OFHTTPRequest *request = [OFHTTPRequest requestWithIRI: IRI]; + OFHTTPResponse *response = [client performRequest: request]; + + [response retain]; + + objc_autoreleasePoolPop(pool); + + return [response autorelease]; +} +@end Index: src/OFHTTPRequest.h ================================================================== --- src/OFHTTPRequest.h +++ src/OFHTTPRequest.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,13 +17,13 @@ #import "OFSocket.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFData; @class OFDictionary OF_GENERIC(KeyType, ObjectType); -@class OFData; +@class OFIRI; @class OFString; /** @file */ /** @@ -66,22 +66,22 @@ * @brief A class for storing HTTP requests. */ OF_SUBCLASSING_RESTRICTED @interface OFHTTPRequest: OFObject { - OFURI *_URI; + OFIRI *_IRI; OFHTTPRequestMethod _method; OFHTTPRequestProtocolVersion _protocolVersion; OFDictionary OF_GENERIC(OFString *, OFString *) *_Nullable _headers; OFSocketAddress _remoteAddress; bool _hasRemoteAddress; } /** - * @brief The URI of the HTTP request. + * @brief The IRI of the HTTP request. */ -@property (copy, nonatomic) OFURI *URI; +@property (copy, nonatomic) OFIRI *IRI; /** * @brief The protocol version of the HTTP request. * * @throw OFUnsupportedVersionException The specified version cannot be set @@ -116,24 +116,24 @@ * @note The setter creates a copy of the remote address. */ @property OF_NULLABLE_PROPERTY (nonatomic) const OFSocketAddress *remoteAddress; /** - * @brief Creates a new OFHTTPRequest with the specified URI. + * @brief Creates a new OFHTTPRequest with the specified IRI. * - * @param URI The URI for the request + * @param IRI The IRI for the request * @return A new, autoreleased OFHTTPRequest */ -+ (instancetype)requestWithURI: (OFURI *)URI; ++ (instancetype)requestWithIRI: (OFIRI *)IRI; /** - * @brief Initializes an already allocated OFHTTPRequest with the specified URI. + * @brief Initializes an already allocated OFHTTPRequest with the specified IRI. * - * @param URI The URI for the request + * @param IRI The IRI for the request * @return An initialized OFHTTPRequest */ -- (instancetype)initWithURI: (OFURI *)URI; +- (instancetype)initWithIRI: (OFIRI *)IRI; - (instancetype)init OF_UNAVAILABLE; @end #ifdef __cplusplus Index: src/OFHTTPRequest.m ================================================================== --- src/OFHTTPRequest.m +++ src/OFHTTPRequest.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,15 +16,15 @@ #include "config.h" #include #import "OFHTTPRequest.h" -#import "OFString.h" -#import "OFURI.h" +#import "OFArray.h" +#import "OFData.h" #import "OFDictionary.h" -#import "OFData.h" -#import "OFArray.h" +#import "OFIRI.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #import "OFUnsupportedVersionException.h" @@ -76,23 +76,23 @@ @throw [OFInvalidFormatException exception]; } @implementation OFHTTPRequest -@synthesize URI = _URI, method = _method, headers = _headers; +@synthesize IRI = _IRI, method = _method, headers = _headers; -+ (instancetype)requestWithURI: (OFURI *)URI ++ (instancetype)requestWithIRI: (OFIRI *)IRI { - return [[[self alloc] initWithURI: URI] autorelease]; + return [[[self alloc] initWithIRI: IRI] autorelease]; } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _method = OFHTTPRequestMethodGet; _protocolVersion.major = 1; _protocolVersion.minor = 1; } @catch (id e) { [self release]; @@ -107,11 +107,11 @@ OF_INVALID_INIT_METHOD } - (void)dealloc { - [_URI release]; + [_IRI release]; [_headers release]; [super dealloc]; } @@ -131,11 +131,11 @@ return NULL; } - (id)copy { - OFHTTPRequest *copy = [[OFHTTPRequest alloc] initWithURI: _URI]; + OFHTTPRequest *copy = [[OFHTTPRequest alloc] initWithIRI: _IRI]; @try { copy->_method = _method; copy->_protocolVersion = _protocolVersion; copy.headers = _headers; @@ -161,11 +161,11 @@ request = object; if (request->_method != _method || request->_protocolVersion.major != _protocolVersion.major || request->_protocolVersion.minor != _protocolVersion.minor || - ![request->_URI isEqual: _URI] || + ![request->_IRI isEqual: _IRI] || ![request->_headers isEqual: _headers]) return false; if (request.remoteAddress != self.remoteAddress && !OFSocketAddressEqual(request.remoteAddress, self.remoteAddress)) @@ -181,11 +181,11 @@ OFHashInit(&hash); OFHashAddByte(&hash, _method); OFHashAddByte(&hash, _protocolVersion.major); OFHashAddByte(&hash, _protocolVersion.minor); - OFHashAddHash(&hash, _URI.hash); + OFHashAddHash(&hash, _IRI.hash); OFHashAddHash(&hash, _headers.hash); if (_hasRemoteAddress) OFHashAddHash(&hash, OFSocketAddressHash(&_remoteAddress)); OFHashFinalize(&hash); @@ -254,17 +254,17 @@ remoteAddress = OFSocketAddressString(&_remoteAddress); else remoteAddress = nil; ret = [[OFString alloc] initWithFormat: - @"<%@:\n\tURI = %@\n" + @"<%@:\n\tIRI = %@\n" @"\tMethod = %s\n" @"\tHeaders = %@\n" @"\tRemote address = %@\n" @">", - self.class, _URI, method, indentedHeaders, remoteAddress]; + self.class, _IRI, method, indentedHeaders, remoteAddress]; objc_autoreleasePoolPop(pool); return [ret autorelease]; } @end Index: src/OFHTTPResponse.h ================================================================== --- src/OFHTTPResponse.h +++ src/OFHTTPResponse.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHTTPResponse.m ================================================================== --- src/OFHTTPResponse.m +++ src/OFHTTPResponse.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHTTPServer.h ================================================================== --- src/OFHTTPServer.h +++ src/OFHTTPServer.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -104,20 +104,20 @@ } /** * @brief The host on which the HTTP server will listen. * - * @throw OFAlreadyConnectedException The host could not be set because - * @ref start had already been called + * @throw OFAlreadyOpenException The host could not be set because @ref start + * had already been called */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *host; /** * @brief The port on which the HTTP server will listen. * - * @throw OFAlreadyConnectedException The port could not be set because - * @ref start had already been called + * @throw OFAlreadyOpenException The port could not be set because @ref start + * had already been called */ @property (nonatomic) uint16_t port; /** * @brief The delegate for the HTTP server. @@ -132,12 +132,12 @@ * If this is larger than 1 (the default), one thread will be used to accept * incoming connections and all others will be used to handle connections. * * For maximum CPU utilization, set this to `[OFSystemInfo numberOfCPUs] + 1`. * - * @throw OFAlreadyConnectedException The number of threads could not be set - * because @ref start had already been called + * @throw OFAlreadyOpenException The number of threads could not be set because + * @ref start had already been called */ @property (nonatomic) size_t numberOfThreads; #endif /** @@ -156,11 +156,11 @@ + (instancetype)server; /** * @brief Starts the HTTP server in the current thread's run loop. * - * @throw OFAlreadyConnectedException The server had already been started + * @throw OFAlreadyOpenException The server had already been started */ - (void)start; /** * @brief Stops the HTTP server, meaning it will not accept any new incoming Index: src/OFHTTPServer.m ================================================================== --- src/OFHTTPServer.m +++ src/OFHTTPServer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -26,18 +26,18 @@ #import "OFData.h" #import "OFDate.h" #import "OFDictionary.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" +#import "OFIRI.h" #import "OFNumber.h" #import "OFSocket+Private.h" #import "OFTCPSocket.h" #import "OFThread.h" #import "OFTimer.h" -#import "OFURI.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" #import "OFOutOfMemoryException.h" @@ -512,11 +512,11 @@ } - (void)createResponse { void *pool = objc_autoreleasePoolPush(); - OFMutableURI *URI; + OFMutableIRI *IRI; OFHTTPRequest *request; OFHTTPServerResponse *response; size_t pos; [_timer invalidate]; @@ -532,36 +532,36 @@ [_host release]; _host = [_server.host copy]; _port = [_server port]; } - URI = [OFMutableURI URIWithScheme: @"http"]; - URI.host = _host; + IRI = [OFMutableIRI IRIWithScheme: @"http"]; + IRI.host = _host; if (_port != 80) - URI.port = [OFNumber numberWithUnsignedShort: _port]; + IRI.port = [OFNumber numberWithUnsignedShort: _port]; @try { if ((pos = [_path rangeOfString: @"?"].location) != OFNotFound) { OFString *path, *query; path = [_path substringToIndex: pos]; query = [_path substringFromIndex: pos + 1]; - URI.percentEncodedPath = path; - URI.percentEncodedQuery = query; + IRI.percentEncodedPath = path; + IRI.percentEncodedQuery = query; } else - URI.percentEncodedPath = _path; + IRI.percentEncodedPath = _path; } @catch (OFInvalidFormatException *e) { objc_autoreleasePoolPop(pool); [self sendErrorAndClose: 400]; return; } - [URI makeImmutable]; + [IRI makeImmutable]; - request = [OFHTTPRequest requestWithURI: URI]; + request = [OFHTTPRequest requestWithIRI: IRI]; request.method = _method; request.protocolVersion = (OFHTTPRequestProtocolVersion){ 1, _HTTPMinorVersion }; request.headers = _headers; request.remoteAddress = _socket.remoteAddress; @@ -802,11 +802,11 @@ - (void)setHost: (OFString *)host { OFString *old; if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; old = _host; _host = [host copy]; [old release]; } @@ -817,11 +817,11 @@ } - (void)setPort: (uint16_t)port { if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; _port = port; } - (uint16_t)port @@ -834,11 +834,11 @@ { if (numberOfThreads == 0) @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; _numberOfThreads = numberOfThreads; } - (size_t)numberOfThreads @@ -848,19 +848,21 @@ #endif - (void)start { void *pool = objc_autoreleasePoolPush(); + OFSocketAddress address; if (_host == nil) @throw [OFInvalidArgumentException exception]; if (_listeningSocket != nil) - @throw [OFAlreadyConnectedException exception]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; _listeningSocket = [[OFTCPSocket alloc] init]; - _port = [_listeningSocket bindToHost: _host port: _port]; + address = [_listeningSocket bindToHost: _host port: _port]; + _port = OFSocketAddressIPPort(&address); [_listeningSocket listen]; #ifdef OF_HAVE_THREADS if (_numberOfThreads > 1) { OFMutableArray *threads = DELETED src/OFHTTPURIHandler.h Index: src/OFHTTPURIHandler.h ================================================================== --- src/OFHTTPURIHandler.h +++ src/OFHTTPURIHandler.h @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURIHandler.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFHTTPURIHandler: OFURIHandler -@end - -OF_ASSUME_NONNULL_END DELETED src/OFHTTPURIHandler.m Index: src/OFHTTPURIHandler.m ================================================================== --- src/OFHTTPURIHandler.m +++ src/OFHTTPURIHandler.m @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFHTTPURIHandler.h" -#import "OFHTTPClient.h" -#import "OFHTTPRequest.h" -#import "OFHTTPResponse.h" - -@implementation OFHTTPURIHandler -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - void *pool = objc_autoreleasePoolPush(); - OFHTTPClient *client = [OFHTTPClient client]; - OFHTTPRequest *request = [OFHTTPRequest requestWithURI: URI]; - OFHTTPResponse *response = [client performRequest: request]; - - [response retain]; - - objc_autoreleasePoolPop(pool); - - return [response autorelease]; -} -@end Index: src/OFHostAddressResolver.h ================================================================== --- src/OFHostAddressResolver.h +++ src/OFHostAddressResolver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHostAddressResolver.m ================================================================== --- src/OFHostAddressResolver.m +++ src/OFHostAddressResolver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -151,12 +151,15 @@ - (void)sendQueries { OFString *domainName; if (!_isFQDN) { - OFString *searchDomain = [_settings->_searchDomains - objectAtIndex: _searchDomainIndex]; + OFString *searchDomain = @""; + + if (_searchDomainIndex < _settings->_searchDomains.count) + searchDomain = [_settings->_searchDomains + objectAtIndex: _searchDomainIndex]; domainName = [OFString stringWithFormat: @"%@.%@", _host, searchDomain]; } else domainName = _host; @@ -286,11 +289,12 @@ objc_autoreleasePoolPop(pool); return; } @catch (OFInvalidFormatException *e) { } - if ((aliases = [_settings->_staticHosts objectForKey: _host]) != nil) { + if ((aliases = [_settings->_staticHosts objectForKey: + _host.lowercaseString]) != nil) { OFMutableData *addresses = [OFMutableData dataWithItemSize: sizeof(OFSocketAddress)]; id exception = nil; for (OFString *alias in aliases) { Index: src/OFHuffmanTree.h ================================================================== --- src/OFHuffmanTree.h +++ src/OFHuffmanTree.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFHuffmanTree.m ================================================================== --- src/OFHuffmanTree.m +++ src/OFHuffmanTree.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFINICategory+Private.h ================================================================== --- src/OFINICategory+Private.h +++ src/OFINICategory+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFINICategory.h ================================================================== --- src/OFINICategory.h +++ src/OFINICategory.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFINICategory.m ================================================================== --- src/OFINICategory.m +++ src/OFINICategory.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFINIFile.h ================================================================== --- src/OFINIFile.h +++ src/OFINIFile.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,12 +17,12 @@ #import "OFString.h" #import "OFINICategory.h" OF_ASSUME_NONNULL_BEGIN +@class OFIRI; @class OFMutableArray OF_GENERIC(ObjectType); -@class OFURI; /** * @class OFINIFile OFINIFile.h ObjFW/OFINIFile.h * * @brief A class for reading, creating and modifying INI files. @@ -39,63 +39,63 @@ @property (readonly, nonatomic) OFArray OF_GENERIC(OFINICategory *) *categories; /** * @brief Creates a new OFINIFile with the contents of the specified file. * - * @param URI The URI to the file whose contents the OFINIFile should contain + * @param IRI The IRI to the file whose contents the OFINIFile should contain * * @return A new, autoreleased OFINIFile with the contents of the specified file * @throw OFInvalidFormatException The format of the specified INI file is * invalid * @throw OFInvalidEncodingException The INI file is not in the specified * encoding */ -+ (instancetype)fileWithURI: (OFURI *)URI; ++ (instancetype)fileWithIRI: (OFIRI *)IRI; /** * @brief Creates a new OFINIFile with the contents of the specified file in * the specified encoding. * - * @param URI The URI to the file whose contents the OFINIFile should contain + * @param IRI The IRI to the file whose contents the OFINIFile should contain * @param encoding The encoding of the specified file * @return A new, autoreleased OFINIFile with the contents of the specified file * @throw OFInvalidFormatException The format of the specified INI file is * invalid * @throw OFInvalidEncodingException The INI file is not in the specified * encoding */ -+ (instancetype)fileWithURI: (OFURI *)URI encoding: (OFStringEncoding)encoding; ++ (instancetype)fileWithIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFINIFile with the contents of the * specified file. * - * @param URI The URI to the file whose contents the OFINIFile should contain + * @param IRI The IRI to the file whose contents the OFINIFile should contain * * @return An initialized OFINIFile with the contents of the specified file * @throw OFInvalidFormatException The format of the specified INI file is * invalid * @throw OFInvalidEncodingException The INI file is not in the specified * encoding */ -- (instancetype)initWithURI: (OFURI *)URI; +- (instancetype)initWithIRI: (OFIRI *)IRI; /** * @brief Initializes an already allocated OFINIFile with the contents of the * specified file in the specified encoding. * - * @param URI The URI to the file whose contents the OFINIFile should contain + * @param IRI The IRI to the file whose contents the OFINIFile should contain * @param encoding The encoding of the specified file * @return An initialized OFINIFile with the contents of the specified file * @throw OFInvalidFormatException The format of the specified INI file is * invalid * @throw OFInvalidEncodingException The INI file is not in the specified * encoding */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding OF_DESIGNATED_INITIALIZER; /** * @brief Returns an @ref OFINICategory for the category with the specified @@ -109,20 +109,20 @@ - (OFINICategory *)categoryForName: (OFString *)name; /** * @brief Writes the contents of the OFINIFile to a file. * - * @param URI The URI of the file to write to + * @param IRI The IRI of the file to write to */ -- (void)writeToURI: (OFURI *)URI; +- (void)writeToIRI: (OFIRI *)IRI; /** * @brief Writes the contents of the OFINIFile to a file in the specified * encoding. * - * @param URI The URI of the file to write to + * @param IRI The IRI of the file to write to * @param encoding The encoding to use */ -- (void)writeToURI: (OFURI *)URI encoding: (OFStringEncoding)encoding; +- (void)writeToIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; @end OF_ASSUME_NONNULL_END Index: src/OFINIFile.m ================================================================== --- src/OFINIFile.m +++ src/OFINIFile.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,21 +19,21 @@ #import "OFINIFile.h" #import "OFArray.h" #import "OFINICategory+Private.h" #import "OFINICategory.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFStream.h" #import "OFString.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" OF_DIRECT_MEMBERS @interface OFINIFile () -- (void)of_parseURI: (OFURI *)URI encoding: (OFStringEncoding)encoding; +- (void)of_parseIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; @end static bool isWhitespaceLine(OFString *line) { @@ -48,38 +48,38 @@ } @implementation OFINIFile @synthesize categories = _categories; -+ (instancetype)fileWithURI: (OFURI *)URI ++ (instancetype)fileWithIRI: (OFIRI *)IRI { - return [[[self alloc] initWithURI: URI] autorelease]; + return [[[self alloc] initWithIRI: IRI] autorelease]; } -+ (instancetype)fileWithURI: (OFURI *)URI encoding: (OFStringEncoding)encoding ++ (instancetype)fileWithIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { - return [[[self alloc] initWithURI: URI encoding: encoding] autorelease]; + return [[[self alloc] initWithIRI: IRI encoding: encoding] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI { - return [self initWithURI: URI encoding: OFStringEncodingAutodetect]; + return [self initWithIRI: IRI encoding: OFStringEncodingAutodetect]; } -- (instancetype)initWithURI: (OFURI *)URI encoding: (OFStringEncoding)encoding +- (instancetype)initWithIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { self = [super init]; @try { _categories = [[OFMutableArray alloc] init]; - [self of_parseURI: URI encoding: encoding]; + [self of_parseIRI: IRI encoding: encoding]; } @catch (id e) { [self release]; @throw e; } @@ -108,11 +108,11 @@ objc_autoreleasePoolPop(pool); return category; } -- (void)of_parseURI: (OFURI *)URI encoding: (OFStringEncoding)encoding +- (void)of_parseIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFStream *file; OFINICategory *category = nil; OFString *line; @@ -119,11 +119,11 @@ if (encoding == OFStringEncodingAutodetect) encoding = OFStringEncodingUTF8; @try { - file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; } @catch (OFOpenItemFailedException *e) { /* Handle missing file like an empty file */ if (e.errNo == ENOENT) return; @@ -154,19 +154,19 @@ } objc_autoreleasePoolPop(pool); } -- (void)writeToURI: (OFURI *)URI +- (void)writeToIRI: (OFIRI *)IRI { - [self writeToURI: URI encoding: OFStringEncodingUTF8]; + [self writeToIRI: IRI encoding: OFStringEncodingUTF8]; } -- (void)writeToURI: (OFURI *)URI encoding: (OFStringEncoding)encoding +- (void)writeToIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"w"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"w"]; bool first = true; for (OFINICategory *category in _categories) if ([category of_writeToStream: file encoding: encoding Index: src/OFINIFileSettings.h ================================================================== --- src/OFINIFileSettings.h +++ src/OFINIFileSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,16 +16,16 @@ #import "OFSettings.h" OF_ASSUME_NONNULL_BEGIN @class OFINIFile; +@class OFIRI; @class OFString; -@class OFURI; @interface OFINIFileSettings: OFSettings { - OFURI *_fileURI; + OFIRI *_fileIRI; OFINIFile *_INIFile; } @end OF_ASSUME_NONNULL_END Index: src/OFINIFileSettings.m ================================================================== --- src/OFINIFileSettings.m +++ src/OFINIFileSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,13 +16,13 @@ #include "config.h" #import "OFINIFileSettings.h" #import "OFArray.h" #import "OFINIFile.h" +#import "OFIRI.h" #import "OFString.h" #import "OFSystemInfo.h" -#import "OFURI.h" @implementation OFINIFileSettings - (instancetype)initWithApplicationName: (OFString *)applicationName { self = [super initWithApplicationName: applicationName]; @@ -30,13 +30,13 @@ @try { void *pool = objc_autoreleasePoolPush(); OFString *fileName; fileName = [applicationName stringByAppendingString: @".ini"]; - _fileURI = [[[OFSystemInfo userConfigURI] - URIByAppendingPathComponent: fileName] copy]; - _INIFile = [[OFINIFile alloc] initWithURI: _fileURI]; + _fileIRI = [[[OFSystemInfo userConfigIRI] + IRIByAppendingPathComponent: fileName] copy]; + _INIFile = [[OFINIFile alloc] initWithIRI: _fileIRI]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -45,11 +45,11 @@ return self; } - (void)dealloc { - [_fileURI release]; + [_fileIRI release]; [_INIFile release]; [super dealloc]; } @@ -241,8 +241,8 @@ objc_autoreleasePoolPop(pool); } - (void)save { - [_INIFile writeToURI: _fileURI]; + [_INIFile writeToIRI: _fileIRI]; } @end Index: src/OFIPXSocket.h ================================================================== --- src/OFIPXSocket.h +++ src/OFIPXSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -33,11 +33,11 @@ * @brief A class which provides methods to create and use IPX sockets. * * Addresses are of type @ref OFSocketAddress. You can use * @ref OFSocketAddressMakeIPX to create an address or * @ref OFSocketAddressIPXNetwork to get the IPX network, - * @ref OFSocketAddressIPXNode to get the IPX node and + * @ref OFSocketAddressGetIPXNode to get the IPX node and * @ref OFSocketAddressIPXPort to get the port (sometimes also called * socket number). * * @warning Even though the OFCopying protocol is implemented, it does *not* * return an independent copy of the socket, but instead retains it. @@ -73,15 +73,15 @@ * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return via the returned socket address. * @param packetType The packet type to use on the socket * @return The address on which this socket can be reached * @throw OFBindIPXSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @throw OFAlreadyOpenException The socket is already bound */ - (OFSocketAddress) bindToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port packetType: (uint8_t)packetType; @end OF_ASSUME_NONNULL_END Index: src/OFIPXSocket.m ================================================================== --- src/OFIPXSocket.m +++ src/OFIPXSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,12 +23,16 @@ #import "OFIPXSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindIPXSocketFailedException.h" + +#ifndef NSPROTO_IPX +# define NSPROTO_IPX 0 +#endif @implementation OFIPXSocket @dynamic delegate; - (OFSocketAddress)bindToNetwork: (uint32_t)network @@ -41,15 +45,15 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeIPX(network, node, port); -#ifdef OF_WINDOWS +#if defined(OF_WINDOWS) || defined(OF_FREEBSD) protocol = NSPROTO_IPX + packetType; #else _packetType = address.sockaddr.ipx.sipx_type = packetType; #endif @@ -120,11 +124,11 @@ } return address; } -#ifndef OF_WINDOWS +#if !defined(OF_WINDOWS) && !defined(OF_FREEBSD) - (void)sendBuffer: (const void *)buffer length: (size_t)length receiver: (const OFSocketAddress *)receiver { OFSocketAddress fixedReceiver; ADDED src/OFIRI+Private.h Index: src/OFIRI+Private.h ================================================================== --- src/OFIRI+Private.h +++ src/OFIRI+Private.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRI.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFIRI () +- (instancetype)of_init OF_METHOD_FAMILY(init); +@end + +OF_ASSUME_NONNULL_END ADDED src/OFIRI.h Index: src/OFIRI.h ================================================================== --- src/OFIRI.h +++ src/OFIRI.h @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" +#import "OFCharacterSet.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFDictionary OF_GENERIC(KeyType, ObjectType); +@class OFNumber; +@class OFPair OF_GENERIC(FirstType, SecondType); +@class OFString; + +/** + * @class OFIRI OFIRI.h ObjFW/OFIRI.h + * + * @brief A class for representing IRIs, URIs, URLs and URNs, for parsing them + * as well as accessing parts of them. + * + * This class follows RFC 3976 and RFC 3987. + */ +@interface OFIRI: OFObject +{ + OFString *_scheme; + OFString *_Nullable _percentEncodedHost; + OFNumber *_Nullable _port; + OFString *_Nullable _percentEncodedUser; + OFString *_Nullable _percentEncodedPassword; + OFString *_percentEncodedPath; + OFString *_Nullable _percentEncodedQuery; + OFString *_Nullable _percentEncodedFragment; + OF_RESERVE_IVARS(OFIRI, 4) +} + +/** + * @brief The scheme part of the IRI. + */ +@property (readonly, copy, nonatomic) OFString *scheme; + +/** + * @brief The host part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *host; + +/** + * @brief The host part of the IRI in percent-encoded form. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *percentEncodedHost; + +/** + * @brief The port part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFNumber *port; + +/** + * @brief The user part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *user; + +/** + * @brief The user part of the IRI in percent-encoded form. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *percentEncodedUser; + +/** + * @brief The password part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *password; + +/** + * @brief The password part of the IRI in percent-encoded form. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *percentEncodedPassword; + +/** + * @brief The path part of the IRI. + */ +@property (readonly, copy, nonatomic) OFString *path; + +/** + * @brief The path part of the IRI in percent-encoded form. + */ +@property (readonly, copy, nonatomic) OFString *percentEncodedPath; + +/** + * @brief The path of the IRI split into components. + * + * The first component must always be `/` to designate the root. + */ +@property (readonly, copy, nonatomic) + OFArray OF_GENERIC(OFString *) *pathComponents; + +/** + * @brief The last path component of the IRI. + * + * Returns the empty string if the path is the root. + */ +@property (readonly, copy, nonatomic) OFString *lastPathComponent; + +/** + * @brief The query part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *query; + +/** + * @brief The query part of the IRI in percent-encoded form. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *percentEncodedQuery; + +/** + * @brief The query part of the IRI as an array. + * + * For example, a query like `key1=value1&key2=value2` would correspond to the + * following array: + * + * @[ + * [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"], + * [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"], + * ] + * + * @throw OFInvalidFormatException The query is not in the correct format + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems; + +/** + * @brief The fragment part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *fragment; + +/** + * @brief The fragment part of the IRI in percent-encoded form. + */ +@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) + OFString *percentEncodedFragment; + +/** + * @brief The IRI as a string. + */ +@property (readonly, nonatomic) OFString *string; + +/** + * @brief The IRI with relative subpaths resolved. + */ +@property (readonly, nonatomic) OFIRI *IRIByStandardizingPath; + +/** + * @brief The IRI with percent-encoding added for all Unicode characters. + */ +@property (readonly, nonatomic) + OFIRI *IRIByAddingPercentEncodingForUnicodeCharacters; + +#ifdef OF_HAVE_FILES +/** + * @brief The local file system representation for a file IRI. + * + * @note This only exists for IRIs with the file scheme and throws an exception + * otherwise. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) + OFString *fileSystemRepresentation; +#endif + +/** + * @brief Creates a new IRI with the specified string. + * + * @param string A string describing an IRI + * @return A new, autoreleased OFIRI + * @throw OFInvalidFormatException The specified string is not a valid IRI + * string + */ ++ (instancetype)IRIWithString: (OFString *)string; + +/** + * @brief Creates a new IRI with the specified string relative to the + * specified IRI. + * + * @param string A string describing a relative or absolute IRI + * @param IRI An IRI to which the string is relative + * @return A new, autoreleased OFIRI + * @throw OFInvalidFormatException The specified string is not a valid IRI + * string + */ ++ (instancetype)IRIWithString: (OFString *)string relativeToIRI: (OFIRI *)IRI; + +#ifdef OF_HAVE_FILES +/** + * @brief Creates a new IRI with the specified local file path. + * + * If a directory exists at the specified path, a slash is appended if there is + * no slash yet. + * + * @param path The local file path + * @return A new, autoreleased OFIRI + * @throw OFInvalidFormatException The specified path is not a valid path + */ ++ (instancetype)fileIRIWithPath: (OFString *)path; + +/** + * @brief Creates a new IRI with the specified local file path. + * + * @param path The local file path + * @param isDirectory Whether the path is a directory, in which case a slash is + * appened if there is no slash yet + * @return An initialized OFIRI + */ ++ (instancetype)fileIRIWithPath: (OFString *)path + isDirectory: (bool)isDirectory; +#endif + +/** + * @brief Initializes an already allocated OFIRI with the specified string. + * + * @param string A string describing an IRI + * @return An initialized OFIRI + * @throw OFInvalidFormatException The specified string is not a valid IRI + * string + */ +- (instancetype)initWithString: (OFString *)string; + +/** + * @brief Initializes an already allocated OFIRI with the specified string and + * relative IRI. + * + * @param string A string describing a relative or absolute IRI + * @param IRI An IRI to which the string is relative + * @return An initialized OFIRI + * @throw OFInvalidFormatException The specified string is not a valid IRI + * string + */ +- (instancetype)initWithString: (OFString *)string relativeToIRI: (OFIRI *)IRI; + +#ifdef OF_HAVE_FILES +/** + * @brief Initializes an already allocated OFIRI with the specified local file + * path. + * + * If a directory exists at the specified path, a slash is appended if there is + * no slash yet. + * + * @param path The local file path + * @return An initialized OFIRI + * @throw OFInvalidFormatException The specified path is not a valid path + */ +- (instancetype)initFileIRIWithPath: (OFString *)path; + +/** + * @brief Initializes an already allocated OFIRI with the specified local file + * path. + * + * @param path The local file path + * @param isDirectory Whether the path is a directory, in which case a slash is + * appened if there is no slash yet + * @return An initialized OFIRI + */ +- (instancetype)initFileIRIWithPath: (OFString *)path + isDirectory: (bool)isDirectory; +#endif + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Returns a new IRI with the specified path component appended. + * + * If the IRI is a file IRI, the file system is queried whether the appended + * component is a directory. + * + * @param component The path component to append. If it starts with the slash, + * the component is not appended, but replaces the path + * instead. + * @return A new IRI with the specified path component appended + */ +- (OFIRI *)IRIByAppendingPathComponent: (OFString *)component; + +/** + * @brief Returns a new IRI with the specified path component appended. + * + * @param component The path component to append. If it starts with the slash, + * the component is not appended, but replaces the path + * instead. + * @param isDirectory Whether the appended component is a directory, meaning + * that the IRI path should have a trailing slash + * @return A new IRI with the specified path component appended + */ +- (OFIRI *)IRIByAppendingPathComponent: (OFString *)component + isDirectory: (bool)isDirectory; +@end + +@interface OFCharacterSet (IRICharacterSets) +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nonatomic) + OFCharacterSet *IRISchemeAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIHostAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIUserAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIPasswordAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIPathAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIQueryAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIQueryKeyValueAllowedCharacterSet; +@property (class, readonly, nonatomic) + OFCharacterSet *IRIFragmentAllowedCharacterSet; +#endif + +/** + * @brief Returns the characters allowed in the scheme part of an IRI. + * + * @return The characters allowed in the scheme part of an IRI. + */ ++ (OFCharacterSet *)IRISchemeAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the host part of an IRI. + * + * @return The characters allowed in the host part of an IRI. + */ ++ (OFCharacterSet *)IRIHostAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the user part of an IRI. + * + * @return The characters allowed in the user part of an IRI. + */ ++ (OFCharacterSet *)IRIUserAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the password part of an IRI. + * + * @return The characters allowed in the password part of an IRI. + */ ++ (OFCharacterSet *)IRIPasswordAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the path part of an IRI. + * + * @return The characters allowed in the path part of an IRI. + */ ++ (OFCharacterSet *)IRIPathAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the query part of an IRI. + * + * @return The characters allowed in the query part of an IRI. + */ ++ (OFCharacterSet *)IRIQueryAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in a key/value in the query part of a + * IRI. + * + * @return The characters allowed in a key/value in the query part of an IRI. + */ ++ (OFCharacterSet *)IRIQueryKeyValueAllowedCharacterSet; + +/** + * @brief Returns the characters allowed in the fragment part of an IRI. + * + * @return The characters allowed in the fragment part of an IRI. + */ ++ (OFCharacterSet *)IRIFragmentAllowedCharacterSet; +@end + +#ifdef __cplusplus +extern "C" { +#endif +extern bool OFIRIIsIPv6Host(OFString *host); +extern void OFIRIVerifyIsEscaped(OFString *, OFCharacterSet *, bool); +#ifdef __cplusplus +} +#endif + +OF_ASSUME_NONNULL_END + +#import "OFMutableIRI.h" ADDED src/OFIRI.m Index: src/OFIRI.m ================================================================== --- src/OFIRI.m +++ src/OFIRI.m @@ -0,0 +1,1373 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include +#include + +#import "OFIRI.h" +#import "OFArray.h" +#import "OFDictionary.h" +#ifdef OF_HAVE_FILES +# import "OFFileManager.h" +# import "OFFileIRIHandler.h" +#endif +#import "OFNumber.h" +#import "OFOnce.h" +#import "OFPair.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" +#import "OFOutOfMemoryException.h" + +@interface OFIRIAllowedCharacterSetBase: OFCharacterSet +@end + +@interface OFIRIAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +@interface OFIRISchemeAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +@interface OFIRIPathAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +@interface OFIRIQueryAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +@interface OFIRIQueryKeyValueAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +@interface OFIRIFragmentAllowedCharacterSet: OFIRIAllowedCharacterSetBase +@end + +OF_DIRECT_MEMBERS +@interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, OFUnichar); +} + +- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; +@end + +static OFCharacterSet *IRIAllowedCharacterSet = nil; +static OFCharacterSet *IRISchemeAllowedCharacterSet = nil; +static OFCharacterSet *IRIPathAllowedCharacterSet = nil; +static OFCharacterSet *IRIQueryAllowedCharacterSet = nil; +static OFCharacterSet *IRIQueryKeyValueAllowedCharacterSet = nil; +static OFCharacterSet *IRIFragmentAllowedCharacterSet = nil; + +static OFOnceControl IRIAllowedCharacterSetOnce = OFOnceControlInitValue; + +static void +initIRIAllowedCharacterSet(void) +{ + IRIAllowedCharacterSet = [[OFIRIAllowedCharacterSet alloc] init]; +} + +static void +initIRISchemeAllowedCharacterSet(void) +{ + IRISchemeAllowedCharacterSet = + [[OFIRISchemeAllowedCharacterSet alloc] init]; +} + +static void +initIRIPathAllowedCharacterSet(void) +{ + IRIPathAllowedCharacterSet = + [[OFIRIPathAllowedCharacterSet alloc] init]; +} + +static void +initIRIQueryAllowedCharacterSet(void) +{ + IRIQueryAllowedCharacterSet = + [[OFIRIQueryAllowedCharacterSet alloc] init]; +} + +static void +initIRIQueryKeyValueAllowedCharacterSet(void) +{ + IRIQueryKeyValueAllowedCharacterSet = + [[OFIRIQueryKeyValueAllowedCharacterSet alloc] init]; +} + +static void +initIRIFragmentAllowedCharacterSet(void) +{ + IRIFragmentAllowedCharacterSet = + [[OFIRIFragmentAllowedCharacterSet alloc] init]; +} + +bool +OFIRIIsIPv6Host(OFString *host) +{ + const char *UTF8String = host.UTF8String; + bool hasColon = false; + + while (*UTF8String != '\0') { + if (!OFASCIIIsDigit(*UTF8String) && *UTF8String != ':' && + (*UTF8String < 'a' || *UTF8String > 'f') && + (*UTF8String < 'A' || *UTF8String > 'F')) + return false; + + if (*UTF8String == ':') + hasColon = true; + + UTF8String++; + } + + return hasColon; +} + +static bool +isUnicode(OFUnichar character) +{ + if (character >= 0xA0 && character <= 0xD7FF) + return true; + if (character >= 0xF900 && character <= 0xFDCF) + return true; + if (character >= 0xFDF0 && character <= 0xFFEF) + return true; + if (character >= 0x10000 && character <= 0x1FFFD) + return true; + if (character >= 0x20000 && character <= 0x2FFFD) + return true; + if (character >= 0x30000 && character <= 0x3FFFD) + return true; + if (character >= 0x40000 && character <= 0x4FFFD) + return true; + if (character >= 0x50000 && character <= 0x5FFFD) + return true; + if (character >= 0x60000 && character <= 0x6FFFD) + return true; + if (character >= 0x70000 && character <= 0x7FFFD) + return true; + if (character >= 0x80000 && character <= 0x8FFFD) + return true; + if (character >= 0x90000 && character <= 0x9FFFD) + return true; + if (character >= 0xA0000 && character <= 0xAFFFD) + return true; + if (character >= 0xB0000 && character <= 0xBFFFD) + return true; + if (character >= 0xC0000 && character <= 0xCFFFD) + return true; + if (character >= 0xD0000 && character <= 0xDFFFD) + return true; + if (character >= 0xE0000 && character <= 0xEFFFD) + return true; + + return false; +} + +static bool +isUnicodePrivate(OFUnichar character) +{ + if (character >= 0xE00 && character <= 0xF8FF) + return true; + if (character >= 0xF0000 && character <= 0xFFFFD) + return true; + if (character >= 0x100000 && character <= 0x10FFFD) + return true; + + return false; +} + +@implementation OFIRIAllowedCharacterSetBase +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OFMaxRetainCount; +} +@end + +@implementation OFIRIAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + if (isUnicode(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return true; + default: + return false; + } +} +@end + +@implementation OFIRISchemeAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + switch (character) { + case '+': + case '-': + case '.': + return true; + default: + return false; + } +} +@end + +@implementation OFIRIPathAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + if (isUnicode(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '/': + return true; + default: + return false; + } +} +@end + +@implementation OFIRIQueryAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + if (isUnicode(character) || isUnicodePrivate(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '/': + case '?': + return true; + default: + return false; + } +} +@end + +@implementation OFIRIQueryKeyValueAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + if (isUnicode(character) || isUnicodePrivate(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case ':': + case '@': + case '/': + case '?': + return true; + default: + return false; + } +} +@end + +@implementation OFIRIFragmentAllowedCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + if (character < CHAR_MAX && OFASCIIIsAlnum(character)) + return true; + + if (isUnicode(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '/': + case '?': + return true; + default: + return false; + } +} +@end + +@implementation OFInvertedCharacterSetWithoutPercent +- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet +{ + self = [super init]; + + @try { + _characterSet = [characterSet retain]; + _characterIsMember = (bool (*)(id, SEL, OFUnichar)) + [_characterSet methodForSelector: + @selector(characterIsMember:)]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_characterSet release]; + + [super dealloc]; +} + +- (bool)characterIsMember: (OFUnichar)character +{ + return (character != '%' && !_characterIsMember(_characterSet, + @selector(characterIsMember:), character)); +} +@end + +void +OFIRIVerifyIsEscaped(OFString *string, OFCharacterSet *characterSet, + bool allowPercent) +{ + void *pool = objc_autoreleasePoolPush(); + + if (allowPercent) + characterSet = [[[OFInvertedCharacterSetWithoutPercent alloc] + initWithCharacterSet: characterSet] autorelease]; + else + characterSet = characterSet.invertedSet; + + if ([string indexOfCharacterFromSet: characterSet] != OFNotFound) + @throw [OFInvalidFormatException exception]; + + objc_autoreleasePoolPop(pool); +} + +@implementation OFCharacterSet (IRICharacterSets) ++ (OFCharacterSet *)IRISchemeAllowedCharacterSet +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initIRISchemeAllowedCharacterSet); + + return IRISchemeAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIHostAllowedCharacterSet +{ + OFOnce(&IRIAllowedCharacterSetOnce, initIRIAllowedCharacterSet); + + return IRIAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIUserAllowedCharacterSet +{ + OFOnce(&IRIAllowedCharacterSetOnce, initIRIAllowedCharacterSet); + + return IRIAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIPasswordAllowedCharacterSet +{ + OFOnce(&IRIAllowedCharacterSetOnce, initIRIAllowedCharacterSet); + + return IRIAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIPathAllowedCharacterSet +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initIRIPathAllowedCharacterSet); + + return IRIPathAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIQueryAllowedCharacterSet +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initIRIQueryAllowedCharacterSet); + + return IRIQueryAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIQueryKeyValueAllowedCharacterSet +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initIRIQueryKeyValueAllowedCharacterSet); + + return IRIQueryKeyValueAllowedCharacterSet; +} + ++ (OFCharacterSet *)IRIFragmentAllowedCharacterSet +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, initIRIFragmentAllowedCharacterSet); + + return IRIFragmentAllowedCharacterSet; +} +@end + +@implementation OFIRI ++ (instancetype)IRI +{ + return [[[self alloc] init] autorelease]; +} + ++ (instancetype)IRIWithString: (OFString *)string +{ + return [[[self alloc] initWithString: string] autorelease]; +} + ++ (instancetype)IRIWithString: (OFString *)string relativeToIRI: (OFIRI *)IRI +{ + return [[[self alloc] initWithString: string + relativeToIRI: IRI] autorelease]; +} + +#ifdef OF_HAVE_FILES ++ (instancetype)fileIRIWithPath: (OFString *)path +{ + return [[[self alloc] initFileIRIWithPath: path] autorelease]; +} + ++ (instancetype)fileIRIWithPath: (OFString *)path isDirectory: (bool)isDirectory +{ + return [[[self alloc] initFileIRIWithPath: path + isDirectory: isDirectory] autorelease]; +} +#endif + +static void +parseUserInfo(OFIRI *self, const char *UTF8String, size_t length) +{ + const char *colon; + + if ((colon = memchr(UTF8String, ':', length)) != NULL) { + self->_percentEncodedUser = [[OFString alloc] + initWithUTF8String: UTF8String + length: colon - UTF8String]; + self->_percentEncodedPassword = [[OFString alloc] + initWithUTF8String: colon + 1 + length: length - (colon - UTF8String) - 1]; + + OFIRIVerifyIsEscaped(self->_percentEncodedPassword, + [OFCharacterSet IRIPasswordAllowedCharacterSet], true); + } else + self->_percentEncodedUser = [[OFString alloc] + initWithUTF8String: UTF8String + length: length]; + + OFIRIVerifyIsEscaped(self->_percentEncodedUser, + [OFCharacterSet IRIUserAllowedCharacterSet], true); +} + +static void +parseHostPort(OFIRI *self, const char *UTF8String, size_t length) +{ + OFString *portString; + + if (*UTF8String == '[') { + const char *end = memchr(UTF8String, ']', length); + + if (end == NULL) + @throw [OFInvalidFormatException exception]; + + for (const char *iter = UTF8String + 1; iter < end; iter++) + if (!OFASCIIIsDigit(*iter) && *iter != ':' && + (*iter < 'a' || *iter > 'f') && + (*iter < 'A' || *iter > 'F')) + @throw [OFInvalidFormatException exception]; + + self->_percentEncodedHost = [[OFString alloc] + initWithUTF8String: UTF8String + length: end - UTF8String + 1]; + + length -= (end - UTF8String) + 1; + UTF8String = end + 1; + } else { + const char *colon = memchr(UTF8String, ':', length); + + if (colon != NULL) { + self->_percentEncodedHost = [[OFString alloc] + initWithUTF8String: UTF8String + length: colon - UTF8String]; + + length -= colon - UTF8String; + UTF8String = colon; + } else { + self->_percentEncodedHost = [[OFString alloc] + initWithUTF8String: UTF8String + length: length]; + + UTF8String += length; + length = 0; + } + + OFIRIVerifyIsEscaped(self->_percentEncodedHost, + [OFCharacterSet IRIHostAllowedCharacterSet], true); + } + + if (length == 0) + return; + + if (length <= 1 || *UTF8String != ':') + @throw [OFInvalidFormatException exception]; + + UTF8String++; + length--; + + for (size_t i = 0; i < length; i++) + if (!OFASCIIIsDigit(UTF8String[i])) + @throw [OFInvalidFormatException exception]; + + portString = [OFString stringWithUTF8String: UTF8String length: length]; + + if (portString.unsignedLongLongValue > 65535) + @throw [OFInvalidFormatException exception]; + + self->_port = [[OFNumber alloc] initWithUnsignedShort: + (unsigned short)portString.unsignedLongLongValue]; +} + +static size_t +parseAuthority(OFIRI *self, const char *UTF8String, size_t length) +{ + size_t ret; + const char *slash, *at; + + if ((slash = memchr(UTF8String, '/', length)) != NULL) + length = slash - UTF8String; + + ret = length; + + if ((at = memchr(UTF8String, '@', length)) != NULL) { + parseUserInfo(self, UTF8String, at - UTF8String); + + length -= at - UTF8String + 1; + UTF8String = at + 1; + } + + parseHostPort(self, UTF8String, length); + + return ret; +} + +static void +parsePathQueryFragment(const char *UTF8String, size_t length, + OFString **pathString, OFString **queryString, OFString **fragmentString) +{ + const char *fragment, *query; + + if ((fragment = memchr(UTF8String, '#', length)) != NULL) { + *fragmentString = [OFString + stringWithUTF8String: fragment + 1 + length: length - (fragment - UTF8String) - 1]; + + OFIRIVerifyIsEscaped(*fragmentString, + [OFCharacterSet IRIQueryAllowedCharacterSet], true); + + length = fragment - UTF8String; + } + + if ((query = memchr(UTF8String, '?', length)) != NULL) { + *queryString = [OFString + stringWithUTF8String: query + 1 + length: length - (query - UTF8String) - 1]; + + OFIRIVerifyIsEscaped(*queryString, + [OFCharacterSet IRIFragmentAllowedCharacterSet], true); + + length = query - UTF8String; + } + + *pathString = [OFString stringWithUTF8String: UTF8String + length: length]; + + OFIRIVerifyIsEscaped(*pathString, + [OFCharacterSet IRIPathAllowedCharacterSet], true); +} + +- (instancetype)initWithString: (OFString *)string +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + const char *UTF8String = string.UTF8String; + size_t length = string.UTF8StringLength; + const char *colon; + OFString *path, *query = nil, *fragment = nil; + + if ((colon = strchr(UTF8String, ':')) == NULL || + colon - UTF8String < 1 || !OFASCIIIsAlpha(UTF8String[0])) + @throw [OFInvalidFormatException exception]; + + _scheme = [[[OFString stringWithUTF8String: UTF8String + length: colon - UTF8String] + lowercaseString] copy]; + + OFIRIVerifyIsEscaped(_scheme, + [OFCharacterSet IRISchemeAllowedCharacterSet], false); + + length -= colon - UTF8String + 1; + UTF8String = colon + 1; + + if (length >= 2 && UTF8String[0] == '/' && + UTF8String[1] == '/') { + size_t authorityLength; + + UTF8String += 2; + length -= 2; + + authorityLength = parseAuthority(self, + UTF8String, length); + + UTF8String += authorityLength; + length -= authorityLength; + + if (length > 0) + OFEnsure(UTF8String[0] == '/'); + } + + parsePathQueryFragment(UTF8String, length, + &path, &query, &fragment); + _percentEncodedPath = [path copy]; + _percentEncodedQuery = [query copy]; + _percentEncodedFragment = [fragment copy]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +static bool +isAbsolute(OFString *string) +{ + void *pool = objc_autoreleasePoolPush(); + + @try { + const char *UTF8String = string.UTF8String; + size_t length = string.UTF8StringLength; + + if (length < 1) + return false; + + if (!OFASCIIIsAlpha(UTF8String[0])) + return false; + + for (size_t i = 1; i < length; i++) { + if (UTF8String[i] == ':') + return true; + + if (!OFASCIIIsAlnum(UTF8String[i]) && + UTF8String[i] != '+' && UTF8String[i] != '-' && + UTF8String[i] != '.') + return false; + } + } @finally { + objc_autoreleasePoolPop(pool); + } + + return false; +} + +static OFString * +merge(OFString *base, OFString *path) +{ + OFMutableArray *components; + + if (base.length == 0) + base = @"/"; + + components = [[[base componentsSeparatedByString: @"/"] + mutableCopy] autorelease]; + + if (components.count == 1) + [components addObject: path]; + else + [components replaceObjectAtIndex: components.count - 1 + withObject: path]; + + return [components componentsJoinedByString: @"/"]; +} + +- (instancetype)initWithString: (OFString *)string relativeToIRI: (OFIRI *)IRI +{ + bool absolute; + + @try { + absolute = isAbsolute(string); + } @catch (id e) { + [self release]; + @throw e; + } + + if (absolute) + return [self initWithString: string]; + + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + const char *UTF8String = string.UTF8String; + size_t length = string.UTF8StringLength; + bool hasAuthority = false; + OFString *path, *query = nil, *fragment = nil; + + _scheme = [IRI->_scheme copy]; + + if (length >= 2 && UTF8String[0] == '/' && + UTF8String[1] == '/') { + size_t authorityLength; + + hasAuthority = true; + + UTF8String += 2; + length -= 2; + + authorityLength = parseAuthority(self, + UTF8String, length); + + UTF8String += authorityLength; + length -= authorityLength; + + if (length > 0) + OFEnsure(UTF8String[0] == '/'); + } else { + _percentEncodedHost = [IRI->_percentEncodedHost copy]; + _port = [IRI->_port copy]; + _percentEncodedUser = [IRI->_percentEncodedUser copy]; + _percentEncodedPassword = + [IRI->_percentEncodedPassword copy]; + } + + parsePathQueryFragment(UTF8String, length, + &path, &query, &fragment); + _percentEncodedFragment = [fragment copy]; + + if (hasAuthority) { + _percentEncodedPath = [path copy]; + _percentEncodedQuery = [query copy]; + } else { + if (path.length == 0) { + _percentEncodedPath = + [IRI->_percentEncodedPath copy]; + _percentEncodedQuery = (query != nil + ? [query copy] + : [IRI->_percentEncodedQuery copy]); + } else { + if ([path hasPrefix: @"/"]) + _percentEncodedPath = [path copy]; + else + _percentEncodedPath = [merge( + IRI->_percentEncodedPath, path) + copy]; + + _percentEncodedQuery = [query copy]; + } + } + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +#ifdef OF_HAVE_FILES +- (instancetype)initFileIRIWithPath: (OFString *)path +{ + bool isDirectory; + + @try { + void *pool = objc_autoreleasePoolPush(); + isDirectory = [path of_isDirectoryPath]; + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + self = [self initFileIRIWithPath: path isDirectory: isDirectory]; + + return self; +} + +- (instancetype)initFileIRIWithPath: (OFString *)path + isDirectory: (bool)isDirectory +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFString *percentEncodedHost = nil; + + if (!path.absolutePath) { + OFString *currentDirectoryPath = [OFFileManager + defaultManager].currentDirectoryPath; + + path = [currentDirectoryPath + stringByAppendingPathComponent: path]; + path = path.stringByStandardizingPath; + } + + path = [path of_pathToIRIPathWithPercentEncodedHost: + &percentEncodedHost]; + _percentEncodedHost = [percentEncodedHost copy]; + + if (isDirectory && ![path hasSuffix: @"/"]) + path = [path stringByAppendingString: @"/"]; + + _scheme = @"file"; + _percentEncodedPath = [[path + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIPathAllowedCharacterSet]] copy]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} +#endif + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)of_init +{ + return [super init]; +} + +- (void)dealloc +{ + [_scheme release]; + [_percentEncodedHost release]; + [_port release]; + [_percentEncodedUser release]; + [_percentEncodedPassword release]; + [_percentEncodedPath release]; + [_percentEncodedQuery release]; + [_percentEncodedFragment release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFIRI *IRI; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFIRI class]]) + return false; + + IRI = object; + + if (![IRI->_scheme isEqual: _scheme]) + return false; + if (IRI->_percentEncodedHost != _percentEncodedHost && + ![IRI->_percentEncodedHost isEqual: _percentEncodedHost]) + return false; + if (IRI->_port != _port && ![IRI->_port isEqual: _port]) + return false; + if (IRI->_percentEncodedUser != _percentEncodedUser && + ![IRI->_percentEncodedUser isEqual: _percentEncodedUser]) + return false; + if (IRI->_percentEncodedPassword != _percentEncodedPassword && + ![IRI->_percentEncodedPassword isEqual: _percentEncodedPassword]) + return false; + if (![IRI->_percentEncodedPath isEqual: _percentEncodedPath]) + return false; + if (IRI->_percentEncodedQuery != _percentEncodedQuery && + ![IRI->_percentEncodedQuery isEqual: _percentEncodedQuery]) + return false; + if (IRI->_percentEncodedFragment != _percentEncodedFragment && + ![IRI->_percentEncodedFragment isEqual: _percentEncodedFragment]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _scheme.hash); + OFHashAddHash(&hash, _percentEncodedHost.hash); + OFHashAddHash(&hash, _port.hash); + OFHashAddHash(&hash, _percentEncodedUser.hash); + OFHashAddHash(&hash, _percentEncodedPassword.hash); + OFHashAddHash(&hash, _percentEncodedPath.hash); + OFHashAddHash(&hash, _percentEncodedQuery.hash); + OFHashAddHash(&hash, _percentEncodedFragment.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)scheme +{ + return _scheme; +} + +- (OFString *)host +{ + if ([_percentEncodedHost hasPrefix: @"["] && + [_percentEncodedHost hasSuffix: @"]"]) { + OFString *host = [_percentEncodedHost substringWithRange: + OFMakeRange(1, _percentEncodedHost.length - 2)]; + + if (!OFIRIIsIPv6Host(host)) + @throw [OFInvalidArgumentException exception]; + + return host; + } + + return _percentEncodedHost.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedHost +{ + return _percentEncodedHost; +} + +- (OFNumber *)port +{ + return _port; +} + +- (OFString *)user +{ + return _percentEncodedUser.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedUser +{ + return _percentEncodedUser; +} + +- (OFString *)password +{ + return _percentEncodedPassword.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedPassword +{ + return _percentEncodedPassword; +} + +- (OFString *)path +{ + return _percentEncodedPath.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedPath +{ + return _percentEncodedPath; +} + +- (OFArray *)pathComponents +{ + void *pool = objc_autoreleasePoolPush(); +#ifdef OF_HAVE_FILES + bool isFile = [_scheme isEqual: @"file"]; +#endif + OFMutableArray *ret; + size_t count; + +#ifdef OF_HAVE_FILES + if (isFile) { + OFString *path = [_percentEncodedPath + of_IRIPathToPathWithPercentEncodedHost: nil]; + ret = [[path.pathComponents mutableCopy] autorelease]; + + if (![ret.firstObject isEqual: @"/"]) + [ret insertObject: @"/" atIndex: 0]; + } else +#endif + ret = [[[_percentEncodedPath componentsSeparatedByString: @"/"] + mutableCopy] autorelease]; + + count = ret.count; + + if (count > 0 && [ret.firstObject length] == 0) + [ret replaceObjectAtIndex: 0 withObject: @"/"]; + + for (size_t i = 0; i < count; i++) { + OFString *component = [ret objectAtIndex: i]; + +#ifdef OF_HAVE_FILES + if (isFile) + component = + [component of_pathComponentToIRIPathComponent]; +#endif + + component = component.stringByRemovingPercentEncoding; + [ret replaceObjectAtIndex: i withObject: component]; + } + + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)lastPathComponent +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path = _percentEncodedPath; + const char *UTF8String, *lastComponent; + size_t length; + OFString *ret; + + if ([path isEqual: @"/"]) { + objc_autoreleasePoolPop(pool); + return @"/"; + } + + if ([path hasSuffix: @"/"]) + path = [path substringToIndex: path.length - 1]; + + UTF8String = lastComponent = path.UTF8String; + length = path.UTF8StringLength; + + for (size_t i = 1; i <= length; i++) { + if (UTF8String[length - i] == '/') { + lastComponent = UTF8String + (length - i) + 1; + break; + } + } + + ret = [OFString + stringWithUTF8String: lastComponent + length: length - (lastComponent - UTF8String)]; + ret = [ret.stringByRemovingPercentEncoding retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)query +{ + return _percentEncodedQuery.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedQuery +{ + return _percentEncodedQuery; +} + +- (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *)queryItems +{ + void *pool; + OFArray OF_GENERIC(OFString *) *pairs; + OFMutableArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) + *ret; + + if (_percentEncodedQuery == nil) + return nil; + + pool = objc_autoreleasePoolPush(); + pairs = [_percentEncodedQuery componentsSeparatedByString: @"&"]; + ret = [OFMutableArray arrayWithCapacity: pairs.count]; + + for (OFString *pair in pairs) { + OFArray *parts = [pair componentsSeparatedByString: @"="]; + OFString *name, *value; + + if (parts.count != 2) + @throw [OFInvalidFormatException exception]; + + name = [[parts objectAtIndex: 0] + stringByRemovingPercentEncoding]; + value = [[parts objectAtIndex: 1] + stringByRemovingPercentEncoding]; + + [ret addObject: [OFPair pairWithFirstObject: name + secondObject: value]]; + } + + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} + +- (OFString *)fragment +{ + return _percentEncodedFragment.stringByRemovingPercentEncoding; +} + +- (OFString *)percentEncodedFragment +{ + return _percentEncodedFragment; +} + +- (id)copy +{ + return [self retain]; +} + +- (id)mutableCopy +{ + OFIRI *copy = [[OFMutableIRI alloc] initWithScheme: _scheme]; + + @try { + copy->_percentEncodedHost = [_percentEncodedHost copy]; + copy->_port = [_port copy]; + copy->_percentEncodedUser = [_percentEncodedUser copy]; + copy->_percentEncodedPassword = [_percentEncodedPassword copy]; + copy->_percentEncodedPath = [_percentEncodedPath copy]; + copy->_percentEncodedQuery = [_percentEncodedQuery copy]; + copy->_percentEncodedFragment = [_percentEncodedFragment copy]; + } @catch (id e) { + [copy release]; + @throw e; + } + + return copy; +} + +- (OFString *)string +{ + OFMutableString *ret = [OFMutableString string]; + + [ret appendFormat: @"%@:", _scheme]; + + if (_percentEncodedHost != nil || _port != nil || + _percentEncodedUser != nil || _percentEncodedPassword != nil) + [ret appendString: @"//"]; + + if (_percentEncodedUser != nil && _percentEncodedPassword != nil) + [ret appendFormat: @"%@:%@@", + _percentEncodedUser, + _percentEncodedPassword]; + else if (_percentEncodedUser != nil) + [ret appendFormat: @"%@@", _percentEncodedUser]; + + if (_percentEncodedHost != nil) + [ret appendString: _percentEncodedHost]; + if (_port != nil) + [ret appendFormat: @":%@", _port]; + + [ret appendString: _percentEncodedPath]; + + if (_percentEncodedQuery != nil) + [ret appendFormat: @"?%@", _percentEncodedQuery]; + + if (_percentEncodedFragment != nil) + [ret appendFormat: @"#%@", _percentEncodedFragment]; + + [ret makeImmutable]; + + return ret; +} + +#ifdef OF_HAVE_FILES +- (OFString *)fileSystemRepresentation +{ + void *pool = objc_autoreleasePoolPush(); + OFString *path; + + if (![_scheme isEqual: @"file"]) + @throw [OFInvalidArgumentException exception]; + + if (![_percentEncodedPath hasPrefix: @"/"]) + @throw [OFInvalidFormatException exception]; + + path = [self.path + of_IRIPathToPathWithPercentEncodedHost: _percentEncodedHost]; + + [path retain]; + + objc_autoreleasePoolPop(pool); + + return [path autorelease]; +} +#endif + +- (OFIRI *)IRIByAppendingPathComponent: (OFString *)component +{ + OFMutableIRI *IRI = [[self mutableCopy] autorelease]; + [IRI appendPathComponent: component]; + [IRI makeImmutable]; + return IRI; +} + +- (OFIRI *)IRIByAppendingPathComponent: (OFString *)component + isDirectory: (bool)isDirectory +{ + OFMutableIRI *IRI = [[self mutableCopy] autorelease]; + [IRI appendPathComponent: component isDirectory: isDirectory]; + [IRI makeImmutable]; + return IRI; +} + +- (OFIRI *)IRIByStandardizingPath +{ + OFMutableIRI *IRI = [[self mutableCopy] autorelease]; + [IRI standardizePath]; + [IRI makeImmutable]; + return IRI; +} + +- (OFIRI *)IRIByAddingPercentEncodingForUnicodeCharacters +{ + OFMutableIRI *IRI = [[self mutableCopy] autorelease]; + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *ASCII = + [OFCharacterSet characterSetWithRange: OFMakeRange(0, 0x80)]; + + IRI.percentEncodedHost = [_percentEncodedHost + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + IRI.percentEncodedUser = [_percentEncodedUser + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + IRI.percentEncodedPassword = [_percentEncodedPassword + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + IRI.percentEncodedPath = [_percentEncodedPath + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + IRI.percentEncodedQuery = [_percentEncodedQuery + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + IRI.percentEncodedFragment = [_percentEncodedFragment + stringByAddingPercentEncodingWithAllowedCharacters: ASCII]; + + [IRI makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return IRI; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", + self.class, self.string]; +} +@end ADDED src/OFIRIHandler.h Index: src/OFIRIHandler.h ================================================================== --- src/OFIRIHandler.h +++ src/OFIRIHandler.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFFileManager.h" +#import "OFObject.h" +#import "OFString.h" + +OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFData; +@class OFDate; +@class OFIRI; +@class OFStream; + +/** + * @class OFIRIHandler OFIRIHandler.h ObjFW/OFIRIHandler.h + * + * @brief A handler for an IRI scheme. + */ +@interface OFIRIHandler: OFObject +{ + OFString *_scheme; + OF_RESERVE_IVARS(OFIRIHandler, 4) +} + +/** + * @brief The scheme this OFIRIHandler handles. + */ +@property (readonly, nonatomic) OFString *scheme; + +/** + * @brief Registers the specified class as the handler for the specified scheme. + * + * If the same class is specified for two schemes, one instance of it is + * created per scheme. + * + * @param class_ The class to register as the handler for the specified scheme + * @param scheme The scheme for which to register the handler + * @return Whether the class was successfully registered. If a handler for the + * same scheme is already registered, registration fails. + */ ++ (bool)registerClass: (Class)class_ forScheme: (OFString *)scheme; + +/** + * @brief Returns the handler for the specified IRI. + * + * @return The handler for the specified IRI. + * @throw OFUnsupportedProtocolException The specified IRI is not supported + */ ++ (OFIRIHandler *)handlerForIRI: (OFIRI *)IRI; + +/** + * @brief Opens the item at the specified IRI. + * + * @param IRI The IRI of the item which should be opened + * @param mode The mode in which the file should be opened.@n + * Possible modes are: + * @n + * Mode | Description + * ---------------|------------------------------------- + * `r` | Read-only + * `r+` | Read-write + * `w` | Write-only, create or truncate + * `wx` | Write-only, create or fail, exclusive + * `w+` | Read-write, create or truncate + * `w+x` | Read-write, create or fail, exclusive + * `a` | Write-only, create or append + * `a+` | Read-write, create or append + * @n + * The handler is allowed to not implement all modes and is also + * allowed to implement additional, scheme-specific modes. + * @return The opened stream if it was successfully opened + * @throw OFOpenItemFailedException Opening the item failed + * @throw OFUnsupportedProtocolException The specified IRI is not supported + */ ++ (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Initializes the handler for the specified scheme. + * + * @param scheme The scheme to initialize for + * @return An initialized IRI handler + */ +- (instancetype)initWithScheme: (OFString *)scheme OF_DESIGNATED_INITIALIZER; + +/** + * @brief Opens the item at the specified IRI. + * + * @param IRI The IRI of the item which should be opened + * @param mode The mode in which the file should be opened.@n + * Possible modes are: + * @n + * Mode | Description + * ---------------|------------------------------------- + * `r` | Read-only + * `r+` | Read-write + * `w` | Write-only, create or truncate + * `wx` | Write-only, create or fail, exclusive + * `w+` | Read-write, create or truncate + * `w+x` | Read-write, create or fail, exclusive + * `a` | Write-only, create or append + * `a+` | Read-write, create or append + * @n + * The handler is allowed to not implement all modes and is also + * allowed to implement additional, scheme-specific modes. + * @return The opened stream if it was successfully opened + * @throw OFOpenItemFailedException Opening the item failed + * @throw OFUnsupportedProtocolException The specified IRI is not supported by + * the handler + */ +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode; + +/** + * @brief Returns the attributes for the item at the specified IRI. + * + * @param IRI The IRI to return the attributes for + * @return A dictionary of attributes for the specified IRI, with the keys of + * type @ref OFFileAttributeKey + * @throw OFGetItemAttributesFailedException Failed to get the attributes of + * the item + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (OFFileAttributes)attributesOfItemAtIRI: (OFIRI *)IRI; + +/** + * @brief Sets the attributes for the item at the specified IRI. + * + * All attributes not part of the dictionary are left unchanged. + * + * @param attributes The attributes to set for the specified IRI + * @param IRI The IRI of the item to set the attributes for + * @@throw OFSetItemAttributesFailedException Failed to set the attributes of + * the item + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + * @throw OFNotImplementedException Setting one or more of the specified + * attributes is not implemented for the + * specified item + */ +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtIRI: (OFIRI *)IRI; + +/** + * @brief Checks whether a file exists at the specified IRI. + * + * @param IRI The IRI to check + * @return A boolean whether there is a file at the specified IRI + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (bool)fileExistsAtIRI: (OFIRI *)IRI; + +/** + * @brief Checks whether a directory exists at the specified IRI. + * + * @param IRI The IRI to check + * @return A boolean whether there is a directory at the specified IRI + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (bool)directoryExistsAtIRI: (OFIRI *)IRI; + +/** + * @brief Creates a directory at the specified IRI. + * + * @param IRI The IRI of the directory to create + * @throw OFCreateDirectoryFailedException Creating the directory failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (void)createDirectoryAtIRI: (OFIRI *)IRI; + +/** + * @brief Returns an array with the IRIs of the items in the specified + * directory. + * + * @note `.` and `..` are not part of the returned array. + * + * @param IRI The IRI to the directory whose items should be returned + * @return An array with the IRIs of the items in the specified directory + * @throw OFOpenItemFailedException Opening the directory failed + * @throw OFReadFailedException Reading from the directory failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (OFArray OF_GENERIC(OFIRI *) *)contentsOfDirectoryAtIRI: (OFIRI *)IRI; + +/** + * @brief Removes the item at the specified IRI. + * + * If the item at the specified IRI is a directory, it is removed recursively. + * + * @param IRI The IRI to the item which should be removed + * @throw OFRemoveItemFailedException Removing the item failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (void)removeItemAtIRI: (OFIRI *)IRI; + +/** + * @brief Creates a hard link for the specified item. + * + * The destination IRI must have a full path, which means it must include the + * name of the item. + * + * This method is not available for all IRIs. + * + * @param source The IRI to the item for which a link should be created + * @param destination The IRI to the item which should link to the source + * @throw OFLinkItemFailedException Linking the item failed + * @throw OFUnsupportedProtocolException The handler cannot handle the scheme + * of one of the IRIs + * @throw OFNotImplementedException Hardlinks are not implemented for the + * specified IRI + */ +- (void)linkItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; + +/** + * @brief Creates a symbolic link for an item. + * + * The destination IRI must have a full path, which means it must include the + * name of the item. + * + * This method is not available for all IRIs. + * + * @note On Windows, this requires at least Windows Vista and administrator + * privileges! + * + * @param IRI The IRI to the item which should symbolically link to the target + * @param target The target of the symbolic link + * @throw OFCreateSymbolicLinkFailed Creating a symbolic link failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (void)createSymbolicLinkAtIRI: (OFIRI *)IRI + withDestinationPath: (OFString *)target; + +/** + * @brief Tries to efficiently copy an item. If a copy would only be possible + * by reading the entire item and then writing it, it returns false. + * + * The destination IRI must have a full path, which means it must include the + * name of the item. + * + * If an item already exists, the copy operation fails. This is also the case + * if a directory is copied and an item already exists in the destination + * directory. + * + * @param source The file, directory or symbolic link to copy + * @param destination The destination IRI + * @return True if an efficient copy was performed, false if an efficient copy + * was not possible. Note that errors while performing a copy are + * reported via exceptions and not by returning false! + * @throw OFCopyItemFailedException Copying failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (bool)copyItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; + +/** + * @brief Tries to efficiently move an item. If a move would only be possible + * by copying the source and deleting it, it returns false. + * + * The destination IRI must have a full path, which means it must include the + * name of the item. + * + * If the destination is on a different logical device or uses a different + * scheme, an efficient move is not possible and false is returned. + * + * @param source The item to rename + * @param destination The new name for the item + * @return True if an efficient move was performed, false if an efficient move + * was not possible. Note that errors while performing a move are + * reported via exceptions and not by returning false! + * @throw OFMoveItemFailedException Moving failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + */ +- (bool)moveItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination; + +/** + * @brief Returns the extended attribute data for the specified name of the + * item at the specified IRI. + * + * This method is not available for all IRIs. + * + * @param name The name of the extended attribute + * @param IRI The IRI of the item to return the extended attribute from + * @throw OFGetItemAttributesFailedException Getting the extended attribute + * failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + * @throw OFNotImplementedException Getting extended attributes is not + * implemented for the specified item + */ +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; + +/** + * @brief Sets the extended attribute data for the specified name of the item + * at the specified IRI. + * + * This method is not available for all IRIs. + * + * @param data The data for the extended attribute + * @param name The name of the extended attribute + * @param IRI The IRI of the item to set the extended attribute on + * @throw OFSetItemAttributesFailedException Setting the extended attribute + * failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + * @throw OFNotImplementedException Setting extended attributes is not + * implemented for the specified item + */ +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; + +/** + * @brief Removes the extended attribute for the specified name wof the item at + * the specified IRI. + * + * This method is not available for all IRIs. + * + * @param name The name of the extended attribute to remove + * @param IRI The IRI of the item to remove the extended attribute from + * @throw OFSetItemAttributesFailedException Removing the extended attribute + * failed + * @throw OFUnsupportedProtocolException The handler cannot handle the IRI's + * scheme + * @throw OFNotImplementedException Removing extended attributes is not + * implemented for the specified item + */ +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFIRIHandler.m Index: src/OFIRIHandler.m ================================================================== --- src/OFIRIHandler.m +++ src/OFIRIHandler.m @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFIRIHandler.h" +#import "OFDictionary.h" +#import "OFIRI.h" +#import "OFNumber.h" + +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif + +#import "OFArchiveIRIHandler.h" +#import "OFEmbeddedIRIHandler.h" +#ifdef OF_HAVE_FILES +# import "OFFileIRIHandler.h" +#endif +#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) +# import "OFHTTPIRIHandler.h" +#endif + +#import "OFUnsupportedProtocolException.h" + +static OFMutableDictionary OF_GENERIC(OFString *, OFIRIHandler *) *handlers; +#ifdef OF_HAVE_THREADS +static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} +#endif + +@implementation OFIRIHandler +@synthesize scheme = _scheme; + ++ (void)initialize +{ + if (self != [OFIRIHandler class]) + return; + + handlers = [[OFMutableDictionary alloc] init]; +#ifdef OF_HAVE_THREADS + mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); +#endif + + [self registerClass: [OFEmbeddedIRIHandler class] + forScheme: @"embedded"]; +#ifdef OF_HAVE_FILES + [self registerClass: [OFFileIRIHandler class] forScheme: @"file"]; +#endif +#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) + [self registerClass: [OFHTTPIRIHandler class] forScheme: @"http"]; + [self registerClass: [OFHTTPIRIHandler class] forScheme: @"https"]; +#endif + [self registerClass: [OFArchiveIRIHandler class] forScheme: @"gzip"]; + [self registerClass: [OFArchiveIRIHandler class] forScheme: @"lha"]; + [self registerClass: [OFArchiveIRIHandler class] forScheme: @"tar"]; + [self registerClass: [OFArchiveIRIHandler class] forScheme: @"zip"]; +} + ++ (bool)registerClass: (Class)class forScheme: (OFString *)scheme +{ +#ifdef OF_HAVE_THREADS + [mutex lock]; + @try { +#endif + OFIRIHandler *handler; + + if ([handlers objectForKey: scheme] != nil) + return false; + + handler = [[class alloc] initWithScheme: scheme]; + @try { + [handlers setObject: handler forKey: scheme]; + } @finally { + [handler release]; + } +#ifdef OF_HAVE_THREADS + } @finally { + [mutex unlock]; + } +#endif + + return true; +} + ++ (OFIRIHandler *)handlerForIRI: (OFIRI *)IRI +{ + OF_KINDOF(OFIRIHandler *) handler; + +#ifdef OF_HAVE_THREADS + [mutex lock]; + @try { +#endif + handler = [handlers objectForKey: IRI.scheme]; +#ifdef OF_HAVE_THREADS + } @finally { + [mutex unlock]; + } +#endif + + if (handler == nil) + @throw [OFUnsupportedProtocolException exceptionWithIRI: IRI]; + + return handler; +} + ++ (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + return [[self handlerForIRI: IRI] openItemAtIRI: IRI mode: mode]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithScheme: (OFString *)scheme +{ + self = [super init]; + + @try { + _scheme = [scheme copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_scheme release]; + + [super dealloc]; +} + +- (OFStream *)openItemAtIRI: (OFIRI *)IRI mode: (OFString *)mode +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFFileAttributes)attributesOfItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setAttributes: (OFFileAttributes)attributes ofItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)fileExistsAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)directoryExistsAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)createDirectoryAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (OFArray OF_GENERIC(OFIRI *) *)contentsOfDirectoryAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)removeItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)linkItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)createSymbolicLinkAtIRI: (OFIRI *)destination + withDestinationPath: (OFString *)source +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (bool)copyItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination +{ + return false; +} + +- (bool)moveItemAtIRI: (OFIRI *)source toIRI: (OFIRI *)destination +{ + return false; +} + +- (OFData *)extendedAttributeDataForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)setExtendedAttributeData: (OFData *)data + forName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (void)removeExtendedAttributeForName: (OFString *)name + ofItemAtIRI: (OFIRI *)IRI +{ + OF_UNRECOGNIZED_SELECTOR +} +@end Index: src/OFInflate64Stream.h ================================================================== --- src/OFInflate64Stream.h +++ src/OFInflate64Stream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInflate64Stream.m ================================================================== --- src/OFInflate64Stream.m +++ src/OFInflate64Stream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInflateStream.h ================================================================== --- src/OFInflateStream.h +++ src/OFInflateStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInflateStream.m ================================================================== --- src/OFInflateStream.m +++ src/OFInflateStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInvertedCharacterSet.h ================================================================== --- src/OFInvertedCharacterSet.h +++ src/OFInvertedCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInvertedCharacterSet.m ================================================================== --- src/OFInvertedCharacterSet.m +++ src/OFInvertedCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInvocation.h ================================================================== --- src/OFInvocation.h +++ src/OFInvocation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFInvocation.m ================================================================== --- src/OFInvocation.m +++ src/OFInvocation.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFJSONRepresentation.h ================================================================== --- src/OFJSONRepresentation.h +++ src/OFJSONRepresentation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFKernelEventObserver.m ================================================================== --- src/OFKernelEventObserver.m +++ src/OFKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -46,11 +46,13 @@ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfRangeException.h" #ifdef OF_AMIGAOS +# define Class IntuitionClass # include +# undef Class #endif @implementation OFKernelEventObserver @synthesize delegate = _delegate; #ifdef OF_AMIGAOS Index: src/OFKeyValueCoding.h ================================================================== --- src/OFKeyValueCoding.h +++ src/OFKeyValueCoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFKqueueKernelEventObserver.h ================================================================== --- src/OFKqueueKernelEventObserver.h +++ src/OFKqueueKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFKqueueKernelEventObserver.m ================================================================== --- src/OFKqueueKernelEventObserver.m +++ src/OFKqueueKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFLHAArchive.h ================================================================== --- src/OFLHAArchive.h +++ src/OFLHAArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,12 +18,12 @@ #import "OFLHAArchiveEntry.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN +@class OFIRI; @class OFStream; -@class OFURI; /** * @class OFLHAArchive OFLHAArchive.h ObjFW/OFLHAArchive.h * * @brief A class for accessing and manipulating LHA files. @@ -59,28 +59,28 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; /** * @brief Creates a new OFLHAArchive object with the specified file. * - * @param URI The URI to the LHA file + * @param IRI The IRI to the LHA file * @param mode The mode for the LHA file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return A new, autoreleased OFLHAArchive */ -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode; ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** - * @brief Creates a URI for accessing a the specified file within the specified - * LHA archive. + * @brief Creates an IRI for accessing a the specified file within the + * specified LHA archive. * * @param path The path of the file within the archive - * @param URI The URI of the archive - * @return A URI for accessing the specified file within the specified LHA + * @param IRI The IRI of the archive + * @return An IRI for accessing the specified file within the specified LHA * archive */ -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI; ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFLHAArchive object with the @@ -98,17 +98,17 @@ /** * @brief Initializes an already allocated OFLHAArchive object with the * specified file. * - * @param URI The URI to the LHA file + * @param IRI The IRI to the LHA file * @param mode The mode for the LHA file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return An initialized OFLHAArchive */ -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode; +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** * @brief Returns the next entry from the LHA archive or `nil` if all entries * have been read. * Index: src/OFLHAArchive.m ================================================================== --- src/OFLHAArchive.m +++ src/OFLHAArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,18 +20,18 @@ #include #import "OFLHAArchive.h" #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" -#import "OFArchiveURIHandler.h" +#import "OFArchiveIRIHandler.h" #import "OFCRC16.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFLHADecompressingStream.h" #import "OFSeekableStream.h" #import "OFStream.h" #import "OFString.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -86,18 +86,18 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode { - return [[[self alloc] initWithURI: URI mode: mode] autorelease]; + return [[[self alloc] initWithIRI: IRI mode: mode] autorelease]; } -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI { - return OFArchiveURIHandlerURIForFileInArchive(@"lha", path, URI); + return OFArchiveIRIHandlerIRIForFileInArchive(@"lha", path, IRI); } - (instancetype)init { OF_INVALID_INIT_METHOD @@ -134,20 +134,20 @@ } return self; } -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); OFStream *stream; @try { if ([mode isEqual: @"a"]) - stream = [OFURIHandler openItemAtURI: URI mode: @"r+"]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: @"r+"]; else - stream = [OFURIHandler openItemAtURI: URI mode: mode]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: mode]; } @catch (id e) { [self release]; @throw e; } @@ -173,10 +173,23 @@ char header[21]; size_t headerLen; if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; + + if (_currentEntry != nil && _lastReturnedStream == nil) { + /* + * No read stream was created since the last call to + * -[nextEntry]. Create it so that we can properly skip the + * data. + */ + void *pool = objc_autoreleasePoolPush(); + + [self streamForReadingCurrentEntry]; + + objc_autoreleasePoolPop(pool); + } [_currentEntry release]; _currentEntry = nil; [(OFLHAArchiveFileReadStream *)_lastReturnedStream of_skip]; @@ -200,11 +213,11 @@ headerLen += [_stream readIntoBuffer: header + headerLen length: 21 - headerLen]; } - _currentEntry= [[OFLHAArchiveEntry alloc] + _currentEntry = [[OFLHAArchiveEntry alloc] of_initWithHeader: header stream: _stream encoding: _encoding]; return _currentEntry; Index: src/OFLHAArchiveEntry+Private.h ================================================================== --- src/OFLHAArchiveEntry+Private.h +++ src/OFLHAArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFLHAArchiveEntry.h ================================================================== --- src/OFLHAArchiveEntry.h +++ src/OFLHAArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFLHAArchiveEntry.m ================================================================== --- src/OFLHAArchiveEntry.m +++ src/OFLHAArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFLHADecompressingStream.h ================================================================== --- src/OFLHADecompressingStream.h +++ src/OFLHADecompressingStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFLHADecompressingStream.m ================================================================== --- src/OFLHADecompressingStream.m +++ src/OFLHADecompressingStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,11 +14,10 @@ */ #import "OFObject.h" #import "OFCollection.h" #import "OFEnumerator.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -79,12 +78,11 @@ /** * @class OFList OFList.h ObjFW/OFList.h * * @brief A class which provides easy to use double-linked lists. */ -@interface OFList OF_GENERIC(ObjectType): OFObject +@interface OFList OF_GENERIC(ObjectType): OFObject #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif { OFListItem _Nullable _firstListItem; Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,10 @@ #include #import "OFList.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" @@ -67,39 +66,10 @@ + (instancetype)list { return [[[self alloc] init] autorelease]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [self init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - for (OFXMLElement *child in - [element elementsForNamespace: OFSerializationNS]) { - void *pool2 = objc_autoreleasePoolPush(); - - [self appendObject: child.objectByDeserializing]; - - objc_autoreleasePoolPop(pool2); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - - (void)dealloc { OFListItem next; for (OFListItem iter = _firstListItem; iter != NULL; iter = next) { @@ -371,28 +341,10 @@ [ret makeImmutable]; return ret; } -- (OFXMLElement *)XMLElementBySerializing -{ - OFXMLElement *element = - [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS]; - - for (OFListItem iter = _firstListItem; - iter != NULL; iter = iter->next) { - void *pool = objc_autoreleasePoolPush(); - - [element addChild: [iter->object XMLElementBySerializing]]; - - objc_autoreleasePoolPop(pool); - } - - return element; -} - - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { OFListItem listItem; Index: src/OFLocale.h ================================================================== --- src/OFLocale.h +++ src/OFLocale.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,10 +15,12 @@ #import "OFObject.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN + +@class OFIRI; /** @file */ /** * @def OF_LOCALIZED @@ -136,18 +138,16 @@ * * @return The decimal point of the system's locale */ + (nullable OFString *)decimalSeparator; -#ifdef OF_HAVE_FILES /** * @brief Adds a directory to scan for localizations. * - * @param path The path to the directory to scan for localizations + * @param IRI The IRI to the directory to scan for localizations */ -+ (void)addLocalizationDirectory: (OFString *)path; -#endif ++ (void)addLocalizationDirectoryIRI: (OFIRI *)IRI; /** * @brief Initializes the current OFLocale. * * @warning This sets the locale via `setlocale()`! @@ -157,18 +157,16 @@ * instance of OFLocale, which will become the current locale, and * call this method. */ - (instancetype)init; -#ifdef OF_HAVE_FILES /** * @brief Adds a directory to scan for localizations. * - * @param path The path to the directory to scan for localizations + * @param IRI The IRI to the directory to scan for localizations */ -- (void)addLocalizationDirectory: (OFString *)path; -#endif +- (void)addLocalizationDirectoryIRI: (OFIRI *)IRI; /** * @brief Returns the localized string for the specified ID, using the fallback * string if it cannot be looked up or is missing. * Index: src/OFLocale.m ================================================================== --- src/OFLocale.m +++ src/OFLocale.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,24 +16,27 @@ #include "config.h" #include #import "OFLocale.h" -#import "OFString.h" #import "OFArray.h" #import "OFDictionary.h" +#import "OFIRI.h" #import "OFNumber.h" +#import "OFString.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include # include +# undef Class #endif static OFLocale *currentLocale = nil; static OFDictionary *operatorPrecedences = nil; @@ -359,16 +362,14 @@ + (OFString *)decimalSeparator { return currentLocale.decimalSeparator; } -#ifdef OF_HAVE_FILES -+ (void)addLocalizationDirectory: (OFString *)path ++ (void)addLocalizationDirectoryIRI: (OFIRI *)IRI { - [currentLocale addLocalizationDirectory: path]; + [currentLocale addLocalizationDirectoryIRI: IRI]; } -#endif - (instancetype)init { self = [super init]; @@ -378,11 +379,15 @@ if (currentLocale != nil) @throw [OFInitializationFailedException exceptionWithClass: self.class]; +# ifdef OF_MSDOS + _encoding = OFStringEncodingCodepage437; +# else _encoding = OFStringEncodingUTF8; +# endif _decimalSeparator = @"."; _localizedStrings = [[OFMutableArray alloc] init]; if ((locale = setlocale(LC_ALL, "")) != NULL) _decimalSeparator = [[OFString alloc] @@ -492,25 +497,25 @@ [_localizedStrings release]; [super dealloc]; } -#ifdef OF_HAVE_FILES -- (void)addLocalizationDirectory: (OFString *)path +- (void)addLocalizationDirectoryIRI: (OFIRI *)IRI { void *pool; - OFString *mapPath, *languageCode, *countryCode, *localizationFile; + OFIRI *mapIRI, *localizationIRI; + OFString *languageCode, *countryCode, *localizationFile; OFDictionary *map; if (_languageCode == nil) return; pool = objc_autoreleasePoolPush(); - mapPath = [path stringByAppendingPathComponent: @"localizations.json"]; + mapIRI = [IRI IRIByAppendingPathComponent: @"localizations.json"]; @try { - map = [[OFString stringWithContentsOfFile: mapPath] + map = [[OFString stringWithContentsOfIRI: mapIRI] objectByParsingJSON]; } @catch (OFOpenItemFailedException *e) { objc_autoreleasePoolPop(pool); return; } @@ -530,19 +535,18 @@ if (localizationFile == nil) { objc_autoreleasePoolPop(pool); return; } - localizationFile = [path stringByAppendingPathComponent: + localizationIRI = [IRI IRIByAppendingPathComponent: [localizationFile stringByAppendingString: @".json"]]; - [_localizedStrings addObject: [[OFString stringWithContentsOfFile: - localizationFile] objectByParsingJSON]]; + [_localizedStrings addObject: [[OFString stringWithContentsOfIRI: + localizationIRI] objectByParsingJSON]]; objc_autoreleasePoolPop(pool); } -#endif - (OFString *)localizedStringForID: (OFConstantString *)ID fallback: (id)fallback, ... { OFString *ret; Index: src/OFLocking.h ================================================================== --- src/OFLocking.h +++ src/OFLocking.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMD5Hash.h ================================================================== --- src/OFMD5Hash.h +++ src/OFMD5Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMD5Hash.m ================================================================== --- src/OFMD5Hash.m +++ src/OFMD5Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTable+Private.h ================================================================== --- src/OFMapTable+Private.h +++ src/OFMapTable+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTable.h ================================================================== --- src/OFMapTable.h +++ src/OFMapTable.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTable.m ================================================================== --- src/OFMapTable.m +++ src/OFMapTable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTableDictionary.h ================================================================== --- src/OFMapTableDictionary.h +++ src/OFMapTableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTableDictionary.m ================================================================== --- src/OFMapTableDictionary.m +++ src/OFMapTableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,11 +19,10 @@ #import "OFArray.h" #import "OFMapTable+Private.h" #import "OFMapTable.h" #import "OFMutableMapTableDictionary.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -225,63 +224,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - OFArray *keys, *objects; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFXMLElement *keyElement, *objectElement; - - keys = [element elementsForName: @"key" - namespace: OFSerializationNS]; - objects = [element elementsForName: @"object" - namespace: OFSerializationNS]; - - if (keys.count != objects.count) - @throw [OFInvalidFormatException exception]; - - _mapTable = [[OFMapTable alloc] - initWithKeyFunctions: keyFunctions - objectFunctions: objectFunctions - capacity: keys.count]; - - keyEnumerator = [keys objectEnumerator]; - objectEnumerator = [objects objectEnumerator]; - while ((keyElement = [keyEnumerator nextObject]) != nil && - (objectElement = [objectEnumerator nextObject]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); - OFXMLElement *key, *object; - - key = [keyElement elementsForNamespace: - OFSerializationNS].firstObject; - object = [objectElement elementsForNamespace: - OFSerializationNS].firstObject; - - if (key == nil || object == nil) - @throw [OFInvalidFormatException exception]; - - [_mapTable setObject: object.objectByDeserializing - forKey: key.objectByDeserializing]; - - objc_autoreleasePoolPop(pool2); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { Index: src/OFMapTableSet.h ================================================================== --- src/OFMapTableSet.h +++ src/OFMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMapTableSet.m ================================================================== --- src/OFMapTableSet.m +++ src/OFMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,10 @@ #import "OFCountedMapTableSet.h" #import "OFMapTable.h" #import "OFMapTable+Private.h" #import "OFMutableMapTableSet.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFEnumerationMutationException.h" static void * @@ -176,41 +175,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [self init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if ((![element.name isEqual: @"OFSet"] && - ![element.name isEqual: @"OFMutableSet"]) || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - for (OFXMLElement *child in - [element elementsForNamespace: OFSerializationNS]) { - void *pool2 = objc_autoreleasePoolPush(); - - [_mapTable setObject: (void *)1 - forKey: [child objectByDeserializing]]; - - objc_autoreleasePoolPop(pool2); - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { ADDED src/OFMatrix4x4.h Index: src/OFMatrix4x4.h ================================================================== --- src/OFMatrix4x4.h +++ src/OFMatrix4x4.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @brief A 4x4 matrix of floats. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFMatrix4x4: OFObject +{ + float _values[4][4]; +} + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (readonly, class) OFMatrix4x4 *identityMatrix; +#endif + +/** + * @brief A 2D array of the 4x4 floats of the matrix in row-major format. + * + * These may be modified directly. + */ +@property (readonly, nonatomic) float (*values)[4]; + +/** + * @brief Returns the 4x4 identity matrix. + */ ++ (OFMatrix4x4 *)identityMatrix; + +/** + * @brief Creates a new 4x4 matrix with the specified values. + * + * @param values A 2D array of 4x4 floats in row-major format + * @return A new, autoreleased OFMatrix4x4 + */ ++ (instancetype)matrixWithValues: (const float [_Nonnull 4][4])values; + +/** + * @brief Initializes an already allocated 4x4 matrix with the specified values. + * + * @param values A 2D array of 4x4 floats in row-major format + * @return An initialized OFMatrix4x4 + */ +- (instancetype)initWithValues: (const float [_Nonnull 4][4])values; + +/** + * @brief Mulitplies the receiver with the specified matrix on the left side + * and the receiver on the right side. + * + * @param matrix The matrix to multiply the receiver with + */ +- (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix; + +/** + * @brief Translates the matrix with the specified vector. + * + * @param vector The vector to translate the matrix with + */ +- (void)translateWithVector: (OFVector3D)vector; + +/** + * @brief Scales the matrix with the specified vector. + * + * @param vector The vector to scale the matrix with + */ +- (void)scaleWithVector: (OFVector3D)vector; + +/** + * @brief Transforms the specified vector according to the matrix. + * + * @param vector The vector to transform + * @return The transformed vector + */ +- (OFVector4D)transformedVector: (OFVector4D)vector; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFMatrix4x4.m Index: src/OFMatrix4x4.m ================================================================== --- src/OFMatrix4x4.m +++ src/OFMatrix4x4.m @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMatrix4x4.h" +#import "OFOnce.h" +#import "OFString.h" + +static const float identityValues[4][4] = { + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } +}; + +@implementation OFMatrix4x4 ++ (OFMatrix4x4 *)identityMatrix +{ + return [[[OFMatrix4x4 alloc] + initWithValues: identityValues] autorelease]; +} + ++ (instancetype)matrixWithValues: (const float [4][4])values +{ + return [[[self alloc] initWithValues: values] autorelease]; +} + +- (instancetype)initWithValues: (const float [4][4])values +{ + self = [super init]; + + memcpy(_values, values, sizeof(_values)); + + return self; +} + +- (float (*)[4])values +{ + return _values; +} + +- (instancetype)copy +{ + return [[OFMatrix4x4 alloc] + initWithValues: (const float (*)[4])_values]; +} + +- (bool)isEqual: (OFMatrix4x4 *)matrix +{ + if (![matrix isKindOfClass: [OFMatrix4x4 class]]) + return false; + + return (memcmp(_values, matrix->_values, sizeof(_values)) == 0); +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + for (uint_fast8_t i = 0; i < 4; i++) + for (uint_fast8_t j = 0; j < 4; j++) + OFHashAddHash(&hash, OFFloatToRawUInt32(_values[i][j])); + + OFHashFinalize(&hash); + + return hash; +} + +- (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix +{ + float right[4][4]; + memcpy(right, _values, sizeof(right)); + +#define left matrix->_values + _values[0][0] = left[0][0] * right[0][0] + left[0][1] * right[1][0] + + left[0][2] * right[2][0] + left[0][3] * right[3][0]; + _values[0][1] = left[0][0] * right[0][1] + left[0][1] * right[1][1] + + left[0][2] * right[2][1] + left[0][3] * right[3][1]; + _values[0][2] = left[0][0] * right[0][2] + left[0][1] * right[1][2] + + left[0][2] * right[2][2] + left[0][3] * right[3][2]; + _values[0][3] = left[0][0] * right[0][3] + left[0][1] * right[1][3] + + left[0][2] * right[2][3] + left[0][3] * right[3][3]; + + _values[1][0] = left[1][0] * right[0][0] + left[1][1] * right[1][0] + + left[1][2] * right[2][0] + left[1][3] * right[3][0]; + _values[1][1] = left[1][0] * right[0][1] + left[1][1] * right[1][1] + + left[1][2] * right[2][1] + left[1][3] * right[3][1]; + _values[1][2] = left[1][0] * right[0][2] + left[1][1] * right[1][2] + + left[1][2] * right[2][2] + left[1][3] * right[3][2]; + _values[1][3] = left[1][0] * right[0][3] + left[1][1] * right[1][3] + + left[1][2] * right[2][3] + left[1][3] * right[3][3]; + + _values[2][0] = left[2][0] * right[0][0] + left[2][1] * right[1][0] + + left[2][2] * right[2][0] + left[2][3] * right[3][0]; + _values[2][1] = left[2][0] * right[0][1] + left[2][1] * right[1][1] + + left[2][2] * right[2][1] + left[2][3] * right[3][1]; + _values[2][2] = left[2][0] * right[0][2] + left[2][1] * right[1][2] + + left[2][2] * right[2][2] + left[2][3] * right[3][2]; + _values[2][3] = left[2][0] * right[0][3] + left[2][1] * right[1][3] + + left[2][2] * right[2][3] + left[2][3] * right[3][3]; + + _values[3][0] = left[3][0] * right[0][0] + left[3][1] * right[1][0] + + left[3][2] * right[2][0] + left[3][3] * right[3][0]; + _values[3][1] = left[3][0] * right[0][1] + left[3][1] * right[1][1] + + left[3][2] * right[2][1] + left[3][3] * right[3][1]; + _values[3][2] = left[3][0] * right[0][2] + left[3][1] * right[1][2] + + left[3][2] * right[2][2] + left[3][3] * right[3][2]; + _values[3][3] = left[3][0] * right[0][3] + left[3][1] * right[1][3] + + left[3][2] * right[2][3] + left[3][3] * right[3][3]; +#undef left +} + +- (void)translateWithVector: (OFVector3D)vector +{ + OFMatrix4x4 *translation = [[OFMatrix4x4 alloc] initWithValues: + (const float [4][4]){ + { 1, 0, 0, vector.x }, + { 0, 1, 0, vector.y }, + { 0, 0, 1, vector.z }, + { 0, 0, 0, 1 } + }]; + [self multiplyWithMatrix: translation]; + [translation release]; +} + +- (void)scaleWithVector: (OFVector3D)vector +{ + OFMatrix4x4 *scale = [[OFMatrix4x4 alloc] initWithValues: + (const float [4][4]){ + { vector.x, 0, 0, 0 }, + { 0, vector.y, 0, 0 }, + { 0, 0, vector.z, 0 }, + { 0, 0, 0, 1 } + }]; + [self multiplyWithMatrix: scale]; + [scale release]; +} + +- (OFVector4D)transformedVector: (OFVector4D)vector +{ + return OFMakeVector4D( + _values[0][0] * vector.x + _values[0][1] * vector.y + + _values[0][2] * vector.z + _values[0][3] * vector.w, + _values[1][0] * vector.x + _values[1][1] * vector.y + + _values[1][2] * vector.z + _values[1][3] * vector.w, + _values[2][0] * vector.x + _values[2][1] * vector.y + + _values[2][2] * vector.z + _values[2][3] * vector.w, + _values[3][0] * vector.x + _values[3][1] * vector.y + + _values[3][2] * vector.z + _values[3][3] * vector.w); +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"", + _values[0][0], _values[0][1], _values[0][2], _values[0][3], + _values[1][0], _values[1][1], _values[1][2], _values[1][3], + _values[2][0], _values[2][1], _values[2][2], _values[2][3], + _values[3][0], _values[3][1], _values[3][2], _values[3][3]]; +} +@end Index: src/OFMemoryStream.h ================================================================== --- src/OFMemoryStream.h +++ src/OFMemoryStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMemoryStream.m ================================================================== --- src/OFMemoryStream.m +++ src/OFMemoryStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMessagePackExtension.h ================================================================== --- src/OFMessagePackExtension.h +++ src/OFMessagePackExtension.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMessagePackExtension.m ================================================================== --- src/OFMessagePackExtension.m +++ src/OFMessagePackExtension.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMessagePackRepresentation.h ================================================================== --- src/OFMessagePackRepresentation.h +++ src/OFMessagePackRepresentation.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMethodSignature.h ================================================================== --- src/OFMethodSignature.h +++ src/OFMethodSignature.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMethodSignature.m ================================================================== --- src/OFMethodSignature.m +++ src/OFMethodSignature.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -144,11 +144,12 @@ return alignment; } static size_t -#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 7 +#if defined(__clang__) && __has_attribute(__optnone__) && \ + __clang_major__ == 3 && __clang_minor__ <= 7 /* Work around an ICE in Clang 3.7.0 on Windows/x86 */ __attribute__((__optnone__)) #endif alignmentOfEncoding(const char **type, size_t *length, bool inStruct) { @@ -438,10 +439,15 @@ return size; } static size_t +#if defined(__clang__) && __has_attribute(__optnone__) && \ + __clang_major__ == 3 && __clang_minor__ <= 7 +/* Work around an ICE in Clang 3.7.0 on Windows/x86 */ +__attribute__((__optnone__)) +#endif sizeOfEncoding(const char **type, size_t *length) { size_t size; if (*length == 0) Index: src/OFMutableAdjacentArray.h ================================================================== --- src/OFMutableAdjacentArray.h +++ src/OFMutableAdjacentArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableAdjacentArray.m ================================================================== --- src/OFMutableAdjacentArray.m +++ src/OFMutableAdjacentArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableArchiveEntry.h ================================================================== --- src/OFMutableArchiveEntry.h +++ src/OFMutableArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableArray.h ================================================================== --- src/OFMutableArray.h +++ src/OFMutableArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -200,10 +200,21 @@ * should be the same as that of -[compare:]. * @param options The options to use when sorting the array */ - (void)sortUsingSelector: (SEL)selector options: (OFArraySortOptions)options; +/** + * @brief Sorts the array using the specified function and options. + * + * @param compare The function to use to sort the array + * @param context Context passed to the function to compare + * @param options The options to use when sorting the array + */ +- (void)sortUsingFunction: (OFCompareFunction)compare + context: (nullable void *)context + options: (OFArraySortOptions)options; + #ifdef OF_HAVE_BLOCKS /** * @brief Sorts the array using the specified comparator and options. * * @param comparator The comparator to use to sort the array Index: src/OFMutableArray.m ================================================================== --- src/OFMutableArray.m +++ src/OFMutableArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -30,23 +30,13 @@ } placeholder; @interface OFMutableArrayPlaceholder: OFMutableArray @end -static OFComparisonResult -compare(id left, id right, SEL selector) -{ - OFComparisonResult (*comparator)(id, SEL, id) = - (OFComparisonResult (*)(id, SEL, id)) - [left methodForSelector: selector]; - - return comparator(left, selector, right); -} - static void -quicksort(OFMutableArray *array, size_t left, size_t right, SEL selector, - OFArraySortOptions options) +quicksort(OFMutableArray *array, size_t left, size_t right, + OFCompareFunction compare, void *context, OFArraySortOptions options) { OFComparisonResult ascending, descending; if (options & OFArraySortDescending) { ascending = OFOrderedDescending; @@ -61,80 +51,34 @@ size_t j = right - 1; id pivot = [array objectAtIndex: right]; do { while (compare([array objectAtIndex: i], pivot, - selector) != descending && i < right) + context) != descending && i < right) i++; while (compare([array objectAtIndex: j], pivot, - selector) != ascending && j > left) + context) != ascending && j > left) j--; if (i < j) [array exchangeObjectAtIndex: i withObjectAtIndex: j]; } while (i < j); - if (compare([array objectAtIndex: i], pivot, selector) == + if (compare([array objectAtIndex: i], pivot, context) == descending) [array exchangeObjectAtIndex: i withObjectAtIndex: right]; if (i > 0) - quicksort(array, left, i - 1, selector, options); - - left = i + 1; - } -} - -#ifdef OF_HAVE_BLOCKS -static void -quicksortWithBlock(OFMutableArray *array, size_t left, size_t right, - OFComparator comparator, OFArraySortOptions options) -{ - OFComparisonResult ascending, descending; - - if (options & OFArraySortDescending) { - ascending = OFOrderedDescending; - descending = OFOrderedAscending; - } else { - ascending = OFOrderedAscending; - descending = OFOrderedDescending; - } - - while (left < right) { - size_t i = left; - size_t j = right - 1; - id pivot = [array objectAtIndex: right]; - - do { - while (comparator([array objectAtIndex: i], pivot) != - descending && i < right) - i++; - - while (comparator([array objectAtIndex: j], pivot) != - ascending && j > left) - j--; - - if (i < j) - [array exchangeObjectAtIndex: i - withObjectAtIndex: j]; - } while (i < j); - - if (comparator([array objectAtIndex: i], pivot) == descending) - [array exchangeObjectAtIndex: i - withObjectAtIndex: right]; - - if (i > 0) - quicksortWithBlock(array, left, i - 1, comparator, + quicksort(array, left, i - 1, compare, context, options); left = i + 1; } } -#endif @implementation OFMutableArrayPlaceholder - (instancetype)init { return (id)[[OFMutableAdjacentArray alloc] init]; @@ -178,16 +122,10 @@ { return (id)[[OFMutableAdjacentArray alloc] initWithObjects: objects count: count]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMutableAdjacentArray alloc] - initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -411,32 +349,64 @@ - (void)sort { [self sortUsingSelector: @selector(compare:) options: 0]; } + +static OFComparisonResult +selectorCompare(id left, id right, void *context) +{ + SEL selector = context; + OFComparisonResult (*comparator)(id, SEL, id) = + (OFComparisonResult (*)(id, SEL, id)) + [left methodForSelector: selector]; + + return comparator(left, selector, right); +} - (void)sortUsingSelector: (SEL)selector options: (OFArraySortOptions)options { size_t count = self.count; if (count == 0 || count == 1) return; - quicksort(self, 0, count - 1, selector, options); + quicksort(self, 0, count - 1, selectorCompare, (void *)selector, + options); +} + +- (void)sortUsingFunction: (OFCompareFunction)compare + context: (void *)context + options: (OFArraySortOptions)options +{ + size_t count = self.count; + + if (count == 0 || count == 1) + return; + + quicksort(self, 0, count - 1, compare, context, options); } #ifdef OF_HAVE_BLOCKS +static OFComparisonResult +blockCompare(id left, id right, void *context) +{ + OFComparator block = (OFComparator)context; + + return block(left, right); +} + - (void)sortUsingComparator: (OFComparator)comparator options: (OFArraySortOptions)options { size_t count = self.count; if (count == 0 || count == 1) return; - quicksortWithBlock(self, 0, count - 1, comparator, options); + quicksort(self, 0, count - 1, blockCompare, comparator, options); } #endif - (void)reverse { Index: src/OFMutableData.h ================================================================== --- src/OFMutableData.h +++ src/OFMutableData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,10 @@ #import "OFData.h" OF_ASSUME_NONNULL_BEGIN @class OFString; -@class OFURI; /** * @class OFMutableData OFMutableData.h ObjFW/OFMutableData.h * * @brief A class for storing and manipulating arbitrary data in an array. Index: src/OFMutableData.m ================================================================== --- src/OFMutableData.m +++ src/OFMutableData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableDictionary.h ================================================================== --- src/OFMutableDictionary.h +++ src/OFMutableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableDictionary.m ================================================================== --- src/OFMutableDictionary.m +++ src/OFMutableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -78,16 +78,10 @@ { return (id)[[OFMutableMapTableDictionary alloc] initWithKey: firstKey arguments: arguments]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMutableMapTableDictionary alloc] - initWithSerialization: element]; -} - - (instancetype)initWithCapacity: (size_t)capacity { return (id)[[OFMutableMapTableDictionary alloc] initWithCapacity: capacity]; } ADDED src/OFMutableIRI.h Index: src/OFMutableIRI.h ================================================================== --- src/OFMutableIRI.h +++ src/OFMutableIRI.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFIRI.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFMutableIRI OFMutableIRI.h ObjFW/OFMutableIRI.h + * + * @brief A class for representing IRIs, URIs, URLs and URNs, for parsing them, + * accessing parts of them as well as modifying them. + * + * This class follows RFC 3976 and RFC 3987. + */ +@interface OFMutableIRI: OFIRI +{ + OF_RESERVE_IVARS(OFMutableIRI, 4) +} + +/** + * @brief The scheme part of the IRI. + * + * @throw OFInvalidFormatException The scheme being set is not in the correct + * format + */ +@property (readwrite, copy, nonatomic) OFString *scheme; + +/** + * @brief The host part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *host; + +/** + * @brief The host part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The host being set is not in the correct + * format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *percentEncodedHost; + +/** + * @brief The port part of the IRI. + * + * @throw OFInvalidArgumentException The port is not valid (e.g. negative or + * too big) + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFNumber *port; + +/** + * @brief The user part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *user; + +/** + * @brief The user part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The user being set is not in the correct + * format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *percentEncodedUser; + +/** + * @brief The password part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *password; + +/** + * @brief The password part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The password being set is not in the correct + * format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *percentEncodedPassword; + +/** + * @brief The path part of the IRI. + */ +@property (readwrite, copy, nonatomic) OFString *path; + +/** + * @brief The path part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The path being set is not in the correct + * format + */ +@property (readwrite, copy, nonatomic) OFString *percentEncodedPath; + +/** + * @brief The path of the IRI split into components. + * + * The first component must always be empty to designate the root. + * + * @throw OFInvalidFormatException The path components being set are not in the + * correct format + */ +@property (readwrite, copy, nonatomic) + OFArray OF_GENERIC(OFString *) *pathComponents; + +/** + * @brief The query part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *query; + +/** + * @brief The query part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The query being set is not in the correct + * format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *percentEncodedQuery; + +/** + * @brief The query part of the IRI as an array. + * + * For example, a query like `key1=value1&key2=value2` would correspond to the + * following array: + * + * @[ + * [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"], + * [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"], + * ] + * + * @throw OFInvalidFormatException The query is not in the correct format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems; + +/** + * @brief The fragment part of the IRI. + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *fragment; + +/** + * @brief The fragment part of the IRI in percent-encoded form. + * + * Setting this retains the original percent-encoding used - if more characters + * than necessary are percent-encoded, it is kept this way. + * + * @throw OFInvalidFormatException The fragment being set is not in the correct + * format + */ +@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) + OFString *percentEncodedFragment; + +/** + * @brief Creates a new mutable IRI with the specified schemed. + * + * @param scheme The scheme for the IRI + * @return A new, autoreleased OFMutableIRI + */ ++ (instancetype)IRIWithScheme: (OFString *)scheme; + +/** + * @brief Initializes an already allocated mutable IRI with the specified + * schemed. + * + * @param scheme The scheme for the IRI + * @return An initialized OFMutableIRI + */ +- (instancetype)initWithScheme: (OFString *)scheme; + +/** + * @brief Appends the specified path component. + * + * @param component The component to append + */ +- (void)appendPathComponent: (OFString *)component; + +/** + * @brief Appends the specified path component. + * + * @param component The component to append + * @param isDirectory Whether the path is a directory, in which case a slash is + * appened if there is no slash yet + */ +- (void)appendPathComponent: (OFString *)component + isDirectory: (bool)isDirectory; + +/** + * @brief Resolves relative subpaths. + */ +- (void)standardizePath; + +/** + * @brief Converts the mutable IRI to an immutable IRI. + */ +- (void)makeImmutable; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFMutableIRI.m Index: src/OFMutableIRI.m ================================================================== --- src/OFMutableIRI.m +++ src/OFMutableIRI.m @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMutableIRI.h" +#import "OFIRI+Private.h" +#import "OFArray.h" +#import "OFDictionary.h" +#ifdef OF_HAVE_FILES +# import "OFFileManager.h" +#endif +#import "OFNumber.h" +#import "OFPair.h" +#import "OFString.h" + +#import "OFInvalidArgumentException.h" +#import "OFInvalidFormatException.h" + +@implementation OFMutableIRI +@dynamic scheme, host, percentEncodedHost, port, user, percentEncodedUser; +@dynamic password, percentEncodedPassword, path, percentEncodedPath; +@dynamic pathComponents, query, percentEncodedQuery, queryItems, fragment; +@dynamic percentEncodedFragment; + ++ (instancetype)IRIWithScheme: (OFString *)scheme +{ + return [[[self alloc] initWithScheme: scheme] autorelease]; +} + +- (instancetype)initWithScheme: (OFString *)scheme +{ + self = [super of_init]; + + @try { + self.scheme = scheme; + _percentEncodedPath = @""; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)setScheme: (OFString *)scheme +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _scheme; + + if (scheme.length < 1 || !OFASCIIIsAlpha(*scheme.UTF8String)) + @throw [OFInvalidFormatException exception]; + + OFIRIVerifyIsEscaped(scheme, + [OFCharacterSet IRISchemeAllowedCharacterSet], false); + + _scheme = [scheme.lowercaseString copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setHost: (OFString *)host +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedHost; + + if (OFIRIIsIPv6Host(host)) + _percentEncodedHost = [[OFString alloc] + initWithFormat: @"[%@]", host]; + else + _percentEncodedHost = [[host + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIHostAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedHost: (OFString *)percentEncodedHost +{ + OFString *old; + + if ([percentEncodedHost hasPrefix: @"["] && + [percentEncodedHost hasSuffix: @"]"]) { + if (!OFIRIIsIPv6Host([percentEncodedHost substringWithRange: + OFMakeRange(1, percentEncodedHost.length - 2)])) + @throw [OFInvalidFormatException exception]; + } else if (percentEncodedHost != nil) + OFIRIVerifyIsEscaped(percentEncodedHost, + [OFCharacterSet IRIHostAllowedCharacterSet], true); + + old = _percentEncodedHost; + _percentEncodedHost = [percentEncodedHost copy]; + [old release]; +} + +- (void)setPort: (OFNumber *)port +{ + OFNumber *old = _port; + + if (port.longLongValue < 0 || port.longLongValue > 65535) + @throw [OFInvalidArgumentException exception]; + + _port = [port copy]; + [old release]; +} + +- (void)setUser: (OFString *)user +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedUser; + + _percentEncodedUser = [[user + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIUserAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedUser: (OFString *)percentEncodedUser +{ + OFString *old; + + if (percentEncodedUser != nil) + OFIRIVerifyIsEscaped(percentEncodedUser, + [OFCharacterSet IRIUserAllowedCharacterSet], true); + + old = _percentEncodedUser; + _percentEncodedUser = [percentEncodedUser copy]; + [old release]; +} + +- (void)setPassword: (OFString *)password +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedPassword; + + _percentEncodedPassword = [[password + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIPasswordAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedPassword: (OFString *)percentEncodedPassword +{ + OFString *old; + + if (percentEncodedPassword != nil) + OFIRIVerifyIsEscaped(percentEncodedPassword, + [OFCharacterSet IRIPasswordAllowedCharacterSet], true); + + old = _percentEncodedPassword; + _percentEncodedPassword = [percentEncodedPassword copy]; + [old release]; +} + +- (void)setPath: (OFString *)path +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedPath; + + _percentEncodedPath = [[path + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIPathAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedPath: (OFString *)percentEncodedPath +{ + OFString *old; + + OFIRIVerifyIsEscaped(percentEncodedPath, + [OFCharacterSet IRIPathAllowedCharacterSet], true); + + old = _percentEncodedPath; + _percentEncodedPath = [percentEncodedPath copy]; + [old release]; +} + +- (void)setPathComponents: (OFArray *)components +{ + void *pool = objc_autoreleasePoolPush(); + + if (components.count == 0) + @throw [OFInvalidFormatException exception]; + + if ([components.firstObject isEqual: @"/"]) { + OFMutableArray *mutComponents = + [[components mutableCopy] autorelease]; + [mutComponents replaceObjectAtIndex: 0 withObject: @""]; + components = mutComponents; + } + + self.path = [components componentsJoinedByString: @"/"]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setQuery: (OFString *)query +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedQuery; + + _percentEncodedQuery = [[query + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIQueryAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedQuery: (OFString *)percentEncodedQuery +{ + OFString *old; + + if (percentEncodedQuery != nil) + OFIRIVerifyIsEscaped(percentEncodedQuery, + [OFCharacterSet IRIQueryAllowedCharacterSet], true); + + old = _percentEncodedQuery; + _percentEncodedQuery = [percentEncodedQuery copy]; + [old release]; +} + +- (void)setQueryItems: + (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *) + queryItems +{ + void *pool; + OFMutableString *percentEncodedQuery; + OFCharacterSet *characterSet; + OFString *old; + + if (queryItems == nil) { + [_percentEncodedQuery release]; + _percentEncodedQuery = nil; + return; + } + + pool = objc_autoreleasePoolPush(); + percentEncodedQuery = [OFMutableString string]; + characterSet = [OFCharacterSet IRIQueryKeyValueAllowedCharacterSet]; + + for (OFPair OF_GENERIC(OFString *, OFString *) *item in queryItems) { + OFString *key = [item.firstObject + stringByAddingPercentEncodingWithAllowedCharacters: + characterSet]; + OFString *value = [item.secondObject + stringByAddingPercentEncodingWithAllowedCharacters: + characterSet]; + + if (percentEncodedQuery.length > 0) + [percentEncodedQuery appendString: @"&"]; + + [percentEncodedQuery appendFormat: @"%@=%@", key, value]; + } + + old = _percentEncodedQuery; + _percentEncodedQuery = [percentEncodedQuery copy]; + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setFragment: (OFString *)fragment +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old = _percentEncodedFragment; + + _percentEncodedFragment = [[fragment + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIFragmentAllowedCharacterSet]] copy]; + + [old release]; + + objc_autoreleasePoolPop(pool); +} + +- (void)setPercentEncodedFragment: (OFString *)percentEncodedFragment +{ + OFString *old; + + if (percentEncodedFragment != nil) + OFIRIVerifyIsEscaped(percentEncodedFragment, + [OFCharacterSet IRIFragmentAllowedCharacterSet], true); + + old = _percentEncodedFragment; + _percentEncodedFragment = [percentEncodedFragment copy]; + [old release]; +} + +- (id)copy +{ + OFMutableIRI *copy = [self mutableCopy]; + + [copy makeImmutable]; + + return copy; +} + +- (void)appendPathComponent: (OFString *)component +{ + [self appendPathComponent: component isDirectory: false]; + +#ifdef OF_HAVE_FILES + if ([_scheme isEqual: @"file"] && + ![_percentEncodedPath hasSuffix: @"/"] && + [[OFFileManager defaultManager] directoryExistsAtIRI: self]) { + void *pool = objc_autoreleasePoolPush(); + OFString *path = [_percentEncodedPath + stringByAppendingString: @"/"]; + + [_percentEncodedPath release]; + _percentEncodedPath = [path retain]; + + objc_autoreleasePoolPop(pool); + } +#endif +} + +- (void)appendPathComponent: (OFString *)component + isDirectory: (bool)isDirectory +{ + void *pool; + OFString *path; + + if ([component isEqual: @"/"] && [_percentEncodedPath hasSuffix: @"/"]) + return; + + pool = objc_autoreleasePoolPush(); + component = [component + stringByAddingPercentEncodingWithAllowedCharacters: + [OFCharacterSet IRIPathAllowedCharacterSet]]; + +#if defined(OF_WINDOWS) || defined(OF_MSDOS) + if ([_percentEncodedPath hasSuffix: @"/"] || + ([_scheme isEqual: @"file"] && + [_percentEncodedPath hasSuffix: @":"])) +#else + if ([_percentEncodedPath hasSuffix: @"/"]) +#endif + path = [_percentEncodedPath stringByAppendingString: component]; + else + path = [_percentEncodedPath + stringByAppendingFormat: @"/%@", component]; + + if (isDirectory && ![path hasSuffix: @"/"]) + path = [path stringByAppendingString: @"/"]; + + [_percentEncodedPath release]; + _percentEncodedPath = [path retain]; + + objc_autoreleasePoolPop(pool); +} + +- (void)standardizePath +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableArray OF_GENERIC(OFString *) *array; + bool done = false, startsWithEmpty, endsWithEmpty; + OFString *path; + + array = [[[_percentEncodedPath + componentsSeparatedByString: @"/"] mutableCopy] autorelease]; + + endsWithEmpty = ([array.lastObject length] == 0); + startsWithEmpty = ([array.firstObject length] == 0); + + while (!done) { + size_t length = array.count; + + done = true; + + for (size_t i = 0; i < length; i++) { + OFString *current = [array objectAtIndex: i]; + OFString *parent = + (i > 0 ? [array objectAtIndex: i - 1] : nil); + + if ([current isEqual: @"."] || current.length == 0) { + [array removeObjectAtIndex: i]; + + done = false; + break; + } + + if ([current isEqual: @".."] && parent != nil && + ![parent isEqual: @".."]) { + [array removeObjectsInRange: + OFMakeRange(i - 1, 2)]; + + done = false; + break; + } + } + } + + if (startsWithEmpty) + [array insertObject: @"" atIndex: 0]; + if (endsWithEmpty) + [array addObject: @""]; + + path = [array componentsJoinedByString: @"/"]; + if (startsWithEmpty && path.length == 0) + path = @"/"; + + self.percentEncodedPath = path; + + objc_autoreleasePoolPop(pool); +} + +- (void)makeImmutable +{ + object_setClass(self, [OFIRI class]); +} +@end Index: src/OFMutableLHAArchiveEntry.h ================================================================== --- src/OFMutableLHAArchiveEntry.h +++ src/OFMutableLHAArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableLHAArchiveEntry.m ================================================================== --- src/OFMutableLHAArchiveEntry.m +++ src/OFMutableLHAArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableMapTableDictionary.h ================================================================== --- src/OFMutableMapTableDictionary.h +++ src/OFMutableMapTableDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableMapTableDictionary.m ================================================================== --- src/OFMutableMapTableDictionary.m +++ src/OFMutableMapTableDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableMapTableSet.h ================================================================== --- src/OFMutableMapTableSet.h +++ src/OFMutableMapTableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableMapTableSet.m ================================================================== --- src/OFMutableMapTableSet.m +++ src/OFMutableMapTableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutablePair.h ================================================================== --- src/OFMutablePair.h +++ src/OFMutablePair.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutablePair.m ================================================================== --- src/OFMutablePair.m +++ src/OFMutablePair.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableSet.h ================================================================== --- src/OFMutableSet.h +++ src/OFMutableSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableSet.m ================================================================== --- src/OFMutableSet.m +++ src/OFMutableSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -67,16 +67,10 @@ { return (id)[[OFMutableMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMutableMapTableSet alloc] - initWithSerialization: element]; -} - - (instancetype)initWithCapacity: (size_t)capacity { return (id)[[OFMutableMapTableSet alloc] initWithCapacity: capacity]; } Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -172,28 +172,23 @@ initWithContentsOfFile: path encoding: encoding]; } #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI { - return (id)[[OFMutableUTF8String alloc] initWithContentsOfURI: URI]; + return (id)[[OFMutableUTF8String alloc] initWithContentsOfIRI: IRI]; } -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { return (id)[[OFMutableUTF8String alloc] - initWithContentsOfURI: URI + initWithContentsOfIRI: IRI encoding: encoding]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMutableUTF8String alloc] initWithSerialization: element]; -} - - (instancetype)retain { return self; } Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableTriple.h ================================================================== --- src/OFMutableTriple.h +++ src/OFMutableTriple.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableTriple.m ================================================================== --- src/OFMutableTriple.m +++ src/OFMutableTriple.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/OFMutableURI.h Index: src/OFMutableURI.h ================================================================== --- src/OFMutableURI.h +++ src/OFMutableURI.h @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURI.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFMutableURI OFMutableURI.h ObjFW/OFMutableURI.h - * - * @brief A class for parsing URIs as per RFC 3986 and accessing and modifying - * parts of it. - */ -@interface OFMutableURI: OFURI -{ - OF_RESERVE_IVARS(OFMutableURI, 4) -} - -/** - * @brief The scheme part of the URI. - * - * @throw OFInvalidFormatException The scheme being set is not in the correct - * format - */ -@property (readwrite, copy, nonatomic) OFString *scheme; - -/** - * @brief The host part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *host; - -/** - * @brief The host part of the URI in percent-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The host being set is not in the correct - * format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *percentEncodedHost; - -/** - * @brief The port part of the URI. - * - * @throw OFInvalidArgumentException The port is not valid (e.g. negative or - * too big) - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFNumber *port; - -/** - * @brief The user part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *user; - -/** - * @brief The user part of the URI in percent-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The user being set is not in the correct - * format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *percentEncodedUser; - -/** - * @brief The password part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *password; - -/** - * @brief The password part of the URI in URI-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The password being set is not in the correct - * format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *percentEncodedPassword; - -/** - * @brief The path part of the URI. - */ -@property (readwrite, copy, nonatomic) OFString *path; - -/** - * @brief The path part of the URI in percent-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The path being set is not in the correct - * format - */ -@property (readwrite, copy, nonatomic) OFString *percentEncodedPath; - -/** - * @brief The path of the URI split into components. - * - * The first component must always be empty to designate the root. - * - * @throw OFInvalidFormatException The path components being set are not in the - * correct format - */ -@property (readwrite, copy, nonatomic) - OFArray OF_GENERIC(OFString *) *pathComponents; - -/** - * @brief The query part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *query; - -/** - * @brief The query part of the URI in percent-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The query being set is not in the correct - * format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *percentEncodedQuery; - -/** - * @brief The query part of the URI as an array. - * - * For example, a query like `key1=value1&key2=value2` would correspond to the - * following array: - * - * @[ - * [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"], - * [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"], - * ] - * - * @throw OFInvalidFormatException The query is not in the correct format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems; - -/** - * @brief The fragment part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *fragment; - -/** - * @brief The fragment part of the URI in percent-encoded form. - * - * Setting this retains the original percent-encoding used - if more characters - * than necessary are percent-encoded, it is kept this way. - * - * @throw OFInvalidFormatException The fragment being set is not in the correct - * format - */ -@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) - OFString *percentEncodedFragment; - -/** - * @brief Creates a new mutable URI with the specified schemed. - * - * @param scheme The scheme for the URI - * @return A new, autoreleased OFMutableURI - */ -+ (instancetype)URIWithScheme: (OFString *)scheme; - -/** - * @brief Initializes an already allocated mutable URI with the specified - * schemed. - * - * @param scheme The scheme for the URI - * @return An initialized OFMutableURI - */ -- (instancetype)initWithScheme: (OFString *)scheme; - -/** - * @brief Appends the specified path component. - * - * @param component The component to append - */ -- (void)appendPathComponent: (OFString *)component; - -/** - * @brief Appends the specified path component. - * - * @param component The component to append - * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet - */ -- (void)appendPathComponent: (OFString *)component - isDirectory: (bool)isDirectory; - -/** - * @brief Resolves relative subpaths. - */ -- (void)standardizePath; - -/** - * @brief Converts the mutable URI to an immutable URI. - */ -- (void)makeImmutable; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFMutableURI.m Index: src/OFMutableURI.m ================================================================== --- src/OFMutableURI.m +++ src/OFMutableURI.m @@ -1,439 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFMutableURI.h" -#import "OFURI+Private.h" -#import "OFArray.h" -#import "OFDictionary.h" -#ifdef OF_HAVE_FILES -# import "OFFileManager.h" -#endif -#import "OFNumber.h" -#import "OFPair.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" - -@implementation OFMutableURI -@dynamic scheme, host, percentEncodedHost, port, user, percentEncodedUser; -@dynamic password, percentEncodedPassword, path, percentEncodedPath; -@dynamic pathComponents, query, percentEncodedQuery, queryItems, fragment; -@dynamic percentEncodedFragment; - -+ (instancetype)URIWithScheme: (OFString *)scheme -{ - return [[[self alloc] initWithScheme: scheme] autorelease]; -} - -- (instancetype)initWithScheme: (OFString *)scheme -{ - self = [super of_init]; - - @try { - self.scheme = scheme; - _percentEncodedPath = @""; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)setScheme: (OFString *)scheme -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _scheme; - - if (scheme.length < 1 || !OFASCIIIsAlpha(*scheme.UTF8String)) - @throw [OFInvalidFormatException exception]; - - OFURIVerifyIsEscaped(scheme, - [OFCharacterSet URISchemeAllowedCharacterSet], false); - - _scheme = [scheme.lowercaseString copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setHost: (OFString *)host -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedHost; - - if (OFURIIsIPv6Host(host)) - _percentEncodedHost = [[OFString alloc] - initWithFormat: @"[%@]", host]; - else - _percentEncodedHost = [[host - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIHostAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedHost: (OFString *)percentEncodedHost -{ - OFString *old; - - if ([percentEncodedHost hasPrefix: @"["] && - [percentEncodedHost hasSuffix: @"]"]) { - if (!OFURIIsIPv6Host([percentEncodedHost substringWithRange: - OFMakeRange(1, percentEncodedHost.length - 2)])) - @throw [OFInvalidFormatException exception]; - } else if (percentEncodedHost != nil) - OFURIVerifyIsEscaped(percentEncodedHost, - [OFCharacterSet URIHostAllowedCharacterSet], true); - - old = _percentEncodedHost; - _percentEncodedHost = [percentEncodedHost copy]; - [old release]; -} - -- (void)setPort: (OFNumber *)port -{ - OFNumber *old = _port; - - if (port.longLongValue < 0 || port.longLongValue > 65535) - @throw [OFInvalidArgumentException exception]; - - _port = [port copy]; - [old release]; -} - -- (void)setUser: (OFString *)user -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedUser; - - _percentEncodedUser = [[user - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIUserAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedUser: (OFString *)percentEncodedUser -{ - OFString *old; - - if (percentEncodedUser != nil) - OFURIVerifyIsEscaped(percentEncodedUser, - [OFCharacterSet URIUserAllowedCharacterSet], true); - - old = _percentEncodedUser; - _percentEncodedUser = [percentEncodedUser copy]; - [old release]; -} - -- (void)setPassword: (OFString *)password -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedPassword; - - _percentEncodedPassword = [[password - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIPasswordAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedPassword: (OFString *)percentEncodedPassword -{ - OFString *old; - - if (percentEncodedPassword != nil) - OFURIVerifyIsEscaped(percentEncodedPassword, - [OFCharacterSet URIPasswordAllowedCharacterSet], true); - - old = _percentEncodedPassword; - _percentEncodedPassword = [percentEncodedPassword copy]; - [old release]; -} - -- (void)setPath: (OFString *)path -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedPath; - - _percentEncodedPath = [[path - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIPathAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedPath: (OFString *)percentEncodedPath -{ - OFString *old; - - OFURIVerifyIsEscaped(percentEncodedPath, - [OFCharacterSet URIPathAllowedCharacterSet], true); - - old = _percentEncodedPath; - _percentEncodedPath = [percentEncodedPath copy]; - [old release]; -} - -- (void)setPathComponents: (OFArray *)components -{ - void *pool = objc_autoreleasePoolPush(); - - if (components.count == 0) - @throw [OFInvalidFormatException exception]; - - if ([components.firstObject isEqual: @"/"]) { - OFMutableArray *mutComponents = - [[components mutableCopy] autorelease]; - [mutComponents replaceObjectAtIndex: 0 withObject: @""]; - components = mutComponents; - } - - self.path = [components componentsJoinedByString: @"/"]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setQuery: (OFString *)query -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedQuery; - - _percentEncodedQuery = [[query - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIQueryAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedQuery: (OFString *)percentEncodedQuery -{ - OFString *old; - - if (percentEncodedQuery != nil) - OFURIVerifyIsEscaped(percentEncodedQuery, - [OFCharacterSet URIQueryAllowedCharacterSet], true); - - old = _percentEncodedQuery; - _percentEncodedQuery = [percentEncodedQuery copy]; - [old release]; -} - -- (void)setQueryItems: - (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *) - queryItems -{ - void *pool; - OFMutableString *percentEncodedQuery; - OFCharacterSet *characterSet; - OFString *old; - - if (queryItems == nil) { - [_percentEncodedQuery release]; - _percentEncodedQuery = nil; - return; - } - - pool = objc_autoreleasePoolPush(); - percentEncodedQuery = [OFMutableString string]; - characterSet = [OFCharacterSet URIQueryKeyValueAllowedCharacterSet]; - - for (OFPair OF_GENERIC(OFString *, OFString *) *item in queryItems) { - OFString *key = [item.firstObject - stringByAddingPercentEncodingWithAllowedCharacters: - characterSet]; - OFString *value = [item.secondObject - stringByAddingPercentEncodingWithAllowedCharacters: - characterSet]; - - if (percentEncodedQuery.length > 0) - [percentEncodedQuery appendString: @"&"]; - - [percentEncodedQuery appendFormat: @"%@=%@", key, value]; - } - - old = _percentEncodedQuery; - _percentEncodedQuery = [percentEncodedQuery copy]; - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setFragment: (OFString *)fragment -{ - void *pool = objc_autoreleasePoolPush(); - OFString *old = _percentEncodedFragment; - - _percentEncodedFragment = [[fragment - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIFragmentAllowedCharacterSet]] copy]; - - [old release]; - - objc_autoreleasePoolPop(pool); -} - -- (void)setPercentEncodedFragment: (OFString *)percentEncodedFragment -{ - OFString *old; - - if (percentEncodedFragment != nil) - OFURIVerifyIsEscaped(percentEncodedFragment, - [OFCharacterSet URIFragmentAllowedCharacterSet], true); - - old = _percentEncodedFragment; - _percentEncodedFragment = [percentEncodedFragment copy]; - [old release]; -} - -- (id)copy -{ - OFMutableURI *copy = [self mutableCopy]; - - [copy makeImmutable]; - - return copy; -} - -- (void)appendPathComponent: (OFString *)component -{ - [self appendPathComponent: component isDirectory: false]; - -#ifdef OF_HAVE_FILES - if ([_scheme isEqual: @"file"] && - ![_percentEncodedPath hasSuffix: @"/"] && - [[OFFileManager defaultManager] directoryExistsAtURI: self]) { - void *pool = objc_autoreleasePoolPush(); - OFString *path = [_percentEncodedPath - stringByAppendingString: @"/"]; - - [_percentEncodedPath release]; - _percentEncodedPath = [path retain]; - - objc_autoreleasePoolPop(pool); - } -#endif -} - -- (void)appendPathComponent: (OFString *)component - isDirectory: (bool)isDirectory -{ - void *pool; - OFString *path; - - if ([component isEqual: @"/"] && [_percentEncodedPath hasSuffix: @"/"]) - return; - - pool = objc_autoreleasePoolPush(); - component = [component - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIPathAllowedCharacterSet]]; - -#if defined(OF_WINDOWS) || defined(OF_MSDOS) - if ([_percentEncodedPath hasSuffix: @"/"] || - ([_scheme isEqual: @"file"] && - [_percentEncodedPath hasSuffix: @":"])) -#else - if ([_percentEncodedPath hasSuffix: @"/"]) -#endif - path = [_percentEncodedPath stringByAppendingString: component]; - else - path = [_percentEncodedPath - stringByAppendingFormat: @"/%@", component]; - - if (isDirectory && ![path hasSuffix: @"/"]) - path = [path stringByAppendingString: @"/"]; - - [_percentEncodedPath release]; - _percentEncodedPath = [path retain]; - - objc_autoreleasePoolPop(pool); -} - -- (void)standardizePath -{ - void *pool = objc_autoreleasePoolPush(); - OFMutableArray OF_GENERIC(OFString *) *array; - bool done = false, startsWithEmpty, endsWithEmpty; - OFString *path; - - array = [[[_percentEncodedPath - componentsSeparatedByString: @"/"] mutableCopy] autorelease]; - - endsWithEmpty = ([array.lastObject length] == 0); - startsWithEmpty = ([array.firstObject length] == 0); - - while (!done) { - size_t length = array.count; - - done = true; - - for (size_t i = 0; i < length; i++) { - OFString *current = [array objectAtIndex: i]; - OFString *parent = - (i > 0 ? [array objectAtIndex: i - 1] : nil); - - if ([current isEqual: @"."] || current.length == 0) { - [array removeObjectAtIndex: i]; - - done = false; - break; - } - - if ([current isEqual: @".."] && parent != nil && - ![parent isEqual: @".."]) { - [array removeObjectsInRange: - OFMakeRange(i - 1, 2)]; - - done = false; - break; - } - } - } - - if (startsWithEmpty) - [array insertObject: @"" atIndex: 0]; - if (endsWithEmpty) - [array addObject: @""]; - - path = [array componentsJoinedByString: @"/"]; - if (startsWithEmpty && path.length == 0) - path = @"/"; - - self.percentEncodedPath = path; - - objc_autoreleasePoolPop(pool); -} - -- (void)makeImmutable -{ - object_setClass(self, [OFURI class]); -} -@end Index: src/OFMutableUTF8String.h ================================================================== --- src/OFMutableUTF8String.h +++ src/OFMutableUTF8String.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableZIPArchiveEntry.h ================================================================== --- src/OFMutableZIPArchiveEntry.h +++ src/OFMutableZIPArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutableZIPArchiveEntry.m ================================================================== --- src/OFMutableZIPArchiveEntry.m +++ src/OFMutableZIPArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutex.h ================================================================== --- src/OFMutex.h +++ src/OFMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFMutex.m ================================================================== --- src/OFMutex.m +++ src/OFMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFNonretainedObjectValue.h ================================================================== --- src/OFNonretainedObjectValue.h +++ src/OFNonretainedObjectValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFNonretainedObjectValue.m ================================================================== --- src/OFNonretainedObjectValue.m +++ src/OFNonretainedObjectValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFNotification.h ================================================================== --- src/OFNotification.h +++ src/OFNotification.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFNotification.m ================================================================== --- src/OFNotification.m +++ src/OFNotification.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFNotificationCenter.h ================================================================== --- src/OFNotificationCenter.h +++ src/OFNotificationCenter.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,10 @@ @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); #ifdef OF_HAVE_THREADS @class OFMutex; #endif -@class OFNotificationCenterHandle; #ifdef OF_HAVE_BLOCKS /** * @brief A block which is called when a notification has been posted. * @@ -62,12 +61,12 @@ /** * @brief Adds an observer for the specified notification and object. * * @param observer The object that should receive notifications * @param selector The selector to call on the observer on notifications. The - * method must take exactly one object of type @ref - * OFNotification. + * method must take exactly one object of type + * @ref OFNotification. * @param name The name of the notification to observe * @param object The object that should be sending the notification, or `nil` * if the object should be ignored to determine what * notifications to deliver */ @@ -101,22 +100,21 @@ * if the object should be ignored to determine what * notifications to deliver * @param block The block to handle notifications * @return An opaque object to remove the observer again */ -- (OFNotificationCenterHandle *) - addObserverForName: (OFNotificationName)name - object: (nullable id)object - usingBlock: (OFNotificationCenterBlock)block; +- (id)addObserverForName: (OFNotificationName)name + object: (nullable id)object + usingBlock: (OFNotificationCenterBlock)block; /** * @brief Removes an observer. The specified observer must be one returned by * @ref addObserver:selector:name:object:. * * @param observer The object that was returned when adding the observer */ -- (void)removeObserver: (OFNotificationCenterHandle *)observer; +- (void)removeObserver: (id)observer; #endif /** * @brief Posts the specified notification. * Index: src/OFNotificationCenter.m ================================================================== --- src/OFNotificationCenter.m +++ src/OFNotificationCenter.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -67,11 +67,11 @@ @try { void *pool = objc_autoreleasePoolPush(); _name = [name copy]; - _observer = [observer retain]; + _observer = observer; _selector = selector; _object = [object retain]; _selectorHash = [[OFString stringWithUTF8String: sel_getName(_selector)] hash]; @@ -106,11 +106,10 @@ #endif - (void)dealloc { [_name release]; - [_observer release]; [_object release]; #ifdef OF_HAVE_BLOCKS [_block release]; #endif @@ -245,14 +244,13 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS -- (OFNotificationCenterHandle *) - addObserverForName: (OFNotificationName)name - object: (id)object - usingBlock: (OFNotificationCenterBlock)block +- (id)addObserverForName: (OFNotificationName)name + object: (id)object + usingBlock: (OFNotificationCenterBlock)block { void *pool = objc_autoreleasePoolPush(); OFNotificationCenterHandle *handle = [[[OFNotificationCenterHandle alloc] initWithName: name object: object @@ -267,13 +265,20 @@ return [handle autorelease]; } #endif -- (void)removeObserver: (OFNotificationCenterHandle *)handle +- (void)removeObserver: (id)handle_ { - void *pool = objc_autoreleasePoolPush(); + OFNotificationCenterHandle *handle; + void *pool; + + if (![handle_ isKindOfClass: [OFNotificationCenterHandle class]]) + @throw [OFInvalidArgumentException exception]; + + handle = handle_; + pool = objc_autoreleasePoolPush(); /* {} required to avoid -Wmisleading-indentation false positive. */ if (![handle isKindOfClass: [OFNotificationCenterHandle class]]) { @throw [OFInvalidArgumentException exception]; } Index: src/OFNull.h ================================================================== --- src/OFNull.h +++ src/OFNull.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,21 +14,20 @@ */ #import "OFObject.h" #import "OFJSONRepresentation.h" #import "OFMessagePackRepresentation.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN /** * @class OFNull OFNull.h ObjFW/OFNull.h * * @brief A class for representing null values in collections. */ OF_SUBCLASSING_RESTRICTED -@interface OFNull: OFObject /** * @brief Returns an OFNull singleton. * * @return An OFNull singleton Index: src/OFNull.m ================================================================== --- src/OFNull.m +++ src/OFNull.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,13 +14,12 @@ */ #include "config.h" #import "OFNull.h" -#import "OFString.h" -#import "OFXMLElement.h" #import "OFData.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" @interface OFNull () - (OFString *) @@ -39,27 +38,10 @@ + (OFNull *)null { return null; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool; - - [self release]; - - pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - objc_autoreleasePoolPop(pool); - - return [OFNull null]; -} - - (OFString *)description { return @""; } @@ -66,25 +48,10 @@ - (id)copy { return self; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -26,11 +26,10 @@ # include #endif #import "OFJSONRepresentation.h" #import "OFMessagePackRepresentation.h" -#import "OFSerialization.h" #import "OFValue.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -41,12 +40,12 @@ * @brief Provides a way to store a number in an object. */ #ifndef OF_NUMBER_M OF_SUBCLASSING_RESTRICTED #endif -@interface OFNumber: OFValue +@interface OFNumber: OFValue { union { double float_; long long signed_; unsigned long long unsigned_; Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,14 +18,12 @@ #include "config.h" #include #import "OFNumber.h" -#import "OFString.h" -#import "OFXMLElement.h" -#import "OFXMLAttribute.h" #import "OFData.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @@ -375,15 +373,10 @@ return (id)doubleZeroNumber; } return (id)[[OFNumber of_alloc] initWithDouble: value]; } - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFNumber of_alloc] initWithSerialization: element]; -} #ifdef __clang__ # pragma clang diagnostic pop #endif @end @@ -782,58 +775,10 @@ _typeEncoding = @encode(double); return self; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - OFString *typeString; - - if (![element.name isEqual: @"OFNumber"] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - typeString = [element attributeForName: @"type"].stringValue; - - if ([typeString isEqual: @"bool"]) { - OFString *stringValue = element.stringValue; - if ([stringValue isEqual: @"true"]) - self = [self initWithBool: true]; - else if ([stringValue isEqual: @"false"]) - self = [self initWithBool: false]; - else - @throw [OFInvalidArgumentException exception]; - } else if ([typeString isEqual: @"float"]) { - unsigned long long value = - [element unsignedLongLongValueWithBase: 16]; - - if (value > UINT64_MAX) - @throw [OFOutOfRangeException exception]; - - self = [self initWithDouble: OFFromBigEndianDouble( - OFRawUInt64ToDouble(OFToBigEndian64(value)))]; - } else if ([typeString isEqual: @"signed"]) - self = [self initWithLongLong: element.longLongValue]; - else if ([typeString isEqual: @"unsigned"]) - self = [self initWithUnsignedLongLong: - element.unsignedLongLongValue]; - else - @throw [OFInvalidArgumentException exception]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - - (const char *)objCType { return _typeEncoding; } @@ -1077,42 +1022,10 @@ self.unsignedLongLongValue]; @throw [OFInvalidFormatException exception]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: @"OFNumber" - namespace: OFSerializationNS - stringValue: self.description]; - - if (*self.objCType == 'B') - [element addAttributeWithName: @"type" stringValue: @"bool"]; - else if (isFloat(self)) { - [element addAttributeWithName: @"type" stringValue: @"float"]; - element.stringValue = [OFString - stringWithFormat: @"%016" PRIx64, - OFFromBigEndian64(OFDoubleToRawUInt64(OFToBigEndianDouble( - self.doubleValue)))]; - } else if (isSigned(self)) - [element addAttributeWithName: @"type" stringValue: @"signed"]; - else if (isUnsigned(self)) - [element addAttributeWithName: @"type" - stringValue: @"unsigned"]; - else - @throw [OFInvalidFormatException exception]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } Index: src/OFObject+KeyValueCoding.h ================================================================== --- src/OFObject+KeyValueCoding.h +++ src/OFObject+KeyValueCoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFObject+KeyValueCoding.m ================================================================== --- src/OFObject+KeyValueCoding.m +++ src/OFObject+KeyValueCoding.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/OFObject+Serialization.h Index: src/OFObject+Serialization.h ================================================================== --- src/OFObject+Serialization.h +++ src/OFObject+Serialization.h @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFObject.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFString; - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFObject_Serialization_reference; -#ifdef __cplusplus -} -#endif - -@interface OFObject (OFSerialization) -/** - * @brief The object serialized as a string. - */ -@property (readonly, nonatomic) OFString *stringBySerializing; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFObject+Serialization.m Index: src/OFObject+Serialization.m ================================================================== --- src/OFObject+Serialization.m +++ src/OFObject+Serialization.m @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "OFObject.h" -#import "OFObject+Serialization.h" -#import "OFSerialization.h" -#import "OFString.h" -#import "OFXMLElement.h" - -int _OFObject_Serialization_reference; - -@implementation OFObject (Serialization) -- (OFString *)stringBySerializing -{ - void *pool; - OFXMLElement *element; - OFXMLElement *root; - OFString *ret; - - if (![self conformsToProtocol: @protocol(OFSerialization)]) { - [self doesNotRecognizeSelector: _cmd]; - abort(); - } - - pool = objc_autoreleasePoolPush(); - element = ((id )self).XMLElementBySerializing; - - root = [OFXMLElement elementWithName: @"serialization" - namespace: OFSerializationNS]; - [root addAttributeWithName: @"version" stringValue: @"1"]; - [root addChild: element]; - - ret = [@"\n" - stringByAppendingString: [root XMLStringWithIndentation: 2]]; - - [ret retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} -@end Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -61,10 +61,21 @@ OFOrderedSame = 0, /** The left object is bigger than the right */ OFOrderedDescending = 1 } OFComparisonResult; +/** + * @brief A function to compare two objects. + * + * @param left The left object + * @param right The right object + * @param context Context passed along for comparing + * @return The order of the objects + */ +typedef OFComparisonResult (*OFCompareFunction)(id _Nonnull left, + id _Nonnull right, void *_Nullable context); + #ifdef OF_HAVE_BLOCKS /** * @brief A comparator to compare two objects. * * @param left The left object @@ -142,11 +153,11 @@ typedef double OFTimeInterval; /** * @struct OFPoint OFObject.h ObjFW/OFObject.h * - * @brief A point. + * @brief A point in 2D space. */ typedef struct OF_BOXABLE { /** The x coordinate of the point */ float x; /** The y coordinate of the point */ @@ -279,10 +290,120 @@ return false; if (!OFEqualSizes(rect1.size, rect2.size)) return false; + return true; +} + +/** + * @struct OFVector3D OFObject.h ObjFW/OFObject.h + * + * @brief A vector in 3D space. + */ +typedef struct OF_BOXABLE { + /** The x coordinate of the vector */ + float x; + /** The y coordinate of the vector */ + float y; + /** The z coordinate of the vector */ + float z; +} OFVector3D; + +/** + * @brief Creates a new OFVector3D. + * + * @param x The x coordinate of the vector + * @param y The x coordinate of the vector + * @param z The z coordinate of the vector + * @return An OFVector3D with the specified coordinates + */ +static OF_INLINE OFVector3D OF_CONST_FUNC +OFMakeVector3D(float x, float y, float z) +{ + OFVector3D vector = { x, y, z }; + + return vector; +} + +/** + * @brief Returns whether the two vectors are equal. + * + * @param vector1 The first vector for the comparison + * @param vector2 The second vectors for the comparison + * @return Whether the two vectors are equal + */ +static OF_INLINE bool +OFEqualVectors3D(OFVector3D vector1, OFVector3D vector2) +{ + if (vector1.x != vector2.x) + return false; + + if (vector1.y != vector2.y) + return false; + + if (vector1.z != vector2.z) + return false; + + return true; +} + +/** + * @struct OFVector4D OFObject.h ObjFW/OFObject.h + * + * @brief A vector in 4D space. + */ +typedef struct OF_BOXABLE { + /** The x coordinate of the vector */ + float x; + /** The y coordinate of the vector */ + float y; + /** The z coordinate of the vector */ + float z; + /** The w coordinate of the vector */ + float w; +} OFVector4D; + +/** + * @brief Creates a new OFVector4D. + * + * @param x The x coordinate of the vector + * @param y The x coordinate of the vector + * @param z The z coordinate of the vector + * @param w The w coordinate of the vector + * @return An OFVector4D with the specified coordinates + */ +static OF_INLINE OFVector4D OF_CONST_FUNC +OFMakeVector4D(float x, float y, float z, float w) +{ + OFVector4D vector = { x, y, z, w }; + + return vector; +} + +/** + * @brief Returns whether the two vectors are equal. + * + * @param vector1 The first vector for the comparison + * @param vector2 The second vectors for the comparison + * @return Whether the two vectors are equal + */ +static OF_INLINE bool +OFEqualVectors4D(OFVector4D vector1, OFVector4D vector2) +{ + if (vector1.x != vector2.x) + return false; + + if (vector1.y != vector2.y) + return false; + + if (vector1.z != vector2.z) + return false; + + if (vector1.w != vector2.w) + return false; + return true; } /** * @brief Adds the specified byte to the hash. @@ -657,17 +778,10 @@ * object * @throw OFInitializationFailedException The instance could not be constructed */ + (instancetype)alloc; -/** - * @brief Calls @ref alloc on `self` and then `init` on the returned object. - * - * @return An allocated and initialized object - */ -+ (instancetype)new; - /** * @brief Returns the class. * * @return The class */ @@ -1400,9 +1514,8 @@ #include "OFBlock.h" #ifdef __OBJC__ # import "OFObject+KeyValueCoding.h" -# import "OFObject+Serialization.h" #endif #endif Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -62,11 +62,13 @@ #ifdef OF_WINDOWS # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include +# undef Class #endif #ifdef OF_APPLE_RUNTIME extern id _Nullable _objc_rootAutorelease(id _Nullable object); #endif @@ -391,11 +393,10 @@ /* References for static linking */ void _references_to_categories_of_OFObject(void) { _OFObject_KeyValueCoding_reference = 1; - _OFObject_Serialization_reference = 1; } @implementation OFObject + (void)load { @@ -443,15 +444,10 @@ + (instancetype)alloc { return OFAllocObject(self, 0, 0, NULL); } -+ (instancetype)new -{ - return [[self alloc] init]; -} - + (Class)class { return self; } @@ -480,14 +476,12 @@ return class_respondsToSelector(self, selector); } + (bool)conformsToProtocol: (Protocol *)protocol { - Class c; - - for (c = self; c != Nil; c = class_getSuperclass(c)) - if (class_conformsToProtocol(c, protocol)) + for (Class iter = self; iter != Nil; iter = class_getSuperclass(iter)) + if (class_conformsToProtocol(iter, protocol)) return true; return false; } @@ -585,16 +579,16 @@ [self inheritMethodsFromClass: superclass]; } + (bool)resolveClassMethod: (SEL)selector { - return NO; + return false; } + (bool)resolveInstanceMethod: (SEL)selector { - return NO; + return false; } - (instancetype)init { return self; Index: src/OFOnce.h ================================================================== --- src/OFOnce.h +++ src/OFOnce.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFOnce.m ================================================================== --- src/OFOnce.m +++ src/OFOnce.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,11 +22,13 @@ # import "OFAtomic.h" # import "OFPlainMutex.h" #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include +# undef Class #endif void OFOnce(OFOnceControl *control, void (*function)(void)) { Index: src/OFOptionsParser.h ================================================================== --- src/OFOptionsParser.h +++ src/OFOptionsParser.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFOptionsParser.m ================================================================== --- src/OFOptionsParser.m +++ src/OFOptionsParser.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPBKDF2.h ================================================================== --- src/OFPBKDF2.h +++ src/OFPBKDF2.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPBKDF2.m ================================================================== --- src/OFPBKDF2.m +++ src/OFPBKDF2.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPair.h ================================================================== --- src/OFPair.h +++ src/OFPair.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPair.m ================================================================== --- src/OFPair.m +++ src/OFPair.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlainCondition.h ================================================================== --- src/OFPlainCondition.h +++ src/OFPlainCondition.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlainCondition.m ================================================================== --- src/OFPlainCondition.m +++ src/OFPlainCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlainMutex.h ================================================================== --- src/OFPlainMutex.h +++ src/OFPlainMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlainMutex.m ================================================================== --- src/OFPlainMutex.m +++ src/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlainThread.h ================================================================== --- src/OFPlainThread.h +++ src/OFPlainThread.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,11 @@ #if !defined(OF_HAVE_THREADS) || \ (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)) # error No threads available! #endif -#import "macros.h" +#import "OFObject.h" #if defined(OF_HAVE_PTHREADS) # include typedef pthread_t OFPlainThread; #elif defined(OF_WINDOWS) Index: src/OFPlainThread.m ================================================================== --- src/OFPlainThread.m +++ src/OFPlainThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPlugin.m ================================================================== --- src/OFPlugin.m +++ src/OFPlugin.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPointValue.h ================================================================== --- src/OFPointValue.h +++ src/OFPointValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPointValue.m ================================================================== --- src/OFPointValue.m +++ src/OFPointValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPointerValue.h ================================================================== --- src/OFPointerValue.h +++ src/OFPointerValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPointerValue.m ================================================================== --- src/OFPointerValue.m +++ src/OFPointerValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPollKernelEventObserver.h ================================================================== --- src/OFPollKernelEventObserver.h +++ src/OFPollKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFPollKernelEventObserver.m ================================================================== --- src/OFPollKernelEventObserver.m +++ src/OFPollKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRIPEMD160Hash.h ================================================================== --- src/OFRIPEMD160Hash.h +++ src/OFRIPEMD160Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRIPEMD160Hash.m ================================================================== --- src/OFRIPEMD160Hash.m +++ src/OFRIPEMD160Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRangeCharacterSet.h ================================================================== --- src/OFRangeCharacterSet.h +++ src/OFRangeCharacterSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRangeCharacterSet.m ================================================================== --- src/OFRangeCharacterSet.m +++ src/OFRangeCharacterSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRangeValue.h ================================================================== --- src/OFRangeValue.h +++ src/OFRangeValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRangeValue.m ================================================================== --- src/OFRangeValue.m +++ src/OFRangeValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRectValue.h ================================================================== --- src/OFRectValue.h +++ src/OFRectValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRectValue.m ================================================================== --- src/OFRectValue.m +++ src/OFRectValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRecursiveMutex.h ================================================================== --- src/OFRecursiveMutex.h +++ src/OFRecursiveMutex.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRecursiveMutex.m ================================================================== --- src/OFRecursiveMutex.m +++ src/OFRecursiveMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRunLoop+Private.h ================================================================== --- src/OFRunLoop+Private.h +++ src/OFRunLoop+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRunLoop.h ================================================================== --- src/OFRunLoop.h +++ src/OFRunLoop.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFRunLoopConstants.inc ================================================================== --- src/OFRunLoopConstants.inc +++ src/OFRunLoopConstants.inc @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA1Hash.h ================================================================== --- src/OFSHA1Hash.h +++ src/OFSHA1Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA1Hash.m ================================================================== --- src/OFSHA1Hash.m +++ src/OFSHA1Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA224Hash.h ================================================================== --- src/OFSHA224Hash.h +++ src/OFSHA224Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA224Hash.m ================================================================== --- src/OFSHA224Hash.m +++ src/OFSHA224Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA224Or256Hash.h ================================================================== --- src/OFSHA224Or256Hash.h +++ src/OFSHA224Or256Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA224Or256Hash.m ================================================================== --- src/OFSHA224Or256Hash.m +++ src/OFSHA224Or256Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA256Hash.h ================================================================== --- src/OFSHA256Hash.h +++ src/OFSHA256Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA256Hash.m ================================================================== --- src/OFSHA256Hash.m +++ src/OFSHA256Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA384Hash.h ================================================================== --- src/OFSHA384Hash.h +++ src/OFSHA384Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA384Hash.m ================================================================== --- src/OFSHA384Hash.m +++ src/OFSHA384Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA384Or512Hash.h ================================================================== --- src/OFSHA384Or512Hash.h +++ src/OFSHA384Or512Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA384Or512Hash.m ================================================================== --- src/OFSHA384Or512Hash.m +++ src/OFSHA384Or512Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA512Hash.h ================================================================== --- src/OFSHA512Hash.h +++ src/OFSHA512Hash.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSHA512Hash.m ================================================================== --- src/OFSHA512Hash.m +++ src/OFSHA512Hash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSPXSocket.h ================================================================== --- src/OFSPXSocket.h +++ src/OFSPXSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -88,11 +88,11 @@ * @param network The network on which the node to connect to is * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to * @throw OFConnectSPXSocketFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; @@ -162,14 +162,14 @@ * computer's node. * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return via the returned socket address. * @return The address on which this socket can be reached * @throw OFBindIPXSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (OFSocketAddress) bindToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFSPXSocket.m ================================================================== --- src/OFSPXSocket.m +++ src/OFSPXSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -21,11 +21,11 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindIPXSocketFailedException.h" #import "OFConnectSPXSocketFailedException.h" #import "OFNotOpenException.h" #ifndef NSPROTO_SPX @@ -183,11 +183,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if ((_socket = socket(address->sockaddr.ipx.sipx_family, SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) { *errNo = OFSocketErrNo(); @@ -321,11 +321,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeIPX(network, node, port); if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == Index: src/OFSPXStreamSocket.h ================================================================== --- src/OFSPXStreamSocket.h +++ src/OFSPXStreamSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -89,11 +89,11 @@ * @param network The network on which the node to connect to is * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to * @throw OFConnectSPXSocketFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; @@ -167,14 +167,14 @@ * computer's node. * @param port The port (sometimes called socket number) to bind to. 0 means to * pick one and return via the returned socket address. * @return The address on which this socket can be reached * @throw OFBindIPXSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (OFSocketAddress) bindToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFSPXStreamSocket.m ================================================================== --- src/OFSPXStreamSocket.m +++ src/OFSPXStreamSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -21,11 +21,11 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindIPXSocketFailedException.h" #import "OFConnectSPXSocketFailedException.h" #import "OFNotOpenException.h" #ifndef NSPROTO_SPX @@ -185,11 +185,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if ((_socket = socket(address->sockaddr.ipx.sipx_family, SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) { *errNo = OFSocketErrNo(); @@ -323,11 +323,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeIPX(network, node, port); if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) Index: src/OFSandbox.h ================================================================== --- src/OFSandbox.h +++ src/OFSandbox.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSandbox.m ================================================================== --- src/OFSandbox.m +++ src/OFSandbox.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFScrypt.h ================================================================== --- src/OFScrypt.h +++ src/OFScrypt.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFScrypt.m ================================================================== --- src/OFScrypt.m +++ src/OFScrypt.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSecureData.h ================================================================== --- src/OFSecureData.h +++ src/OFSecureData.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -102,11 +102,11 @@ itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; #ifdef OF_HAVE_FILES + (instancetype)dataWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; #endif -+ (instancetype)dataWithContentsOfURI: (OFURI *)URI OF_UNAVAILABLE; ++ (instancetype)dataWithContentsOfIRI: (OFIRI *)IRI OF_UNAVAILABLE; + (instancetype)dataWithStringRepresentation: (OFString *)string OF_UNAVAILABLE; + (instancetype)dataWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFSecureData with `count` items of @@ -148,14 +148,13 @@ itemSize: (size_t)itemSize freeWhenDone: (bool)freeWhenDone OF_UNAVAILABLE; #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path OF_UNAVAILABLE; #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI OF_UNAVAILABLE; +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI OF_UNAVAILABLE; - (instancetype)initWithStringRepresentation: (OFString *)string OF_UNAVAILABLE; - (instancetype)initWithBase64EncodedString: (OFString *)string OF_UNAVAILABLE; -- (instancetype)initWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE; /** * @brief Returns a specific item of the OFSecureData. * * Modifying the returned item directly is allowed and will change the contents @@ -185,11 +184,10 @@ - (OFString *)stringRepresentation OF_UNAVAILABLE; - (OFString *)stringByBase64Encoding OF_UNAVAILABLE; #ifdef OF_HAVE_FILES - (void)writeToFile: (OFString *)path OF_UNAVAILABLE; #endif -- (void)writeToURI: (OFURI *)URI OF_UNAVAILABLE; -- (OFXMLElement *)XMLElementBySerializing OF_UNAVAILABLE; +- (void)writeToIRI: (OFIRI *)IRI OF_UNAVAILABLE; - (OFData *)messagePackRepresentation OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/OFSecureData.m ================================================================== --- src/OFSecureData.m +++ src/OFSecureData.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -373,11 +373,11 @@ { OF_UNRECOGNIZED_SELECTOR } #endif -+ (instancetype)dataWithContentsOfURI: (OFURI *)URI ++ (instancetype)dataWithContentsOfIRI: (OFIRI *)IRI { OF_UNRECOGNIZED_SELECTOR } + (instancetype)dataWithStringRepresentation: (OFString *)string @@ -497,11 +497,11 @@ { OF_INVALID_INIT_METHOD } #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI { OF_INVALID_INIT_METHOD } - (instancetype)initWithStringRepresentation: (OFString *)string @@ -509,15 +509,10 @@ OF_INVALID_INIT_METHOD } - (instancetype)initWithBase64EncodedString: (OFString *)string { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ OF_INVALID_INIT_METHOD } - (void)dealloc { @@ -629,20 +624,15 @@ { OF_UNRECOGNIZED_SELECTOR } #endif -- (void)writeToURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (OFXMLElement *)XMLElementBySerializing +- (void)writeToIRI: (OFIRI *)IRI { OF_UNRECOGNIZED_SELECTOR } - (OFData *)messagePackRepresentation { OF_UNRECOGNIZED_SELECTOR } @end Index: src/OFSeekableStream.h ================================================================== --- src/OFSeekableStream.h +++ src/OFSeekableStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSeekableStream.m ================================================================== --- src/OFSeekableStream.m +++ src/OFSeekableStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSelectKernelEventObserver.h ================================================================== --- src/OFSelectKernelEventObserver.h +++ src/OFSelectKernelEventObserver.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSelectKernelEventObserver.m ================================================================== --- src/OFSelectKernelEventObserver.m +++ src/OFSelectKernelEventObserver.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -36,11 +36,13 @@ #import "OFInitializationFailedException.h" #import "OFObserveKernelEventsFailedException.h" #import "OFOutOfRangeException.h" #ifdef OF_AMIGAOS +# define Class IntuitionClass # include +# undef Class #endif #ifdef OF_HPUX /* FD_SET causes warnings on HP-UX/IA64. */ # pragma GCC diagnostic ignored "-Wstrict-aliasing" Index: src/OFSequencedPacketSocket+Private.h ================================================================== --- src/OFSequencedPacketSocket+Private.h +++ src/OFSequencedPacketSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSequencedPacketSocket.m ================================================================== --- src/OFSequencedPacketSocket.m +++ src/OFSequencedPacketSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/OFSerialization.h Index: src/OFSerialization.h ================================================================== --- src/OFSerialization.h +++ src/OFSerialization.h @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFObject.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFConstantString; -@class OFXMLElement; - -/** - * @protocol OFSerialization OFSerialization.h ObjFW/OFSerialization.h - * - * @brief A protocol for serializing objects. - */ -@protocol OFSerialization -/** - * @brief The object serialized into an XML element. - */ -@property (readonly, nonatomic) OFXMLElement *XMLElementBySerializing; - -/** - * @brief Initializes the object with the specified XML element serialization. - * - * @param element An OFXMLElement with the serialized object - * @return An initialized object - * @throw OFInvalidFormatException The specified element is not of the correct - * serialization format - */ -- (instancetype)initWithSerialization: (OFXMLElement *)element; -@end - -#ifdef __cplusplus -extern "C" { -#endif -extern OFConstantString *const OFSerializationNS; -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END DELETED src/OFSerialization.m Index: src/OFSerialization.m ================================================================== --- src/OFSerialization.m +++ src/OFSerialization.m @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFSerialization.h" -#import "OFString.h" - -OFConstantString *const OFSerializationNS = - @"https://objfw.nil.im/serialization"; Index: src/OFSet.h ================================================================== --- src/OFSet.h +++ src/OFSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,11 +22,10 @@ #include #import "OFObject.h" #import "OFCollection.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @@ -61,11 +60,11 @@ * * @note Subclasses must implement @ref count, @ref containsObject: and * @ref objectEnumerator. */ @interface OFSet OF_GENERIC(ObjectType): OFObject + OFMutableCopying> #if !defined(OF_HAVE_GENERICS) && !defined(DOXYGEN) # define ObjectType id #endif /** * @brief An array of all objects in the set. Index: src/OFSet.m ================================================================== --- src/OFSet.m +++ src/OFSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,10 @@ #import "OFSet.h" #import "OFArray.h" #import "OFMapTableSet.h" #import "OFNull.h" #import "OFString.h" -#import "OFXMLElement.h" static struct { Class isa; } placeholder; @@ -70,15 +69,10 @@ { return (id)[[OFMapTableSet alloc] initWithObject: firstObject arguments: arguments]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFMapTableSet alloc] initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -189,15 +183,10 @@ return ret; } - (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ OF_INVALID_INIT_METHOD } - (size_t)count { @@ -360,35 +349,10 @@ return true; return false; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - if ([self isKindOfClass: [OFMutableSet class]]) - element = [OFXMLElement elementWithName: @"OFMutableSet" - namespace: OFSerializationNS]; - else - element = [OFXMLElement elementWithName: @"OFSet" - namespace: OFSerializationNS]; - - for (id object in self) { - void *pool2 = objc_autoreleasePoolPush(); - [element addChild: object.XMLElementBySerializing]; - objc_autoreleasePoolPop(pool2); - } - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFSet *)setByAddingObjectsFromSet: (OFSet *)set { OFMutableSet *new = [[self mutableCopy] autorelease]; [new unionSet: set]; [new makeImmutable]; Index: src/OFSettings.h ================================================================== --- src/OFSettings.h +++ src/OFSettings.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSettings.m ================================================================== --- src/OFSettings.m +++ src/OFSettings.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSizeValue.h ================================================================== --- src/OFSizeValue.h +++ src/OFSizeValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSizeValue.m ================================================================== --- src/OFSizeValue.m +++ src/OFSizeValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSocket+Private.h ================================================================== --- src/OFSocket+Private.h +++ src/OFSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSocket.h ================================================================== --- src/OFSocket.h +++ src/OFSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -59,12 +59,10 @@ # ifdef OF_HAVE_APPLETALK # include # endif #endif -/** @file */ - #ifdef OF_WII # include #endif #ifdef OF_PSP @@ -72,10 +70,12 @@ #endif #import "macros.h" OF_ASSUME_NONNULL_BEGIN + +/** @file */ #ifndef OF_WINDOWS typedef int OFSocketHandle; static const OFSocketHandle OFInvalidSocketHandle = -1; #else @@ -134,43 +134,46 @@ sa_family_t sun_family; char sun_path[108]; }; #endif -#ifndef OF_HAVE_IPX +#ifndef IPX_NODE_LEN # define IPX_NODE_LEN 6 +#endif +#if !defined(OF_HAVE_IPX) struct sockaddr_ipx { sa_family_t sipx_family; uint32_t sipx_network; unsigned char sipx_node[IPX_NODE_LEN]; uint16_t sipx_port; uint8_t sipx_type; }; -#endif -#ifdef OF_WINDOWS +#elif defined(OF_WINDOWS) # define IPX_NODE_LEN 6 # define sipx_family sa_family # define sipx_network sa_netnum # define sipx_node sa_nodenum # define sipx_port sa_socket +#elif defined(OF_FREEBSD) +# define sipx_network sipx_addr.x_net.c_net +# define sipx_node sipx_addr.x_host.c_host #endif #ifndef OF_HAVE_APPLETALK struct sockaddr_at { sa_family_t sat_family; uint8_t sat_port; - struct at_addr { - uint16_t s_net; - uint8_t s_node; - } sat_addr; + uint16_t sat_net; + uint8_t sat_node; }; -#endif -#ifdef OF_WINDOWS -# define sat_port sat_socket #else -# define sat_net sat_addr.s_net -# define sat_node sat_addr.s_node +# ifdef OF_WINDOWS +# define sat_port sat_socket +# else +# define sat_net sat_addr.s_net +# define sat_node sat_addr.s_node +# endif #endif /** * @struct OFSocketAddress OFSocket.h ObjFW/OFSocket.h * @@ -186,10 +189,17 @@ struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; struct sockaddr_ipx ipx; struct sockaddr_at at; +#ifdef OF_HAVE_SOCKADDR_STORAGE + /* + * Required to make the ABI stable in case we want to add more + * address types later. + */ + struct sockaddr_storage storage; +#endif } sockaddr; socklen_t length; } OFSocketAddress; #ifdef __cplusplus @@ -278,11 +288,11 @@ /** * @brief Converts the specified @ref OFSocketAddress to a string. * * @param address The address to convert to a string - * @return The address as an IP string + * @return The address as an IP string, without the port */ extern OFString *_Nonnull OFSocketAddressString( const OFSocketAddress *_Nonnull address); /** Index: src/OFSocket.m ================================================================== --- src/OFSocket.m +++ src/OFSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -51,11 +51,13 @@ #ifdef HAVE_NET_IF_H # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include +# undef Class #endif #ifdef OF_NINTENDO_3DS # include <3ds/types.h> # include <3ds/services/soc.h> @@ -428,10 +430,38 @@ if (number > UINT16_MAX) @throw [OFInvalidFormatException exception]; return (uint16_t)number; } + +static OFString * +transformEmbeddedIPv4(OFString *IPv6) +{ + size_t lastColon = [IPv6 + rangeOfString: @":" + options: OFStringSearchBackwards].location; + OFString *IPv4; + OFSocketAddress address; + const struct sockaddr_in *addrIn; + uint32_t addr; + + if (lastColon == OFNotFound) + @throw [OFInvalidFormatException exception]; + + IPv4 = [IPv6 substringWithRange: + OFMakeRange(lastColon + 1, IPv6.length - lastColon - 1)]; + IPv6 = [IPv6 substringWithRange: OFMakeRange(0, lastColon + 1)]; + + address = OFSocketAddressParseIPv4(IPv4, 0); + addrIn = &address.sockaddr.in; + addr = OFFromBigEndian32(addrIn->sin_addr.s_addr); + + return [IPv6 stringByAppendingString: + [OFString stringWithFormat: @"%x%02x:%x%02x", + (addr & 0xFF000000) >> 24, (addr & 0x00FF0000) >> 16, + (addr & 0x0000FF00) >> 8, addr & 0x000000FF]]; +} OFSocketAddress OFSocketAddressParseIPv6(OFString *IPv6, uint16_t port) { void *pool = objc_autoreleasePoolPush(); @@ -465,10 +495,13 @@ } if (addrIn6->sin6_scope_id == 0) @throw [OFInvalidArgumentException exception]; } + + if ([IPv6 rangeOfString: @"."].location != OFNotFound) + IPv6 = transformEmbeddedIPv4(IPv6); doubleColon = [IPv6 rangeOfString: @"::"].location; if (doubleColon != OFNotFound) { OFString *left = [IPv6 substringToIndex: doubleColon]; OFString *right = [IPv6 substringFromIndex: doubleColon + 2]; @@ -555,10 +588,13 @@ memset(&ret, '\0', sizeof(ret)); ret.family = OFSocketAddressFamilyUNIX; ret.length = (socklen_t) (offsetof(struct sockaddr_un, sun_path) + length); +#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN + ret.sockaddr.un.sun_len = (uint8_t)length; +#endif #ifdef AF_UNIX ret.sockaddr.un.sun_family = AF_UNIX; #else ret.sockaddr.un.sun_family = AF_UNSPEC; #endif @@ -904,19 +940,51 @@ [string makeImmutable]; return string; } + +static OFString * +IPXString(const OFSocketAddress *address) +{ + const struct sockaddr_ipx *addrIPX = &address->sockaddr.ipx; + uint32_t network; + uint64_t node; + + memcpy(&network, &addrIPX->sipx_network, sizeof(addrIPX->sipx_network)); + node = ((uint64_t)addrIPX->sipx_node[0] << 40) | + ((uint64_t)addrIPX->sipx_node[1] << 32) | + ((uint64_t)addrIPX->sipx_node[2] << 24) | + ((uint64_t)addrIPX->sipx_node[3] << 16) | + ((uint64_t)addrIPX->sipx_node[4] << 8) | + (uint64_t)addrIPX->sipx_node[5]; + + return [OFString stringWithFormat: @"%X.%X", + OFFromBigEndian32(network), node]; +} + +static OFString * +appleTalkString(const OFSocketAddress *address) +{ + const struct sockaddr_at *addrAT = &address->sockaddr.at; + + return [OFString stringWithFormat: @"%d.%d", + OFFromBigEndian16(addrAT->sat_net), addrAT->sat_node]; +} OFString * OFSocketAddressString(const OFSocketAddress *address) { switch (address->family) { case OFSocketAddressFamilyIPv4: return IPv4String(address); case OFSocketAddressFamilyIPv6: return IPv6String(address); + case OFSocketAddressFamilyIPX: + return IPXString(address); + case OFSocketAddressFamilyAppleTalk: + return appleTalkString(address); default: @throw [OFInvalidArgumentException exception]; } } Index: src/OFSortedList.h ================================================================== --- src/OFSortedList.h +++ src/OFSortedList.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSortedList.m ================================================================== --- src/OFSortedList.m +++ src/OFSortedList.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStdIOStream+Private.h ================================================================== --- src/OFStdIOStream+Private.h +++ src/OFStdIOStream+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStdIOStream.h ================================================================== --- src/OFStdIOStream.h +++ src/OFStdIOStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStdIOStream.m ================================================================== --- src/OFStdIOStream.m +++ src/OFStdIOStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -45,12 +45,14 @@ #ifdef OF_IOS # undef HAVE_ISATTY #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include +# undef Class # undef HAVE_ISATTY #endif #ifdef OF_WII_U # define BOOL WUT_BOOL @@ -463,11 +465,11 @@ #endif } - (int)columns { -#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && \ +#if defined(HAVE_IOCTL) && defined(TIOCGWINSZ) && \ !defined(OF_AMIGAOS) && !defined(OF_WII_U) struct winsize ws; if (ioctl(_fd, TIOCGWINSZ, &ws) != 0) return -1; @@ -478,11 +480,11 @@ #endif } - (int)rows { -#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && \ +#if defined(HAVE_IOCTL) && defined(TIOCGWINSZ) && \ !defined(OF_AMIGAOS) && !defined(OF_WII_U) struct winsize ws; if (ioctl(_fd, TIOCGWINSZ, &ws) != 0) return -1; Index: src/OFStrPTime.h ================================================================== --- src/OFStrPTime.h +++ src/OFStrPTime.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStrPTime.m ================================================================== --- src/OFStrPTime.m +++ src/OFStrPTime.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStream+Private.h ================================================================== --- src/OFStream+Private.h +++ src/OFStream+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStream.m ================================================================== --- src/OFStream.m +++ src/OFStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStreamSocket+Private.h ================================================================== --- src/OFStreamSocket+Private.h +++ src/OFStreamSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStreamSocket.h ================================================================== --- src/OFStreamSocket.h +++ src/OFStreamSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFStreamSocket.m ================================================================== --- src/OFStreamSocket.m +++ src/OFStreamSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -240,17 +240,21 @@ _listening = true; } - (instancetype)accept { - OFStreamSocket *client = [[[[self class] alloc] init] autorelease]; + OFStreamSocket *client; #if (!defined(HAVE_PACCEPT) && !defined(HAVE_ACCEPT4)) || !defined(SOCK_CLOEXEC) # if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; # endif #endif + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + client = [[[[self class] alloc] init] autorelease]; client->_remoteAddress.length = (socklen_t)sizeof(client->_remoteAddress.sockaddr); #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, Index: src/OFString+CryptographicHashing.h ================================================================== --- src/OFString+CryptographicHashing.h +++ src/OFString+CryptographicHashing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+CryptographicHashing.m ================================================================== --- src/OFString+CryptographicHashing.m +++ src/OFString+CryptographicHashing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+JSONParsing.h ================================================================== --- src/OFString+JSONParsing.h +++ src/OFString+JSONParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+JSONParsing.m ================================================================== --- src/OFString+JSONParsing.m +++ src/OFString+JSONParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+PathAdditions.h ================================================================== --- src/OFString+PathAdditions.h +++ src/OFString+PathAdditions.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -84,13 +84,13 @@ * @return A new, autoreleased OFString with the path extension appended */ - (OFString *)stringByAppendingPathExtension: (OFString *)extension; - (bool)of_isDirectoryPath; -- (OFString *)of_pathToURIPathWithPercentEncodedHost: +- (OFString *)of_pathToIRIPathWithPercentEncodedHost: (OFString *__autoreleasing _Nullable *_Nonnull)percentEncodedHost; -- (OFString *)of_URIPathToPathWithPercentEncodedHost: +- (OFString *)of_IRIPathToPathWithPercentEncodedHost: (nullable OFString *)percentEncodedHost; -- (OFString *)of_pathComponentToURIPathComponent; +- (OFString *)of_pathComponentToIRIPathComponent; @end OF_ASSUME_NONNULL_END Index: src/OFString+PathAdditions.m ================================================================== --- src/OFString+PathAdditions.m +++ src/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+PercentEncoding.h ================================================================== --- src/OFString+PercentEncoding.h +++ src/OFString+PercentEncoding.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -34,11 +34,11 @@ * @throw OFInvalidFormatException The string is not in proper percent encoding */ @property (readonly, nonatomic) OFString *stringByRemovingPercentEncoding; /** - * @brief Percent-encodes a string for use in a URI, but does not escape the + * @brief Percent-encodes a string for use in an IRI, but does not escape the * specified allowed characters. * * @param allowedCharacters A character set of characters that should not be * escaped * Index: src/OFString+PercentEncoding.m ================================================================== --- src/OFString+PercentEncoding.m +++ src/OFString+PercentEncoding.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+PropertyListParsing.h ================================================================== --- src/OFString+PropertyListParsing.h +++ src/OFString+PropertyListParsing.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+PropertyListParsing.m ================================================================== --- src/OFString+PropertyListParsing.m +++ src/OFString+PropertyListParsing.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/OFString+Serialization.h Index: src/OFString+Serialization.h ================================================================== --- src/OFString+Serialization.h +++ src/OFString+Serialization.h @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFString.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFString_Serialization_reference; -#ifdef __cplusplus -} -#endif - -@interface OFString (Serialization) -/** - * @brief The string interpreted as serialization and parsed as an object. - * - * @throw OFMalformedXMLException The XML was malformed - * @throw OFUnboundNamespaceException A prefix was used that was not bound to - * any namespace - * @throw OFInvalidEncodingException The XML is not in the encoding it specified - * @throw OFUnsupportedVersionException The serialization is in an unsupported - * version - */ -@property (readonly, nonatomic) id objectByDeserializing; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFString+Serialization.m Index: src/OFString+Serialization.m ================================================================== --- src/OFString+Serialization.m +++ src/OFString+Serialization.m @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFString.h" -#import "OFString+Serialization.h" -#import "OFSerialization.h" -#import "OFArray.h" -#import "OFXMLElement.h" -#import "OFXMLAttribute.h" - -#import "OFInvalidArgumentException.h" -#import "OFMalformedXMLException.h" -#import "OFUnboundNamespaceException.h" -#import "OFUnsupportedVersionException.h" - -int _OFString_Serialization_reference; - -@implementation OFString (Serialization) -- (id)objectByDeserializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *root; - OFString *version; - OFArray *elements; - id object; - - root = [OFXMLElement elementWithXMLString: self]; - - version = [root attributeForName: @"version"].stringValue; - if (version == nil) - @throw [OFInvalidArgumentException exception]; - - if (version.unsignedLongLongValue != 1) - @throw [OFUnsupportedVersionException - exceptionWithVersion: version]; - - elements = [root elementsForNamespace: OFSerializationNS]; - - if (elements.count != 1) - @throw [OFInvalidArgumentException exception]; - - object = [[elements.firstObject objectByDeserializing] retain]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end Index: src/OFString+XMLEscaping.h ================================================================== --- src/OFString+XMLEscaping.h +++ src/OFString+XMLEscaping.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+XMLEscaping.m ================================================================== --- src/OFString+XMLEscaping.m +++ src/OFString+XMLEscaping.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+XMLUnescaping.h ================================================================== --- src/OFString+XMLUnescaping.h +++ src/OFString+XMLUnescaping.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString+XMLUnescaping.m ================================================================== --- src/OFString+XMLUnescaping.m +++ src/OFString+XMLUnescaping.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -35,11 +35,10 @@ # include #endif #include "OFObject.h" #ifdef __OBJC__ -# import "OFSerialization.h" # import "OFJSONRepresentation.h" # import "OFMessagePackRepresentation.h" #endif OF_ASSUME_NONNULL_BEGIN @@ -134,19 +133,19 @@ #endif #ifdef __OBJC__ @class OFArray OF_GENERIC(ObjectType); @class OFCharacterSet; -@class OFURI; +@class OFIRI; /** * @class OFString OFString.h ObjFW/OFString.h * * @brief A class for handling strings. */ @interface OFString: OFObject + OFJSONRepresentation, OFMessagePackRepresentation> /** * @brief The length of the string in Unicode codepoints. */ @property (readonly, nonatomic) size_t length; @@ -155,11 +154,11 @@ * * The result is valid until the autorelease pool is released. If you want to * use the result outside the scope of the current autorelease pool, you have to * copy it. */ -@property (readonly, nonatomic) const char *UTF8String OF_RETURNS_INNER_POINTER; +@property (readonly, nonatomic) const char *UTF8String; /** * @brief The number of bytes the string needs in UTF-8 encoding. */ @property (readonly, nonatomic) size_t UTF8StringLength; @@ -232,12 +231,11 @@ * use the result outside the scope of the current autorelease pool, you have to * copy it. * * The returned string is *not* null-terminated. */ -@property (readonly, nonatomic) const OFUnichar *characters - OF_RETURNS_INNER_POINTER; +@property (readonly, nonatomic) const OFUnichar *characters; /** * @brief The string in UTF-16 encoding with native byte order. * * The result is valid until the autorelease pool is released. If you want to @@ -244,12 +242,11 @@ * use the result outside the scope of the current autorelease pool, you have to * copy it. * * The returned string is null-terminated. */ -@property (readonly, nonatomic) const OFChar16 *UTF16String - OF_RETURNS_INNER_POINTER; +@property (readonly, nonatomic) const OFChar16 *UTF16String; /** * @brief The length of the string in UTF-16 characters. */ @property (readonly, nonatomic) size_t UTF16StringLength; @@ -261,12 +258,11 @@ * use the result outside the scope of the current autorelease pool, you have to * copy it. * * The returned string is null-terminated. */ -@property (readonly, nonatomic) const OFChar32 *UTF32String - OF_RETURNS_INNER_POINTER; +@property (readonly, nonatomic) const OFChar32 *UTF32String; /** * @brief The string with leading whitespaces deleted. */ @property (readonly, nonatomic) OFString *stringByDeletingLeadingWhitespaces; @@ -553,34 +549,34 @@ + (instancetype)stringWithContentsOfFile: (OFString *)path encoding: (OFStringEncoding)encoding; # endif /** - * @brief Creates a new OFString with the contents of the specified URI. + * @brief Creates a new OFString with the contents of the specified IRI. * - * If the URI's scheme is file, it tries UTF-8 encoding. + * If the IRI's scheme is file, it tries UTF-8 encoding. * - * If the URI's scheme is http(s), it tries to detect the encoding from the HTTP + * If the IRI's scheme is http(s), it tries to detect the encoding from the HTTP * headers. If it could not detect the encoding using the HTTP headers, it tries * UTF-8. * - * @param URI The URI to the contents for the string + * @param IRI The IRI to the contents for the string * @return A new autoreleased OFString * @throw OFInvalidEncodingException The string is not in the expected encoding */ -+ (instancetype)stringWithContentsOfURI: (OFURI *)URI; ++ (instancetype)stringWithContentsOfIRI: (OFIRI *)IRI; /** - * @brief Creates a new OFString with the contents of the specified URI in the + * @brief Creates a new OFString with the contents of the specified IRI in the * specified encoding. * - * @param URI The URI to the contents for the string + * @param IRI The IRI to the contents for the string * @param encoding The encoding to assume * @return A new autoreleased OFString * @throw OFInvalidEncodingException The string is not in the specified encoding */ -+ (instancetype)stringWithContentsOfURI: (OFURI *)URI ++ (instancetype)stringWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; /** * @brief Initializes an already allocated OFString from a UTF-8 encoded C * string. @@ -847,34 +843,34 @@ encoding: (OFStringEncoding)encoding; # endif /** * @brief Initializes an already allocated OFString with the contents of the - * specified URI. + * specified IRI. * - * If the URI's scheme is file, it tries UTF-8 encoding. + * If the IRI's scheme is file, it tries UTF-8 encoding. * - * If the URI's scheme is http(s), it tries to detect the encoding from the HTTP + * If the IRI's scheme is http(s), it tries to detect the encoding from the HTTP * headers. If it could not detect the encoding using the HTTP headers, it tries * UTF-8. * - * @param URI The URI to the contents for the string + * @param IRI The IRI to the contents for the string * @return An initialized OFString * @throw OFInvalidEncodingException The string is not in the expected encoding */ -- (instancetype)initWithContentsOfURI: (OFURI *)URI; +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI; /** * @brief Initializes an already allocated OFString with the contents of the - * specified URI in the specified encoding. + * specified IRI in the specified encoding. * - * @param URI The URI to the contents for the string + * @param IRI The IRI to the contents for the string * @param encoding The encoding to assume * @return An initialized OFString * @throw OFInvalidEncodingException The string is not in the specified encoding */ -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; /** * @brief Writes the OFString into the specified C string with the specified * encoding. @@ -918,12 +914,11 @@ * @param encoding The encoding for the C string * @return The OFString as a C string in the specified encoding * @throw OFInvalidEncodingException The string cannot be represented in the * specified encoding */ -- (const char *)cStringWithEncoding: (OFStringEncoding)encoding - OF_RETURNS_INNER_POINTER; +- (const char *)cStringWithEncoding: (OFStringEncoding)encoding; /** * @brief Returns the OFString as a C string in the specified encoding, * replacing characters that cannot be represented in the specified * encoding with a question mark. @@ -933,12 +928,11 @@ * copy it. * * @param encoding The encoding for the C string * @return The OFString as a C string in the specified encoding */ -- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding - OF_RETURNS_INNER_POINTER; +- (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding; /** * @brief Returns the number of bytes the string needs in the specified * encoding. * @@ -1256,12 +1250,11 @@ * * @param byteOrder The byte order for the UTF-16 encoding * @return The string in UTF-16 encoding with the specified byte order * @throw OFInvalidEncodingException The string cannot be represented in UTF-16 */ -- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder - OF_RETURNS_INNER_POINTER; +- (const OFChar16 *)UTF16StringWithByteOrder: (OFByteOrder)byteOrder; /** * @brief Returns the string in UTF-32 encoding with the specified byte order. * * The result is valid until the autorelease pool is released. If you want to @@ -1271,12 +1264,11 @@ * The returned string is null-terminated. * * @param byteOrder The byte order for the UTF-32 encoding * @return The string in UTF-32 encoding with the specified byte order */ -- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder - OF_RETURNS_INNER_POINTER; +- (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder; /** * @brief Returns the string as OFData with the specified encoding. * * @param encoding The encoding to use for the returned OFData @@ -1305,25 +1297,25 @@ */ - (void)writeToFile: (OFString *)path encoding: (OFStringEncoding)encoding; # endif /** - * @brief Writes the string to the specified URI using UTF-8 encoding. + * @brief Writes the string to the specified IRI using UTF-8 encoding. * - * @param URI The URI to write to + * @param IRI The IRI to write to */ -- (void)writeToURI: (OFURI *)URI; +- (void)writeToIRI: (OFIRI *)IRI; /** - * @brief Writes the string to the specified URI using the specified encoding. + * @brief Writes the string to the specified IRI using the specified encoding. * - * @param URI The URI to write to - * @param encoding The encoding to use to write the string to the URI + * @param IRI The IRI to write to + * @param encoding The encoding to use to write the string to the IRI * @throw OFInvalidEncodingException The string cannot be represented in the * specified encoding */ -- (void)writeToURI: (OFURI *)URI encoding: (OFStringEncoding)encoding; +- (void)writeToIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding; # ifdef OF_HAVE_BLOCKS /** * Enumerates all lines in the receiver using the specified block. * @@ -1376,11 +1368,10 @@ # ifdef OF_HAVE_FILES # import "OFString+PathAdditions.h" # endif # import "OFString+PercentEncoding.h" # import "OFString+PropertyListParsing.h" -# import "OFString+Serialization.h" # import "OFString+XMLEscaping.h" # import "OFString+XMLUnescaping.h" #endif #if defined(__OBJC__) && !defined(NSINTEGER_DEFINED) && !__has_feature(modules) Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,11 +20,11 @@ #include #include #include #include -#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) +#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE) # include #endif #ifdef HAVE_XLOCALE_H # include #endif @@ -37,18 +37,17 @@ #import "OFDictionary.h" #ifdef OF_HAVE_FILES # import "OFFile.h" # import "OFFileManager.h" #endif +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFLocale.h" #import "OFStream.h" #import "OFSystemInfo.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFUTF8String.h" #import "OFUTF8String+Private.h" -#import "OFXMLElement.h" #import "OFGetItemAttributesFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" @@ -80,11 +79,11 @@ static struct { Class isa; } placeholder; -#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) +#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE) static locale_t cLocale; #endif @interface OFString () - (size_t)of_getCString: (char *)cString @@ -133,11 +132,10 @@ #ifdef OF_HAVE_FILES _OFString_PathAdditions_reference = 1; #endif _OFString_PercentEncoding_reference = 1; _OFString_PropertyListParsing_reference = 1; - _OFString_Serialization_reference = 1; _OFString_XMLEscaping_reference = 1; _OFString_XMLUnescaping_reference = 1; } void @@ -580,27 +578,22 @@ return (id)[[OFUTF8String alloc] initWithContentsOfFile: path encoding: encoding]; } #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI { - return (id)[[OFUTF8String alloc] initWithContentsOfURI: URI]; + return (id)[[OFUTF8String alloc] initWithContentsOfIRI: IRI]; } -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { - return (id)[[OFUTF8String alloc] initWithContentsOfURI: URI + return (id)[[OFUTF8String alloc] initWithContentsOfIRI: IRI encoding: encoding]; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - return (id)[[OFUTF8String alloc] initWithSerialization: element]; -} - - (instancetype)retain { return self; } @@ -625,11 +618,11 @@ if (self != [OFString class]) return; placeholder.isa = [OFStringPlaceholder class]; -#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) +#if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE) if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) @throw [OFInitializationFailedException exceptionWithClass: self]; #endif } @@ -794,19 +787,19 @@ return [[[self alloc] initWithContentsOfFile: path encoding: encoding] autorelease]; } #endif -+ (instancetype)stringWithContentsOfURI: (OFURI *)URI ++ (instancetype)stringWithContentsOfIRI: (OFIRI *)IRI { - return [[[self alloc] initWithContentsOfURI: URI] autorelease]; + return [[[self alloc] initWithContentsOfIRI: IRI] autorelease]; } -+ (instancetype)stringWithContentsOfURI: (OFURI *)URI ++ (instancetype)stringWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { - return [[[self alloc] initWithContentsOfURI: URI + return [[[self alloc] initWithContentsOfIRI: IRI encoding: encoding] autorelease]; } - (instancetype)init { @@ -1047,24 +1040,24 @@ return self; } #endif -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI { - return [self initWithContentsOfURI: URI + return [self initWithContentsOfIRI: IRI encoding: OFStringEncodingAutodetect]; } -- (instancetype)initWithContentsOfURI: (OFURI *)URI +- (instancetype)initWithContentsOfIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFData *data; @try { - data = [OFData dataWithContentsOfURI: URI]; + data = [OFData dataWithContentsOfIRI: IRI]; } @catch (id e) { [self release]; @throw e; } @@ -1074,40 +1067,10 @@ self = [self initWithCString: data.items encoding: encoding length: data.count * data.itemSize]; - objc_autoreleasePoolPop(pool); - - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool = objc_autoreleasePoolPush(); - OFString *stringValue; - - @try { - if (![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - if ([self isKindOfClass: [OFMutableString class]]) { - if (![element.name isEqual: @"OFMutableString"]) - @throw [OFInvalidArgumentException exception]; - } else { - if (![element.name isEqual: @"OFString"]) - @throw [OFInvalidArgumentException exception]; - } - - stringValue = element.stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithString: stringValue]; - objc_autoreleasePoolPop(pool); return self; } @@ -1680,32 +1643,10 @@ - (OFString *)description { return [[self copy] autorelease]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - OFString *className; - - if ([self isKindOfClass: [OFMutableString class]]) - className = @"OFMutableString"; - else - className = @"OFString"; - - element = [OFXMLElement elementWithName: className - namespace: OFSerializationNS - stringValue: self]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } @@ -2424,11 +2365,11 @@ if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame) return NAN; if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame) return -NAN; -#ifdef HAVE_STRTOF_L +#if defined(HAVE_STRTOF_L) || defined(HAVE_USELOCALE) const char *UTF8String = self.UTF8String; #else /* * If we have no strtof_l, we have no other choice but to replace "." * with the locale's decimal point. @@ -2440,12 +2381,16 @@ #endif char *endPtr = NULL; float value; errno = 0; -#ifdef HAVE_STRTOF_L +#if defined(HAVE_STRTOF_L) value = strtof_l(UTF8String, &endPtr, cLocale); +#elif defined(HAVE_USELOCALE) + locale_t previousLocale = uselocale(cLocale); + value = strtof(UTF8String, &endPtr); + uselocale(previousLocale); #else value = strtof(UTF8String, &endPtr); #endif if (value == HUGE_VALF && errno == ERANGE) @@ -2477,11 +2422,11 @@ if ([stripped caseInsensitiveCompare: @"NAN"] == OFOrderedSame) return NAN; if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame) return -NAN; -#ifdef HAVE_STRTOD_L +#if defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE) const char *UTF8String = self.UTF8String; #else /* * If we have no strtod_l, we have no other choice but to replace "." * with the locale's decimal point. @@ -2493,12 +2438,16 @@ #endif char *endPtr = NULL; double value; errno = 0; -#ifdef HAVE_STRTOD_L +#if defined(HAVE_STRTOD_L) value = strtod_l(UTF8String, &endPtr, cLocale); +#elif defined(HAVE_USELOCALE) + locale_t previousLocale = uselocale(cLocale); + value = strtod(UTF8String, &endPtr); + uselocale(previousLocale); #else value = strtod(UTF8String, &endPtr); #endif if (value == HUGE_VAL && errno == ERANGE) @@ -2722,21 +2671,21 @@ [file writeString: self encoding: encoding]; objc_autoreleasePoolPop(pool); } #endif -- (void)writeToURI: (OFURI *)URI +- (void)writeToIRI: (OFIRI *)IRI { - [self writeToURI: URI encoding: OFStringEncodingUTF8]; + [self writeToIRI: IRI encoding: OFStringEncodingUTF8]; } -- (void)writeToURI: (OFURI *)URI encoding: (OFStringEncoding)encoding +- (void)writeToIRI: (OFIRI *)IRI encoding: (OFStringEncoding)encoding { void *pool = objc_autoreleasePoolPush(); OFStream *stream; - stream = [OFURIHandler openItemAtURI: URI mode: @"w"]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: @"w"]; [stream writeString: self encoding: encoding]; objc_autoreleasePoolPop(pool); } Index: src/OFSubarray.h ================================================================== --- src/OFSubarray.h +++ src/OFSubarray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSubarray.m ================================================================== --- src/OFSubarray.m +++ src/OFSubarray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSubprocess.h ================================================================== --- src/OFSubprocess.h +++ src/OFSubprocess.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFSubprocess.m ================================================================== --- src/OFSubprocess.m +++ src/OFSubprocess.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/OFSystemInfo+NetworkInterfaces.h Index: src/OFSystemInfo+NetworkInterfaces.h ================================================================== --- src/OFSystemInfo+NetworkInterfaces.h +++ src/OFSystemInfo+NetworkInterfaces.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFSystemInfo.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @brief A dictionary describing a network interface, as returned by + * @ref networkInterfaces. + * + * Keys are of type @ref OFNetworkInterfaceKey. + */ +typedef OFDictionary OF_GENERIC(OFString *, id) *OFNetworkInterface; + +/** + * @brief A key of an @ref OFNetworkInterface. + * + * Possible values are: + * + * * @ref OFNetworkInterfaceIndex + */ +typedef OFConstantString *OFNetworkInterfaceKey; + +/** + * @brief The index of a network interface. + * + * This maps to an @ref OFNumber. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIndex; + +/** + * @brief The hardware address of a network interface. + * + * This maps to an @ref OFData. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceHardwareAddress; + +/** + * @brief The IPv4 addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIPv4Addresses; + +#ifdef OF_HAVE_IPV6 +/** + * @brief The IPv6 addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIPv6Addresses; +#endif + +#ifdef OF_HAVE_IPX +/** + * @brief The IPX addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceIPXAddresses; +#endif + +#ifdef OF_HAVE_APPLETALK +/** + * @brief The AppleTalk addresses of a network interface. + * + * This maps to an @ref OFData of @ref OFSocketAddress. + */ +extern OFNetworkInterfaceKey OFNetworkInterfaceAppleTalkAddresses; +#endif + +@interface OFSystemInfo (NetworkInterfaces) + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nullable, nonatomic) + OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *networkInterfaces; +#endif + +/** + * @brief Returns the available (though not necessarily configured) network + * interfaces. + * + * @return The available network interfaces + */ ++ (nullable OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *) + networkInterfaces; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSystemInfo+NetworkInterfaces.m Index: src/OFSystemInfo+NetworkInterfaces.m ================================================================== --- src/OFSystemInfo+NetworkInterfaces.m +++ src/OFSystemInfo+NetworkInterfaces.m @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFSystemInfo.h" + +OFNetworkInterfaceKey OFNetworkInterfaceIndex = @"OFNetworkInterfaceIndex"; +OFNetworkInterfaceKey OFNetworkInterfaceHardwareAddress = + @"OFNetworkInterfaceHardwareAddress"; +OFNetworkInterfaceKey OFNetworkInterfaceIPv4Addresses = + @"OFNetworkInterfaceIPv4Addresses"; +#ifdef OF_HAVE_IPV6 +OFNetworkInterfaceKey OFNetworkInterfaceIPv6Addresses = + @"OFNetworkInterfaceIPv6Addresses"; +#endif +#ifdef OF_HAVE_IPX +OFNetworkInterfaceKey OFNetworkInterfaceIPXAddresses = + @"OFNetworkInterfaceIPXAddresses"; +#endif +#ifdef OF_HAVE_APPLETALK +OFNetworkInterfaceKey OFNetworkInterfaceAppleTalkAddresses = + @"OFNetworkInterfaceAppleTalkAddresses"; +#endif + +#ifdef OF_WINDOWS +# include "platform/Windows/OFSystemInfo+NetworkInterfaces.m" +#else +# include "platform/POSIX/OFSystemInfo+NetworkInterfaces.m" +#endif Index: src/OFSystemInfo.h ================================================================== --- src/OFSystemInfo.h +++ src/OFSystemInfo.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,12 @@ #import "OFObject.h" #import "OFString.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFDictionary OF_GENERIC(KeyType, ObjectType); +@class OFIRI; /** * @class OFSystemInfo OFSystemInfo.h ObjFW/OFSystemInfo.h * * @brief A class for querying information about the system. @@ -34,17 +35,19 @@ @property (class, readonly, nonatomic) unsigned short ObjFWVersionMajor; @property (class, readonly, nonatomic) unsigned short ObjFWVersionMinor; @property (class, readonly, nullable, nonatomic) OFString *operatingSystemName; @property (class, readonly, nullable, nonatomic) OFString *operatingSystemVersion; -@property (class, readonly, nullable, nonatomic) OFURI *userDataURI; -@property (class, readonly, nullable, nonatomic) OFURI *userConfigURI; -@property (class, readonly, nullable, nonatomic) OFURI *temporaryDirectoryURI; +@property (class, readonly, nullable, nonatomic) OFIRI *userDataIRI; +@property (class, readonly, nullable, nonatomic) OFIRI *userConfigIRI; +@property (class, readonly, nullable, nonatomic) OFIRI *temporaryDirectoryIRI; @property (class, readonly, nullable, nonatomic) OFString *CPUVendor; @property (class, readonly, nullable, nonatomic) OFString *CPUModel; -# if defined(OF_X86_64) || defined(OF_X86) || defined(DOXYGEN) +# if defined(OF_AMD64) || defined(OF_X86) || defined(DOXYGEN) @property (class, readonly, nonatomic) bool supportsMMX; +@property (class, readonly, nonatomic) bool supports3DNow; +@property (class, readonly, nonatomic) bool supportsEnhanced3DNow; @property (class, readonly, nonatomic) bool supportsSSE; @property (class, readonly, nonatomic) bool supportsSSE2; @property (class, readonly, nonatomic) bool supportsSSE3; @property (class, readonly, nonatomic) bool supportsSSSE3; @property (class, readonly, nonatomic) bool supportsSSE41; @@ -124,11 +127,11 @@ * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory.@n * On AmigaOS and MorphOS, it returns `PROGDIR:`. * * @return The path where user data for the application can be stored */ -+ (nullable OFURI *)userDataURI; ++ (nullable OFIRI *)userDataIRI; /** * @brief Returns the path where user configuration for the application can be * stored. * @@ -139,11 +142,11 @@ * On Haiku, it uses the `B_USER_SETTINGS_DIRECTORY` directory. * On AmigaOS and MorphOS, it returns `PROGDIR:`. * * @return The path where user configuration for the application can be stored */ -+ (nullable OFURI *)userConfigURI; ++ (nullable OFIRI *)userConfigIRI; /** * @brief Returns a path where temporary files for can be stored. * * If possible, returns a temporary directory for the user, otherwise returns a @@ -157,11 +160,11 @@ * On Haiku, it uses the `B_SYSTEM_TEMP_DIRECTORY` directory. * On AmigaOS and MorphOS, it returns `T:`. * * @return A path where temporary files can be stored */ -+ (nullable OFURI *)temporaryDirectoryURI; ++ (nullable OFIRI *)temporaryDirectoryIRI; /** * @brief Returns the vendor of the CPU. * * If the vendor could not be determined, `nil` is returned instead. @@ -177,26 +180,44 @@ * * @return The model of the CPU */ + (nullable OFString *)CPUModel; -#if defined(OF_X86_64) || defined(OF_X86) || defined(DOXYGEN) +#if defined(OF_AMD64) || defined(OF_X86) || defined(DOXYGEN) /** * @brief Returns whether the CPU supports MMX. * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports MMX */ + (bool)supportsMMX; +/** + * @brief Returns whether the CPU supports 3DNow!. + * + * @note This method is only available on AMD64 and x86. + * + * @return Whether the CPU supports 3DNow! + */ ++ (bool)supports3DNow; + +/** + * @brief Returns whether the CPU supports enhanced 3DNow!. + * + * @note This method is only available on AMD64 and x86. + * + * @return Whether the CPU supports enhanced 3DNow! + */ ++ (bool)supportsEnhanced3DNow; + /** * @brief Returns whether the CPU supports SSE. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSE */ + (bool)supportsSSE; @@ -203,11 +224,11 @@ /** * @brief Returns whether the CPU supports SSE2. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSE2 */ + (bool)supportsSSE2; @@ -214,11 +235,11 @@ /** * @brief Returns whether the CPU supports SSE3. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSE3 */ + (bool)supportsSSE3; @@ -225,11 +246,11 @@ /** * @brief Returns whether the CPU supports SSSE3. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSSE3 */ + (bool)supportsSSSE3; @@ -236,11 +257,11 @@ /** * @brief Returns whether the CPU supports SSE4.1. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSE4.1 */ + (bool)supportsSSE41; @@ -247,11 +268,11 @@ /** * @brief Returns whether the CPU supports SSE4.2. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports SSE4.2 */ + (bool)supportsSSE42; @@ -258,11 +279,11 @@ /** * @brief Returns whether the CPU supports AVX. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports AVX */ + (bool)supportsAVX; @@ -269,29 +290,29 @@ /** * @brief Returns whether the CPU supports AVX2. * * @warning This method only checks CPU support and assumes OS support! * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports AVX2 */ + (bool)supportsAVX2; /** * @brief Returns whether the CPU supports AES-NI. * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports AES-NI */ + (bool)supportsAESNI; /** * @brief Returns whether the CPU supports Intel SHA Extensions. * - * @note This method is only available on x86 and x86_64. + * @note This method is only available on AMD64 and x86. * * @return Whether the CPU supports Intel SHA Extensions */ + (bool)supportsSHAExtensions; #endif @@ -321,5 +342,9 @@ + (instancetype)alloc OF_UNAVAILABLE; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END + +#ifdef OF_HAVE_SOCKETS +# import "OFSystemInfo+NetworkInterfaces.h" +#endif Index: src/OFSystemInfo.m ================================================================== --- src/OFSystemInfo.m +++ src/OFSystemInfo.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -29,12 +29,14 @@ #if defined(OF_MACOS) || defined(OF_IOS) || defined(OF_NETBSD) # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include +# undef Class #endif #if defined(OF_AMIGAOS4) # include #elif defined(OF_MORPHOS) @@ -44,28 +46,37 @@ #ifdef OF_NINTENDO_SWITCH # define id nx_id # import # undef nx_id #endif + +#ifdef OF_DJGPP +# include +#endif #import "OFSystemInfo.h" #import "OFApplication.h" #import "OFArray.h" +#import "OFData.h" #import "OFDictionary.h" +#ifdef OF_HAVE_FILES + #import "OFFile.h" +#endif +#import "OFIRI.h" #import "OFLocale.h" +#import "OFNumber.h" #import "OFOnce.h" #import "OFString.h" -#import "OFURI.h" + +#import "OFInvalidFormatException.h" +#import "OFOpenItemFailedException.h" #if defined(OF_MACOS) || defined(OF_IOS) # ifdef HAVE_SYSDIR_H # include # endif #endif -#ifdef OF_WINDOWS -# include -#endif #ifdef OF_HAIKU # include #endif #ifdef OF_QNX # include @@ -99,11 +110,11 @@ NSSearchPathDirectory, NSSearchPathDomainMask); extern NSSearchPathEnumerationState NSGetNextSearchPathEnumeration( NSSearchPathEnumerationState, char *); #endif -#if defined(OF_X86_64) || defined(OF_X86) +#if defined(OF_AMD64) || defined(OF_X86) struct X86Regs { uint32_t eax, ebx, ecx, edx; }; #endif @@ -129,26 +140,32 @@ operatingSystemName = @"MorphOS"; #elif defined(OF_AMIGAOS4) operatingSystemName = @"AmigaOS 4"; #elif defined(OF_WII) operatingSystemName = @"Nintendo Wii"; +#elif defined(OF_WII_U) + operatingSystemName = @"Nintendo Wii U"; #elif defined(NINTENDO_3DS) operatingSystemName = @"Nintendo 3DS"; #elif defined(OF_NINTENDO_DS) operatingSystemName = @"Nintendo DS"; +#elif defined(OF_NINTENDO_SWITCH) + operatingSystemName = @"Nintendo Switch"; #elif defined(OF_PSP) operatingSystemName = @"PlayStation Portable"; -#elif defined(OF_MSDOS) - operatingSystemName = @"MS-DOS"; +#elif defined(OF_DJGPP) + operatingSystemName = [[OFString alloc] + initWithCString: _os_flavor + encoding: OFStringEncodingASCII]; #elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) - struct utsname utsname; + struct utsname name; - if (uname(&utsname) != 0) + if (uname(&name) != 0) return; operatingSystemName = [[OFString alloc] - initWithCString: utsname.sysname + initWithCString: name.sysname encoding: [OFLocale encoding]]; #endif } static void @@ -228,44 +245,47 @@ /* TODO */ #elif defined(OF_AMIGAOS) operatingSystemVersion = [[OFString alloc] initWithFormat: @"Kickstart %u.%u", SysBase->LibNode.lib_Version, SysBase->SoftVer]; +#elif defined(OF_DJGPP) + operatingSystemVersion = [[OFString alloc] + initWithFormat: @"%u.%u", _osmajor, _osminor]; #elif defined(OF_WII) || defined(NINTENDO_3DS) || defined(OF_NINTENDO_DS) || \ - defined(OF_PSP) || defined(OF_MSDOS) + defined(OF_PSP) /* Intentionally nothing */ #elif defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) - struct utsname utsname; + struct utsname name; - if (uname(&utsname) != 0) + if (uname(&name) != 0) return; operatingSystemVersion = [[OFString alloc] - initWithCString: utsname.release + initWithCString: name.release encoding: [OFLocale encoding]]; #endif } #ifdef OF_NINTENDO_SWITCH -static OFURI *tmpFSURI = nil; +static OFIRI *tmpFSIRI = nil; static void mountTmpFS(void) { if (R_SUCCEEDED(fsdevMountTemporaryStorage("tmpfs"))) - tmpFSURI = [[OFURI alloc] initFileURIWithPath: @"tmpfs:/" + tmpFSIRI = [[OFIRI alloc] initFileIRIWithPath: @"tmpfs:/" isDirectory: true]; } #endif -#if defined(OF_X86_64) || defined(OF_X86) +#if defined(OF_AMD64) || defined(OF_X86) static OF_INLINE struct X86Regs OF_CONST_FUNC x86CPUID(uint32_t eax, uint32_t ecx) { struct X86Regs regs; -# if defined(OF_X86_64) && defined(__GNUC__) +# if defined(OF_AMD64) && defined(__GNUC__) __asm__ ( "cpuid" : "=a"(regs.eax), "=b"(regs.ebx), "=c"(regs.ecx), "=d"(regs.edx) : "a"(eax), "c"(ecx) ); @@ -366,11 +386,11 @@ OFOnce(&onceControl, initOperatingSystemVersion); return operatingSystemVersion; } -+ (OFURI *)userDataURI ++ (OFIRI *)userDataIRI { #ifdef OF_HAVE_FILES # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; @@ -408,59 +428,59 @@ [path insertString: home atIndex: 0]; } [path makeImmutable]; - return [OFURI fileURIWithPath: path isDirectory: true]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; # elif defined(OF_WINDOWS) OFDictionary *env = [OFApplication environment]; OFString *appData; if ((appData = [env objectForKey: @"APPDATA"]) == nil) return nil; - return [OFURI fileURIWithPath: appData isDirectory: true]; + return [OFIRI fileIRIWithPath: appData isDirectory: true]; # elif defined(OF_HAIKU) char pathC[PATH_MAX]; if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, pathC, PATH_MAX) != B_OK) return nil; - return [OFURI fileURIWithPath: [OFString stringWithUTF8String: pathC] + return [OFIRI fileIRIWithPath: [OFString stringWithUTF8String: pathC] isDirectory: true]; # elif defined(OF_AMIGAOS) - return [OFURI fileURIWithPath: @"PROGDIR:" isDirectory: true]; + return [OFIRI fileIRIWithPath: @"PROGDIR:" isDirectory: true]; # else OFDictionary *env = [OFApplication environment]; OFString *var; - OFURI *URI; + OFIRI *IRI; void *pool; if ((var = [env objectForKey: @"XDG_DATA_HOME"]) != nil && var.length > 0) - return [OFURI fileURIWithPath: var isDirectory: true]; + return [OFIRI fileIRIWithPath: var isDirectory: true]; if ((var = [env objectForKey: @"HOME"]) == nil) return nil; pool = objc_autoreleasePoolPush(); var = [OFString pathWithComponents: [OFArray arrayWithObjects: var, @".local", @"share", nil]]; - URI = [[OFURI alloc] initFileURIWithPath: var isDirectory: true]; + IRI = [[OFIRI alloc] initFileIRIWithPath: var isDirectory: true]; objc_autoreleasePoolPop(pool); - return [URI autorelease]; + return [IRI autorelease]; # endif #else return nil; #endif } -+ (OFURI *)userConfigURI ++ (OFIRI *)userConfigIRI { #ifdef OF_HAVE_FILES # if defined(OF_MACOS) || defined(OF_IOS) char pathC[PATH_MAX]; OFMutableString *path; @@ -498,66 +518,66 @@ } [path appendString: @"/Preferences"]; [path makeImmutable]; - return [OFURI fileURIWithPath: path isDirectory: true]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; # elif defined(OF_WINDOWS) OFDictionary *env = [OFApplication environment]; OFString *appData; if ((appData = [env objectForKey: @"APPDATA"]) == nil) return nil; - return [OFURI fileURIWithPath: appData isDirectory: true]; + return [OFIRI fileIRIWithPath: appData isDirectory: true]; # elif defined(OF_HAIKU) char pathC[PATH_MAX]; if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, pathC, PATH_MAX) != B_OK) return nil; - return [OFURI fileURIWithPath: [OFString stringWithUTF8String: pathC] + return [OFIRI fileIRIWithPath: [OFString stringWithUTF8String: pathC] isDirectory: true]; # elif defined(OF_AMIGAOS) - return [OFURI fileURIWithPath: @"PROGDIR:" isDirectory: true]; + return [OFIRI fileIRIWithPath: @"PROGDIR:" isDirectory: true]; # else OFDictionary *env = [OFApplication environment]; OFString *var; if ((var = [env objectForKey: @"XDG_CONFIG_HOME"]) != nil && var.length > 0) - return [OFURI fileURIWithPath: var isDirectory: true]; + return [OFIRI fileIRIWithPath: var isDirectory: true]; if ((var = [env objectForKey: @"HOME"]) == nil) return nil; var = [var stringByAppendingPathComponent: @".config"]; - return [OFURI fileURIWithPath: var isDirectory: true]; + return [OFIRI fileIRIWithPath: var isDirectory: true]; # endif #else return nil; #endif } -+ (OFURI *)temporaryDirectoryURI ++ (OFIRI *)temporaryDirectoryIRI { #ifdef OF_HAVE_FILES # if defined(OF_MACOS) || defined(OF_IOS) char buffer[PATH_MAX]; size_t length; OFString *path; if ((length = confstr(_CS_DARWIN_USER_TEMP_DIR, buffer, PATH_MAX)) == 0) - return [OFURI fileURIWithPath: @"/tmp" isDirectory: true]; + return [OFIRI fileIRIWithPath: @"/tmp" isDirectory: true]; path = [OFString stringWithCString: buffer encoding: [OFLocale encoding] length: length - 1]; - return [OFURI fileURIWithPath: path isDirectory: true]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; # elif defined(OF_WINDOWS) OFString *path; if ([self isWindowsNT]) { wchar_t buffer[PATH_MAX]; @@ -574,53 +594,57 @@ path = [OFString stringWithCString: buffer encoding: [OFLocale encoding]]; } - return [OFURI fileURIWithPath: path isDirectory: true]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; # elif defined(OF_HAIKU) char pathC[PATH_MAX]; if (find_directory(B_SYSTEM_TEMP_DIRECTORY, 0, false, pathC, PATH_MAX) != B_OK) return nil; - return [OFURI fileURIWithPath: [OFString stringWithUTF8String: pathC] + return [OFIRI fileIRIWithPath: [OFString stringWithUTF8String: pathC] isDirectory: true]; # elif defined(OF_AMIGAOS) - return [OFURI fileURIWithPath: @"T:" isDirectory: true]; + return [OFIRI fileIRIWithPath: @"T:" isDirectory: true]; # elif defined(OF_MSDOS) OFString *path = [[OFApplication environment] objectForKey: @"TEMP"]; if (path == nil) return nil; - return [OFURI fileURIWithPath: path isDirectory: true]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; # elif defined(OF_MINT) - return [OFURI fileURIWithPath: @"u:\\tmp" isDirectory: true]; + return [OFIRI fileIRIWithPath: @"u:\\tmp" isDirectory: true]; # elif defined(OF_NINTENDO_SWITCH) static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, mountTmpFS); - return tmpFSURI; + return tmpFSIRI; # else - OFString *path = - [[OFApplication environment] objectForKey: @"XDG_RUNTIME_DIR"]; + OFString *path; + + path = [[OFApplication environment] objectForKey: @"XDG_RUNTIME_DIR"]; + if (path != nil) + return [OFIRI fileIRIWithPath: path isDirectory: true]; + path = [[OFApplication environment] objectForKey: @"TMPDIR"]; if (path != nil) - return [OFURI fileURIWithPath: path]; + return [OFIRI fileIRIWithPath: path isDirectory: true]; - return [OFURI fileURIWithPath: @"/tmp"]; + return [OFIRI fileIRIWithPath: @"/tmp" isDirectory: true]; # endif #else return nil; #endif } + (OFString *)CPUVendor { -#if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +#if (defined(OF_AMD64) || defined(OF_X86)) && defined(__GNUC__) struct X86Regs regs = x86CPUID(0, 0); uint32_t buffer[3]; if (regs.eax == 0) return nil; @@ -639,11 +663,11 @@ #endif } + (OFString *)CPUModel { -#if (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +#if (defined(OF_AMD64) || defined(OF_X86)) && defined(__GNUC__) struct X86Regs regs = x86CPUID(0x80000000, 0); uint32_t buffer[12]; size_t i; if (regs.eax < 0x80000004) @@ -698,15 +722,25 @@ #else return nil; #endif } -#if defined(OF_X86_64) || defined(OF_X86) +#if defined(OF_AMD64) || defined(OF_X86) + (bool)supportsMMX { return (x86CPUID(1, 0).edx & (1u << 23)); } + ++ (bool)supports3DNow +{ + return (x86CPUID(0x80000001, 0).edx & (1u << 31)); +} + ++ (bool)supportsEnhanced3DNow +{ + return (x86CPUID(0x80000001, 0).edx & (1u << 30)); +} + (bool)supportsSSE { return (x86CPUID(1, 0).edx & (1u << 25)); } Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -155,11 +155,11 @@ * @brief Connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to * @throw OFConnectIPSocketFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToHost: (OFString *)host port: (uint16_t)port; /** * @brief Asynchronously connects the OFTCPSocket to the specified destination. @@ -211,13 +211,13 @@ * * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for * IPv6 to bind to all. * @param port The port to bind to. If the port is 0, an unused port will be * chosen, which can be obtained using the return value. - * @return The port the socket was bound to + * @return The address the socket was bound to * @throw OFBindIPSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ -- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; +- (OFSocketAddress)bindToHost: (OFString *)host port: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFTCPSocket.m ================================================================== --- src/OFTCPSocket.m +++ src/OFTCPSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -41,11 +41,11 @@ #import "OFSocket+Private.h" #import "OFString.h" #import "OFTCPSocketSOCKS5Connector.h" #import "OFThread.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindIPSocketFailedException.h" #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFSetOptionFailedException.h" @@ -139,11 +139,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if ((_socket = socket( ((struct sockaddr *)&address->sockaddr)->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) { *errNo = OFSocketErrNo(); @@ -287,11 +287,11 @@ objc_autoreleasePoolPop(pool); } #endif -- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port +- (OFSocketAddress)bindToHost: (OFString *)host port: (uint16_t)port { const int one = 1; void *pool = objc_autoreleasePoolPush(); OFData *socketAddresses; OFSocketAddress address; @@ -298,11 +298,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if (_SOCKS5Host != nil) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; @@ -359,14 +359,12 @@ OFSocketAddressSetIPPort(&address, rnd); if ((ret = bind(_socket, (struct sockaddr *)&address.sockaddr, - address.length)) == 0) { - port = rnd; + address.length)) == 0) break; - } if (OFSocketErrNo() != EADDRINUSE) { int errNo = OFSocketErrNo(); closesocket(_socket); @@ -380,15 +378,10 @@ } } } #endif - objc_autoreleasePoolPop(pool); - - if (port > 0) - return port; - #if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) memset(&address, 0, sizeof(address)); address.length = (socklen_t)sizeof(address.sockaddr); if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, @@ -404,14 +397,16 @@ errNo: errNo]; } switch (((struct sockaddr *)&address.sockaddr)->sa_family) { case AF_INET: - return OFFromBigEndian16(address.sockaddr.in.sin_port); + address.family = OFSocketAddressFamilyIPv4; + break; # ifdef OF_HAVE_IPV6 case AF_INET6: - return OFFromBigEndian16(address.sockaddr.in6.sin6_port); + address.family = OFSocketAddressFamilyIPv6; + break; # endif default: closesocket(_socket); _socket = OFInvalidSocketHandle; @@ -419,18 +414,15 @@ exceptionWithHost: host port: port socket: self errNo: EAFNOSUPPORT]; } -#else - closesocket(_socket); - _socket = OFInvalidSocketHandle; - @throw [OFBindIPSocketFailedException exceptionWithHost: host - port: port - socket: self - errNo: EADDRNOTAVAIL]; #endif + + objc_autoreleasePoolPop(pool); + + return address; } #if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) - (void)setSendsKeepAlives: (bool)sendsKeepAlives { Index: src/OFTCPSocketSOCKS5Connector.h ================================================================== --- src/OFTCPSocketSOCKS5Connector.h +++ src/OFTCPSocketSOCKS5Connector.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTCPSocketSOCKS5Connector.m ================================================================== --- src/OFTCPSocketSOCKS5Connector.m +++ src/OFTCPSocketSOCKS5Connector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTLSKey.h ================================================================== --- src/OFTLSKey.h +++ src/OFTLSKey.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTLSKey.m ================================================================== --- src/OFTLSKey.m +++ src/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTLSStream.h ================================================================== --- src/OFTLSStream.h +++ src/OFTLSStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -127,11 +127,11 @@ * @brief Asynchronously performs the TLS client handshake for the specified * host and calls the delegate afterwards. * * @param host The host to perform the handshake with * @throw OFTLSHandshakeFailedException The TLS handshake failed - * @throw OFAlreadyConnectedException The handshake was already performed + * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host; /** * @brief Asynchronously performs the TLS client handshake for the specified @@ -138,21 +138,21 @@ * host and calls the delegate afterwards. * * @param host The host to perform the handshake with * @param runLoopMode The run loop mode in which to perform the async handshake * @throw OFTLSHandshakeFailedException The TLS handshake failed - * @throw OFAlreadyConnectedException The handshake was already performed + * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode; /** * @brief Performs the TLS client handshake for the specified host. * * @param host The host to perform the handshake with * @throw OFTLSHandshakeFailedException The TLS handshake failed - * @throw OFAlreadyConnectedException The handshake was already performed + * @throw OFAlreadyOpenException The handshake was already performed */ - (void)performClientHandshakeWithHost: (OFString *)host; @end #ifdef __cplusplus Index: src/OFTLSStream.m ================================================================== --- src/OFTLSStream.m +++ src/OFTLSStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTarArchive.h ================================================================== --- src/OFTarArchive.h +++ src/OFTarArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,12 +18,12 @@ #import "OFString.h" #import "OFTarArchiveEntry.h" OF_ASSUME_NONNULL_BEGIN +@class OFIRI; @class OFStream; -@class OFURI; /** * @class OFTarArchive OFTarArchive.h ObjFW/OFTarArchive.h * * @brief A class for accessing and manipulating tar archives. @@ -30,15 +30,11 @@ */ OF_SUBCLASSING_RESTRICTED @interface OFTarArchive: OFObject { OFStream *_stream; - enum OFTarArchiveMode { - OFTarArchiveModeRead, - OFTarArchiveModeWrite, - OFTarArchiveModeAppend - } _mode; + uint_least8_t _mode; OFStringEncoding _encoding; OFTarArchiveEntry *_Nullable _currentEntry; #ifdef OF_TAR_ARCHIVE_M @public #endif @@ -66,31 +62,31 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; /** * @brief Creates a new OFTarArchive object with the specified file. * - * @param URI The URI to the tar archive + * @param IRI The IRI to the tar archive * @param mode The mode for the tar file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return A new, autoreleased OFTarArchive * @throw OFInvalidFormatException The archive has an invalid format * @throw OFSeekFailedException The archive was open in append mode and seeking * failed */ -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode; ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** - * @brief Creates a URI for accessing a the specified file within the specified - * tar archive. + * @brief Creates an IRI for accessing a the specified file within the + * specified tar archive. * * @param path The path of the file within the archive - * @param URI The URI of the archive - * @return A URI for accessing the specified file within the specified tar + * @param IRI The IRI of the archive + * @return An IRI for accessing the specified file within the specified tar * archive */ -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI; ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFTarArchive object with the @@ -111,20 +107,20 @@ /** * @brief Initializes an already allocated OFTarArchive object with the * specified file. * - * @param URI The URI to the tar archive + * @param IRI The IRI to the tar archive * @param mode The mode for the tar file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return An initialized OFTarArchive * @throw OFInvalidFormatException The archive has an invalid format * @throw OFSeekFailedException The archive was open in append mode and seeking * failed */ -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode; +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** * @brief Returns the next entry from the tar archive or `nil` if all entries * have been read. * Index: src/OFTarArchive.m ================================================================== --- src/OFTarArchive.m +++ src/OFTarArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,23 +20,29 @@ #include #import "OFTarArchive.h" #import "OFTarArchiveEntry.h" #import "OFTarArchiveEntry+Private.h" -#import "OFArchiveURIHandler.h" +#import "OFArchiveIRIHandler.h" #import "OFDate.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFSeekableStream.h" #import "OFStream.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFTruncatedDataException.h" #import "OFWriteFailedException.h" + +enum { + modeRead, + modeWrite, + modeAppend +}; OF_DIRECT_MEMBERS @interface OFTarArchiveFileReadStream: OFStream { OFTarArchive *_archive; @@ -72,18 +78,18 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode { - return [[[self alloc] initWithURI: URI mode: mode] autorelease]; + return [[[self alloc] initWithIRI: IRI mode: mode] autorelease]; } -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI { - return OFArchiveURIHandlerURIForFileInArchive(@"tar", path, URI); + return OFArchiveIRIHandlerIRIForFileInArchive(@"tar", path, IRI); } - (instancetype)init { OF_INVALID_INIT_METHOD @@ -95,19 +101,19 @@ @try { _stream = [stream retain]; if ([mode isEqual: @"r"]) - _mode = OFTarArchiveModeRead; + _mode = modeRead; else if ([mode isEqual: @"w"]) - _mode = OFTarArchiveModeWrite; + _mode = modeWrite; else if ([mode isEqual: @"a"]) - _mode = OFTarArchiveModeAppend; + _mode = modeAppend; else @throw [OFInvalidArgumentException exception]; - if (_mode == OFTarArchiveModeAppend) { + if (_mode == modeAppend) { uint32_t buffer[1024 / sizeof(uint32_t)]; bool empty = true; if (![_stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; @@ -134,20 +140,20 @@ } return self; } -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); OFStream *stream; @try { if ([mode isEqual: @"a"]) - stream = [OFURIHandler openItemAtURI: URI mode: @"r+"]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: @"r+"]; else - stream = [OFURIHandler openItemAtURI: URI mode: mode]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: mode]; } @catch (id e) { [self release]; @throw e; } @@ -170,12 +176,25 @@ - (OFTarArchiveEntry *)nextEntry { uint32_t buffer[512 / sizeof(uint32_t)]; bool empty = true; - if (_mode != OFTarArchiveModeRead) + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; + + if (_currentEntry != nil && _lastReturnedStream == nil) { + /* + * No read stream was created since the last call to + * -[nextEntry]. Create it so that we can properly skip the + * data. + */ + void *pool = objc_autoreleasePoolPush(); + + [self streamForReadingCurrentEntry]; + + objc_autoreleasePoolPop(pool); + } [_currentEntry release]; _currentEntry = nil; [(OFTarArchiveFileReadStream *)_lastReturnedStream of_skip]; @@ -212,11 +231,11 @@ return _currentEntry; } - (OFStream *)streamForReadingCurrentEntry { - if (_mode != OFTarArchiveModeRead) + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if (_currentEntry == nil) @throw [OFInvalidArgumentException exception]; @@ -230,11 +249,11 @@ return _lastReturnedStream; } - (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry { - if (_mode != OFTarArchiveModeWrite && _mode != OFTarArchiveModeAppend) + if (_mode != modeWrite && _mode != modeAppend) @throw [OFInvalidArgumentException exception]; @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { @@ -262,11 +281,11 @@ } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } _lastReturnedStream = nil; - if (_mode == OFTarArchiveModeWrite || _mode == OFTarArchiveModeAppend) { + if (_mode == modeWrite || _mode == modeAppend) { char buffer[1024]; memset(buffer, '\0', 1024); [_stream writeBuffer: buffer length: 1024]; } Index: src/OFTarArchiveEntry+Private.h ================================================================== --- src/OFTarArchiveEntry+Private.h +++ src/OFTarArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFThread+Private.h ================================================================== --- src/OFThread+Private.h +++ src/OFThread+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -30,12 +30,14 @@ #include "unistd_wrapper.h" #include "platform.h" #ifdef OF_AMIGAOS +# define Class IntuitionClass # include # include +# undef Class #endif #ifdef OF_WII # define nanosleep ogc_nanosleep # include Index: src/OFTimer+Private.h ================================================================== --- src/OFTimer+Private.h +++ src/OFTimer+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTriple.h ================================================================== --- src/OFTriple.h +++ src/OFTriple.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFTriple.m ================================================================== --- src/OFTriple.m +++ src/OFTriple.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFUDPSocket+Private.h ================================================================== --- src/OFUDPSocket+Private.h +++ src/OFUDPSocket+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,10 +17,9 @@ OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface OFUDPSocket () -- (uint16_t)of_bindToAddress: (OFSocketAddress *)address - extraType: (int)extraType; +- (void)of_bindToAddress: (OFSocketAddress *)address extraType: (int)extraType; @end OF_ASSUME_NONNULL_END Index: src/OFUDPSocket.h ================================================================== --- src/OFUDPSocket.h +++ src/OFUDPSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -69,13 +69,13 @@ * * @param host The host to bind to. Use `@"0.0.0.0"` for IPv4 or `@"::"` for * IPv6 to bind to all. * @param port The port to bind to. If the port is 0, an unused port will be * chosen, which can be obtained using the return value. - * @return The port the socket was bound to + * @return The address the socket was bound to * @throw OFBindIPSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @throw OFAlreadyOpenException The socket is already bound */ -- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port; +- (OFSocketAddress)bindToHost: (OFString *)host port: (uint16_t)port; @end OF_ASSUME_NONNULL_END Index: src/OFUDPSocket.m ================================================================== --- src/OFUDPSocket.m +++ src/OFUDPSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -32,23 +32,25 @@ #import "OFData.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFThread.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindIPSocketFailedException.h" @implementation OFUDPSocket @dynamic delegate; -- (uint16_t)of_bindToAddress: (OFSocketAddress *)address - extraType: (int)extraType OF_DIRECT +- (void)of_bindToAddress: (OFSocketAddress *)address + extraType: (int)extraType OF_DIRECT { - void *pool = objc_autoreleasePoolPush(); - uint16_t port; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; +#endif +#if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) + OFString *host; + uint16_t port; #endif if ((_socket = socket( ((struct sockaddr *)&address->sockaddr)->sa_family, SOCK_DGRAM | SOCK_CLOEXEC | extraType, 0)) == OFInvalidSocketHandle) @@ -100,11 +102,11 @@ break; if (OFSocketErrNo() != EADDRINUSE) { int errNo = OFSocketErrNo(); OFString *host = OFSocketAddressString(address); - port = OFSocketAddressIPPort(address); + uint16_t port = OFSocketAddressIPPort(address); closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindIPSocketFailedException @@ -115,16 +117,14 @@ } } } #endif - objc_autoreleasePoolPop(pool); - - if ((port = OFSocketAddressIPPort(address)) > 0) - return port; - #if !defined(OF_HPUX) && !defined(OF_WII) && !defined(OF_NINTENDO_3DS) + host = OFSocketAddressString(address); + port = OFSocketAddressIPPort(address); + memset(address, 0, sizeof(*address)); address->length = (socklen_t)sizeof(address->sockaddr); if (OFGetSockName(_socket, (struct sockaddr *)&address->sockaddr, &address->length) != 0) { @@ -131,64 +131,56 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindIPSocketFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressIPPort(address) - socket: self - errNo: errNo]; + @throw [OFBindIPSocketFailedException exceptionWithHost: host + port: port + socket: self + errNo: errNo]; } switch (((struct sockaddr *)&address->sockaddr)->sa_family) { case AF_INET: - return OFFromBigEndian16(address->sockaddr.in.sin_port); + address->family = OFSocketAddressFamilyIPv4; + break; # ifdef OF_HAVE_IPV6 case AF_INET6: - return OFFromBigEndian16(address->sockaddr.in6.sin6_port); + address->family = OFSocketAddressFamilyIPv6; + break; # endif default: closesocket(_socket); _socket = OFInvalidSocketHandle; @throw [OFBindIPSocketFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressIPPort(address) + exceptionWithHost: host + port: port socket: self errNo: EAFNOSUPPORT]; } -#else - closesocket(_socket); - _socket = OFInvalidSocketHandle; - - @throw [OFBindIPSocketFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressIPPort(address) - socket: self - errNo: EADDRNOTAVAIL]; #endif } -- (uint16_t)bindToHost: (OFString *)host port: (uint16_t)port +- (OFSocketAddress)bindToHost: (OFString *)host port: (uint16_t)port { void *pool = objc_autoreleasePoolPush(); OFData *socketAddresses; OFSocketAddress address; if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; socketAddresses = [[OFThread DNSResolver] resolveAddressesForHost: host addressFamily: OFSocketAddressFamilyAny]; address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; OFSocketAddressSetIPPort(&address, port); - port = [self of_bindToAddress: &address extraType: 0]; + [self of_bindToAddress: &address extraType: 0]; objc_autoreleasePoolPop(pool); - return port; + return address; } @end Index: src/OFUNIXDatagramSocket.h ================================================================== --- src/OFUNIXDatagramSocket.h +++ src/OFUNIXDatagramSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -64,11 +64,11 @@ * @brief Bind the socket to the specified path. * * @param path The path to bind to * @return The address on which this socket can be reached * @throw OFBindUNIXSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @throw OFAlreadyOpenException The socket is already bound */ - (OFSocketAddress)bindToPath: (OFString *)path; @end OF_ASSUME_NONNULL_END Index: src/OFUNIXDatagramSocket.m ================================================================== --- src/OFUNIXDatagramSocket.m +++ src/OFUNIXDatagramSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,11 +22,11 @@ #import "OFUNIXDatagramSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFString.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindUNIXSocketFailedException.h" @implementation OFUNIXDatagramSocket @dynamic delegate; @@ -36,11 +36,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeUNIX(path); if ((_socket = socket(address.sockaddr.un.sun_family, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) Index: src/OFUNIXStreamSocket.h ================================================================== --- src/OFUNIXStreamSocket.h +++ src/OFUNIXStreamSocket.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -53,20 +53,20 @@ /** * @brief Connects the OFUNIXStreamSocket to the specified destination. * * @param path The path to connect to * @throw OFConnectUNIXSocketFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToPath: (OFString *)path; /** * @brief Binds the socket to the specified host and port. * * @param path The path to bind to * @throw OFBindUNIXSocketFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)bindToPath: (OFString *)path; @end OF_ASSUME_NONNULL_END Index: src/OFUNIXStreamSocket.m ================================================================== --- src/OFUNIXStreamSocket.m +++ src/OFUNIXStreamSocket.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,11 +22,11 @@ #import "OFUNIXStreamSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFString.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFBindUNIXSocketFailedException.h" #import "OFConnectUNIXSocketFailedException.h" @implementation OFUNIXStreamSocket @dynamic delegate; @@ -37,11 +37,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeUNIX(path); if ((_socket = socket(address.sockaddr.un.sun_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) @@ -77,11 +77,11 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL) && defined(FD_CLOEXEC) int flags; #endif if (_socket != OFInvalidSocketHandle) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; address = OFSocketAddressMakeUNIX(path); if ((_socket = socket(address.sockaddr.un.sun_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) DELETED src/OFURI+Private.h Index: src/OFURI+Private.h ================================================================== --- src/OFURI+Private.h +++ src/OFURI+Private.h @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFURI.h" - -OF_ASSUME_NONNULL_BEGIN - -@interface OFURI () -- (instancetype)of_init OF_METHOD_FAMILY(init); -@end - -OF_ASSUME_NONNULL_END DELETED src/OFURI.h Index: src/OFURI.h ================================================================== --- src/OFURI.h +++ src/OFURI.h @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFObject.h" -#import "OFCharacterSet.h" -#import "OFSerialization.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFArray OF_GENERIC(ObjectType); -@class OFDictionary OF_GENERIC(KeyType, ObjectType); -@class OFNumber; -@class OFPair OF_GENERIC(FirstType, SecondType); -@class OFString; - -/** - * @class OFURI OFURI.h ObjFW/OFURI.h - * - * @brief A class for parsing URIs as per RFC 3986 and accessing parts of it. - */ -@interface OFURI: OFObject -{ - OFString *_scheme; - OFString *_Nullable _percentEncodedHost; - OFNumber *_Nullable _port; - OFString *_Nullable _percentEncodedUser; - OFString *_Nullable _percentEncodedPassword; - OFString *_percentEncodedPath; - OFString *_Nullable _percentEncodedQuery; - OFString *_Nullable _percentEncodedFragment; - OF_RESERVE_IVARS(OFURI, 4) -} - -/** - * @brief The scheme part of the URI. - */ -@property (readonly, copy, nonatomic) OFString *scheme; - -/** - * @brief The host part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *host; - -/** - * @brief The host part of the URI in percent-encoded form. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *percentEncodedHost; - -/** - * @brief The port part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFNumber *port; - -/** - * @brief The user part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *user; - -/** - * @brief The user part of the URI in percent-encoded form. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *percentEncodedUser; - -/** - * @brief The password part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *password; - -/** - * @brief The password part of the URI in percent-encoded form. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *percentEncodedPassword; - -/** - * @brief The path part of the URI. - */ -@property (readonly, copy, nonatomic) OFString *path; - -/** - * @brief The path part of the URI in percent-encoded form. - */ -@property (readonly, copy, nonatomic) OFString *percentEncodedPath; - -/** - * @brief The path of the URI split into components. - * - * The first component must always be `/` to designate the root. - */ -@property (readonly, copy, nonatomic) - OFArray OF_GENERIC(OFString *) *pathComponents; - -/** - * @brief The last path component of the URI. - * - * Returns the empty string if the path is the root. - */ -@property (readonly, copy, nonatomic) OFString *lastPathComponent; - -/** - * @brief The query part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *query; - -/** - * @brief The query part of the URI in percent-encoded form. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *percentEncodedQuery; - -/** - * @brief The query part of the URI as an array. - * - * For example, a query like `key1=value1&key2=value2` would correspond to the - * following array: - * - * @[ - * [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"], - * [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"], - * ] - * - * @throw OFInvalidFormatException The query is not in the correct format - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems; - -/** - * @brief The fragment part of the URI. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *fragment; - -/** - * @brief The fragment part of the URI in URI-encoded form. - */ -@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) - OFString *percentEncodedFragment; - -/** - * @brief The URI as a string. - */ -@property (readonly, nonatomic) OFString *string; - -/** - * @brief The URI with relative subpaths resolved. - */ -@property (readonly, nonatomic) OFURI *URIByStandardizingPath; - -#ifdef OF_HAVE_FILES -/** - * @brief The local file system representation for a file URI. - * - * @note This only exists for URIs with the file scheme and throws an exception - * otherwise. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - OFString *fileSystemRepresentation; -#endif - -/** - * @brief Creates a new URI with the specified string. - * - * @param string A string describing a URI - * @return A new, autoreleased OFURI - * @throw OFInvalidFormatException The specified string is not a valid URI - * string - */ -+ (instancetype)URIWithString: (OFString *)string; - -/** - * @brief Creates a new URI with the specified string relative to the - * specified URI. - * - * @param string A string describing a relative or absolute URI - * @param URI An URI to which the string is relative - * @return A new, autoreleased OFURI - * @throw OFInvalidFormatException The specified string is not a valid URI - * string - */ -+ (instancetype)URIWithString: (OFString *)string relativeToURI: (OFURI *)URI; - -#ifdef OF_HAVE_FILES -/** - * @brief Creates a new URI with the specified local file path. - * - * If a directory exists at the specified path, a slash is appended if there is - * no slash yet. - * - * @param path The local file path - * @return A new, autoreleased OFURI - * @throw OFInvalidFormatException The specified path is not a valid path - */ -+ (instancetype)fileURIWithPath: (OFString *)path; - -/** - * @brief Creates a new URI with the specified local file path. - * - * @param path The local file path - * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet - * @return An initialized OFURI - */ -+ (instancetype)fileURIWithPath: (OFString *)path - isDirectory: (bool)isDirectory; -#endif - -/** - * @brief Initializes an already allocated OFURI with the specified string. - * - * @param string A string describing a URI - * @return An initialized OFURI - * @throw OFInvalidFormatException The specified string is not a valid URI - * string - */ -- (instancetype)initWithString: (OFString *)string; - -/** - * @brief Initializes an already allocated OFURI with the specified string and - * relative URI. - * - * @param string A string describing a relative or absolute URI - * @param URI A URI to which the string is relative - * @return An initialized OFURI - * @throw OFInvalidFormatException The specified string is not a valid URI - * string - */ -- (instancetype)initWithString: (OFString *)string relativeToURI: (OFURI *)URI; - -#ifdef OF_HAVE_FILES -/** - * @brief Initializes an already allocated OFURI with the specified local file - * path. - * - * If a directory exists at the specified path, a slash is appended if there is - * no slash yet. - * - * @param path The local file path - * @return An initialized OFURI - * @throw OFInvalidFormatException The specified path is not a valid path - */ -- (instancetype)initFileURIWithPath: (OFString *)path; - -/** - * @brief Initializes an already allocated OFURI with the specified local file - * path. - * - * @param path The local file path - * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet - * @return An initialized OFURI - */ -- (instancetype)initFileURIWithPath: (OFString *)path - isDirectory: (bool)isDirectory; -#endif - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Returns a new URI with the specified path component appended. - * - * If the URI is a file URI, the file system is queried whether the appended - * component is a directory. - * - * @param component The path component to append. If it starts with the slash, - * the component is not appended, but replaces the path - * instead. - * @return A new URI with the specified path component appended - */ -- (OFURI *)URIByAppendingPathComponent: (OFString *)component; - -/** - * @brief Returns a new URI with the specified path component appended. - * - * @param component The path component to append. If it starts with the slash, - * the component is not appended, but replaces the path - * instead. - * @param isDirectory Whether the appended component is a directory, meaning - * that the URI path should have a trailing slash - * @return A new URI with the specified path component appended - */ -- (OFURI *)URIByAppendingPathComponent: (OFString *)component - isDirectory: (bool)isDirectory; -@end - -@interface OFCharacterSet (URICharacterSets) -#ifdef OF_HAVE_CLASS_PROPERTIES -@property (class, readonly, nonatomic) - OFCharacterSet *URISchemeAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIHostAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIUserAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIPasswordAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIPathAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIQueryAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIQueryKeyValueAllowedCharacterSet; -@property (class, readonly, nonatomic) - OFCharacterSet *URIFragmentAllowedCharacterSet; -#endif - -/** - * @brief Returns the characters allowed in the scheme part of a URI. - * - * @return The characters allowed in the scheme part of a URI. - */ -+ (OFCharacterSet *)URISchemeAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the host part of a URI. - * - * @return The characters allowed in the host part of a URI. - */ -+ (OFCharacterSet *)URIHostAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the user part of a URI. - * - * @return The characters allowed in the user part of a URI. - */ -+ (OFCharacterSet *)URIUserAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the password part of a URI. - * - * @return The characters allowed in the password part of a URI. - */ -+ (OFCharacterSet *)URIPasswordAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the path part of a URI. - * - * @return The characters allowed in the path part of a URI. - */ -+ (OFCharacterSet *)URIPathAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the query part of a URI. - * - * @return The characters allowed in the query part of a URI. - */ -+ (OFCharacterSet *)URIQueryAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in a key/value in the query part of a - * URI. - * - * @return The characters allowed in a key/value in the query part of a URI. - */ -+ (OFCharacterSet *)URIQueryKeyValueAllowedCharacterSet; - -/** - * @brief Returns the characters allowed in the fragment part of a URI. - * - * @return The characters allowed in the fragment part of a URI. - */ -+ (OFCharacterSet *)URIFragmentAllowedCharacterSet; -@end - -#ifdef __cplusplus -extern "C" { -#endif -extern bool OFURIIsIPv6Host(OFString *host); -extern void OFURIVerifyIsEscaped(OFString *, OFCharacterSet *, bool); -#ifdef __cplusplus -} -#endif - -OF_ASSUME_NONNULL_END - -#import "OFMutableURI.h" DELETED src/OFURI.m Index: src/OFURI.m ================================================================== --- src/OFURI.m +++ src/OFURI.m @@ -1,1277 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include -#include - -#import "OFURI.h" -#import "OFArray.h" -#import "OFDictionary.h" -#ifdef OF_HAVE_FILES -# import "OFFileManager.h" -# import "OFFileURIHandler.h" -#endif -#import "OFNumber.h" -#import "OFOnce.h" -#import "OFPair.h" -#import "OFString.h" -#import "OFXMLElement.h" - -#import "OFInvalidArgumentException.h" -#import "OFInvalidFormatException.h" -#import "OFOutOfMemoryException.h" - -@interface OFURIAllowedCharacterSetBase: OFCharacterSet -@end - -@interface OFURIAllowedCharacterSet: OFURIAllowedCharacterSetBase -@end - -@interface OFURISchemeAllowedCharacterSet: OFURIAllowedCharacterSetBase -@end - -@interface OFURIPathAllowedCharacterSet: OFURIAllowedCharacterSetBase -@end - -@interface OFURIQueryOrFragmentAllowedCharacterSet: OFURIAllowedCharacterSetBase -@end - -@interface OFURIQueryKeyValueAllowedCharacterSet: OFURIAllowedCharacterSetBase -@end - -OF_DIRECT_MEMBERS -@interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet -{ - OFCharacterSet *_characterSet; - bool (*_characterIsMember)(id, SEL, OFUnichar); -} - -- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; -@end - -static OFCharacterSet *URIAllowedCharacterSet = nil; -static OFCharacterSet *URISchemeAllowedCharacterSet = nil; -static OFCharacterSet *URIPathAllowedCharacterSet = nil; -static OFCharacterSet *URIQueryOrFragmentAllowedCharacterSet = nil; -static OFCharacterSet *URIQueryKeyValueAllowedCharacterSet = nil; - -static OFOnceControl URIAllowedCharacterSetOnce = OFOnceControlInitValue; -static OFOnceControl URIQueryOrFragmentAllowedCharacterSetOnce = - OFOnceControlInitValue; - -static void -initURIAllowedCharacterSet(void) -{ - URIAllowedCharacterSet = [[OFURIAllowedCharacterSet alloc] init]; -} - -static void -initURISchemeAllowedCharacterSet(void) -{ - URISchemeAllowedCharacterSet = - [[OFURISchemeAllowedCharacterSet alloc] init]; -} - -static void -initURIPathAllowedCharacterSet(void) -{ - URIPathAllowedCharacterSet = - [[OFURIPathAllowedCharacterSet alloc] init]; -} - -static void -initURIQueryOrFragmentAllowedCharacterSet(void) -{ - URIQueryOrFragmentAllowedCharacterSet = - [[OFURIQueryOrFragmentAllowedCharacterSet alloc] init]; -} - -static void -initURIQueryKeyValueAllowedCharacterSet(void) -{ - URIQueryKeyValueAllowedCharacterSet = - [[OFURIQueryKeyValueAllowedCharacterSet alloc] init]; -} - -bool -OFURIIsIPv6Host(OFString *host) -{ - const char *UTF8String = host.UTF8String; - bool hasColon = false; - - while (*UTF8String != '\0') { - if (!OFASCIIIsDigit(*UTF8String) && *UTF8String != ':' && - (*UTF8String < 'a' || *UTF8String > 'f') && - (*UTF8String < 'A' || *UTF8String > 'F')) - return false; - - if (*UTF8String == ':') - hasColon = true; - - UTF8String++; - } - - return hasColon; -} - -@implementation OFURIAllowedCharacterSetBase -- (instancetype)autorelease -{ - return self; -} - -- (instancetype)retain -{ - return self; -} - -- (void)release -{ -} - -- (unsigned int)retainCount -{ - return OFMaxRetainCount; -} -@end - -@implementation OFURIAllowedCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - return true; - default: - return false; - } -} -@end - -@implementation OFURISchemeAllowedCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '+': - case '-': - case '.': - return true; - default: - return false; - } -} -@end - -@implementation OFURIPathAllowedCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - case ':': - case '@': - case '/': - return true; - default: - return false; - } -} -@end - -@implementation OFURIQueryOrFragmentAllowedCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '&': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case '=': - case ':': - case '@': - case '/': - case '?': - return true; - default: - return false; - } -} -@end - -@implementation OFURIQueryKeyValueAllowedCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - if (character < CHAR_MAX && OFASCIIIsAlnum(character)) - return true; - - switch (character) { - case '-': - case '.': - case '_': - case '~': - case '!': - case '$': - case '\'': - case '(': - case ')': - case '*': - case '+': - case ',': - case ';': - case ':': - case '@': - case '/': - case '?': - return true; - default: - return false; - } -} -@end - -@implementation OFInvertedCharacterSetWithoutPercent -- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet -{ - self = [super init]; - - @try { - _characterSet = [characterSet retain]; - _characterIsMember = (bool (*)(id, SEL, OFUnichar)) - [_characterSet methodForSelector: - @selector(characterIsMember:)]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_characterSet release]; - - [super dealloc]; -} - -- (bool)characterIsMember: (OFUnichar)character -{ - return (character != '%' && !_characterIsMember(_characterSet, - @selector(characterIsMember:), character)); -} -@end - -void -OFURIVerifyIsEscaped(OFString *string, OFCharacterSet *characterSet, - bool allowPercent) -{ - void *pool = objc_autoreleasePoolPush(); - - if (allowPercent) - characterSet = [[[OFInvertedCharacterSetWithoutPercent alloc] - initWithCharacterSet: characterSet] autorelease]; - else - characterSet = characterSet.invertedSet; - - if ([string indexOfCharacterFromSet: characterSet] != OFNotFound) - @throw [OFInvalidFormatException exception]; - - objc_autoreleasePoolPop(pool); -} - -@implementation OFCharacterSet (URICharacterSets) -+ (OFCharacterSet *)URISchemeAllowedCharacterSet -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - OFOnce(&onceControl, initURISchemeAllowedCharacterSet); - - return URISchemeAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIHostAllowedCharacterSet -{ - OFOnce(&URIAllowedCharacterSetOnce, initURIAllowedCharacterSet); - - return URIAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIUserAllowedCharacterSet -{ - OFOnce(&URIAllowedCharacterSetOnce, initURIAllowedCharacterSet); - - return URIAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIPasswordAllowedCharacterSet -{ - OFOnce(&URIAllowedCharacterSetOnce, initURIAllowedCharacterSet); - - return URIAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIPathAllowedCharacterSet -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - OFOnce(&onceControl, initURIPathAllowedCharacterSet); - - return URIPathAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIQueryAllowedCharacterSet -{ - OFOnce(&URIQueryOrFragmentAllowedCharacterSetOnce, - initURIQueryOrFragmentAllowedCharacterSet); - - return URIQueryOrFragmentAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIQueryKeyValueAllowedCharacterSet -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - OFOnce(&onceControl, initURIQueryKeyValueAllowedCharacterSet); - - return URIQueryKeyValueAllowedCharacterSet; -} - -+ (OFCharacterSet *)URIFragmentAllowedCharacterSet -{ - OFOnce(&URIQueryOrFragmentAllowedCharacterSetOnce, - initURIQueryOrFragmentAllowedCharacterSet); - - return URIQueryOrFragmentAllowedCharacterSet; -} -@end - -@implementation OFURI -+ (instancetype)URI -{ - return [[[self alloc] init] autorelease]; -} - -+ (instancetype)URIWithString: (OFString *)string -{ - return [[[self alloc] initWithString: string] autorelease]; -} - -+ (instancetype)URIWithString: (OFString *)string - relativeToURI: (OFURI *)URI -{ - return [[[self alloc] initWithString: string - relativeToURI: URI] autorelease]; -} - -#ifdef OF_HAVE_FILES -+ (instancetype)fileURIWithPath: (OFString *)path -{ - return [[[self alloc] initFileURIWithPath: path] autorelease]; -} - -+ (instancetype)fileURIWithPath: (OFString *)path - isDirectory: (bool)isDirectory -{ - return [[[self alloc] initFileURIWithPath: path - isDirectory: isDirectory] autorelease]; -} -#endif - -static void -parseUserInfo(OFURI *self, const char *UTF8String, size_t length) -{ - const char *colon; - - if ((colon = memchr(UTF8String, ':', length)) != NULL) { - self->_percentEncodedUser = [[OFString alloc] - initWithUTF8String: UTF8String - length: colon - UTF8String]; - self->_percentEncodedPassword = [[OFString alloc] - initWithUTF8String: colon + 1 - length: length - (colon - UTF8String) - 1]; - - OFURIVerifyIsEscaped(self->_percentEncodedPassword, - [OFCharacterSet URIPasswordAllowedCharacterSet], true); - } else - self->_percentEncodedUser = [[OFString alloc] - initWithUTF8String: UTF8String - length: length]; - - OFURIVerifyIsEscaped(self->_percentEncodedUser, - [OFCharacterSet URIUserAllowedCharacterSet], true); -} - -static void -parseHostPort(OFURI *self, const char *UTF8String, size_t length) -{ - OFString *portString; - - if (*UTF8String == '[') { - const char *end = memchr(UTF8String, ']', length); - - if (end == NULL) - @throw [OFInvalidFormatException exception]; - - for (const char *iter = UTF8String + 1; iter < end; iter++) - if (!OFASCIIIsDigit(*iter) && *iter != ':' && - (*iter < 'a' || *iter > 'f') && - (*iter < 'A' || *iter > 'F')) - @throw [OFInvalidFormatException exception]; - - self->_percentEncodedHost = [[OFString alloc] - initWithUTF8String: UTF8String - length: end - UTF8String + 1]; - - length -= (end - UTF8String) + 1; - UTF8String = end + 1; - } else { - const char *colon = memchr(UTF8String, ':', length); - - if (colon != NULL) { - self->_percentEncodedHost = [[OFString alloc] - initWithUTF8String: UTF8String - length: colon - UTF8String]; - - length -= colon - UTF8String; - UTF8String = colon; - } else { - self->_percentEncodedHost = [[OFString alloc] - initWithUTF8String: UTF8String - length: length]; - - UTF8String += length; - length = 0; - } - - OFURIVerifyIsEscaped(self->_percentEncodedHost, - [OFCharacterSet URIHostAllowedCharacterSet], true); - } - - if (length == 0) - return; - - if (length <= 1 || *UTF8String != ':') - @throw [OFInvalidFormatException exception]; - - UTF8String++; - length--; - - for (size_t i = 0; i < length; i++) - if (!OFASCIIIsDigit(UTF8String[i])) - @throw [OFInvalidFormatException exception]; - - portString = [OFString stringWithUTF8String: UTF8String length: length]; - - if (portString.unsignedLongLongValue > 65535) - @throw [OFInvalidFormatException exception]; - - self->_port = [[OFNumber alloc] initWithUnsignedShort: - (unsigned short)portString.unsignedLongLongValue]; -} - -static size_t -parseAuthority(OFURI *self, const char *UTF8String, size_t length) -{ - size_t ret; - const char *slash, *at; - - if ((slash = memchr(UTF8String, '/', length)) != NULL) - length = slash - UTF8String; - - ret = length; - - if ((at = memchr(UTF8String, '@', length)) != NULL) { - parseUserInfo(self, UTF8String, at - UTF8String); - - length -= at - UTF8String + 1; - UTF8String = at + 1; - } - - parseHostPort(self, UTF8String, length); - - return ret; -} - -static void -parsePathQueryFragment(const char *UTF8String, size_t length, - OFString **pathString, OFString **queryString, OFString **fragmentString) -{ - const char *fragment, *query; - - if ((fragment = memchr(UTF8String, '#', length)) != NULL) { - *fragmentString = [OFString - stringWithUTF8String: fragment + 1 - length: length - (fragment - UTF8String) - 1]; - - OFURIVerifyIsEscaped(*fragmentString, - [OFCharacterSet URIQueryAllowedCharacterSet], true); - - length = fragment - UTF8String; - } - - if ((query = memchr(UTF8String, '?', length)) != NULL) { - *queryString = [OFString - stringWithUTF8String: query + 1 - length: length - (query - UTF8String) - 1]; - - OFURIVerifyIsEscaped(*queryString, - [OFCharacterSet URIFragmentAllowedCharacterSet], true); - - length = query - UTF8String; - } - - *pathString = [OFString stringWithUTF8String: UTF8String - length: length]; - - OFURIVerifyIsEscaped(*pathString, - [OFCharacterSet URIQueryAllowedCharacterSet], true); -} - -- (instancetype)initWithString: (OFString *)string -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *UTF8String = string.UTF8String; - size_t length = string.UTF8StringLength; - const char *colon; - OFString *path, *query = nil, *fragment = nil; - - if ((colon = strchr(UTF8String, ':')) == NULL || - colon - UTF8String < 1 || !OFASCIIIsAlpha(UTF8String[0])) - @throw [OFInvalidFormatException exception]; - - _scheme = [[[OFString stringWithUTF8String: UTF8String - length: colon - UTF8String] - lowercaseString] copy]; - - OFURIVerifyIsEscaped(_scheme, - [OFCharacterSet URISchemeAllowedCharacterSet], false); - - length -= colon - UTF8String + 1; - UTF8String = colon + 1; - - if (length >= 2 && UTF8String[0] == '/' && - UTF8String[1] == '/') { - size_t authorityLength; - - UTF8String += 2; - length -= 2; - - authorityLength = parseAuthority(self, - UTF8String, length); - - UTF8String += authorityLength; - length -= authorityLength; - - if (length > 0) - OFEnsure(UTF8String[0] == '/'); - } - - parsePathQueryFragment(UTF8String, length, - &path, &query, &fragment); - _percentEncodedPath = [path copy]; - _percentEncodedQuery = [query copy]; - _percentEncodedFragment = [fragment copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -static bool -isAbsolute(OFString *string) -{ - void *pool = objc_autoreleasePoolPush(); - - @try { - const char *UTF8String = string.UTF8String; - size_t length = string.UTF8StringLength; - - if (length < 1) - return false; - - if (!OFASCIIIsAlpha(UTF8String[0])) - return false; - - for (size_t i = 1; i < length; i++) { - if (UTF8String[i] == ':') - return true; - - if (!OFASCIIIsAlnum(UTF8String[i]) && - UTF8String[i] != '+' && UTF8String[i] != '-' && - UTF8String[i] != '.') - return false; - } - } @finally { - objc_autoreleasePoolPop(pool); - } - - return false; -} - -static OFString * -merge(OFString *base, OFString *path) -{ - OFMutableArray *components; - - if (base.length == 0) - base = @"/"; - - components = [[[base componentsSeparatedByString: @"/"] - mutableCopy] autorelease]; - - if (components.count == 1) - [components addObject: path]; - else - [components replaceObjectAtIndex: components.count - 1 - withObject: path]; - - return [components componentsJoinedByString: @"/"]; -} - -- (instancetype)initWithString: (OFString *)string relativeToURI: (OFURI *)URI -{ - bool absolute; - - @try { - absolute = isAbsolute(string); - } @catch (id e) { - [self release]; - @throw e; - } - - if (absolute) - return [self initWithString: string]; - - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - const char *UTF8String = string.UTF8String; - size_t length = string.UTF8StringLength; - bool hasAuthority = false; - OFString *path, *query = nil, *fragment = nil; - - _scheme = [URI->_scheme copy]; - - if (length >= 2 && UTF8String[0] == '/' && - UTF8String[1] == '/') { - size_t authorityLength; - - hasAuthority = true; - - UTF8String += 2; - length -= 2; - - authorityLength = parseAuthority(self, - UTF8String, length); - - UTF8String += authorityLength; - length -= authorityLength; - - if (length > 0) - OFEnsure(UTF8String[0] == '/'); - } else { - _percentEncodedHost = [URI->_percentEncodedHost copy]; - _port = [URI->_port copy]; - _percentEncodedUser = [URI->_percentEncodedUser copy]; - _percentEncodedPassword = - [URI->_percentEncodedPassword copy]; - } - - parsePathQueryFragment(UTF8String, length, - &path, &query, &fragment); - _percentEncodedFragment = [fragment copy]; - - if (hasAuthority) { - _percentEncodedPath = [path copy]; - _percentEncodedQuery = [query copy]; - } else { - if (path.length == 0) { - _percentEncodedPath = - [URI->_percentEncodedPath copy]; - _percentEncodedQuery = (query != nil - ? [query copy] - : [URI->_percentEncodedQuery copy]); - } else { - if ([path hasPrefix: @"/"]) - _percentEncodedPath = [path copy]; - else - _percentEncodedPath = [merge( - URI->_percentEncodedPath, path) - copy]; - - _percentEncodedQuery = [query copy]; - } - } - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -#ifdef OF_HAVE_FILES -- (instancetype)initFileURIWithPath: (OFString *)path -{ - bool isDirectory; - - @try { - void *pool = objc_autoreleasePoolPush(); - isDirectory = [path of_isDirectoryPath]; - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initFileURIWithPath: path isDirectory: isDirectory]; - - return self; -} - -- (instancetype)initFileURIWithPath: (OFString *)path - isDirectory: (bool)isDirectory -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - OFString *percentEncodedHost = nil; - - if (!path.absolutePath) { - OFString *currentDirectoryPath = [OFFileManager - defaultManager].currentDirectoryPath; - - path = [currentDirectoryPath - stringByAppendingPathComponent: path]; - path = path.stringByStandardizingPath; - } - - path = [path of_pathToURIPathWithPercentEncodedHost: - &percentEncodedHost]; - _percentEncodedHost = [percentEncodedHost copy]; - - if (isDirectory && ![path hasSuffix: @"/"]) - path = [path stringByAppendingString: @"/"]; - - _scheme = @"file"; - _percentEncodedPath = [[path - stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIPathAllowedCharacterSet]] copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#endif - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)of_init -{ - return [super init]; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool = objc_autoreleasePoolPush(); - OFString *stringValue; - - @try { - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - stringValue = element.stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithString: stringValue]; - - objc_autoreleasePoolPop(pool); - - return self; -} - -- (void)dealloc -{ - [_scheme release]; - [_percentEncodedHost release]; - [_port release]; - [_percentEncodedUser release]; - [_percentEncodedPassword release]; - [_percentEncodedPath release]; - [_percentEncodedQuery release]; - [_percentEncodedFragment release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFURI *URI; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFURI class]]) - return false; - - URI = object; - - if (![URI->_scheme isEqual: _scheme]) - return false; - if (URI->_percentEncodedHost != _percentEncodedHost && - ![URI->_percentEncodedHost isEqual: _percentEncodedHost]) - return false; - if (URI->_port != _port && ![URI->_port isEqual: _port]) - return false; - if (URI->_percentEncodedUser != _percentEncodedUser && - ![URI->_percentEncodedUser isEqual: _percentEncodedUser]) - return false; - if (URI->_percentEncodedPassword != _percentEncodedPassword && - ![URI->_percentEncodedPassword isEqual: _percentEncodedPassword]) - return false; - if (![URI->_percentEncodedPath isEqual: _percentEncodedPath]) - return false; - if (URI->_percentEncodedQuery != _percentEncodedQuery && - ![URI->_percentEncodedQuery isEqual: _percentEncodedQuery]) - return false; - if (URI->_percentEncodedFragment != _percentEncodedFragment && - ![URI->_percentEncodedFragment isEqual: _percentEncodedFragment]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _scheme.hash); - OFHashAddHash(&hash, _percentEncodedHost.hash); - OFHashAddHash(&hash, _port.hash); - OFHashAddHash(&hash, _percentEncodedUser.hash); - OFHashAddHash(&hash, _percentEncodedPassword.hash); - OFHashAddHash(&hash, _percentEncodedPath.hash); - OFHashAddHash(&hash, _percentEncodedQuery.hash); - OFHashAddHash(&hash, _percentEncodedFragment.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)scheme -{ - return _scheme; -} - -- (OFString *)host -{ - if ([_percentEncodedHost hasPrefix: @"["] && - [_percentEncodedHost hasSuffix: @"]"]) { - OFString *host = [_percentEncodedHost substringWithRange: - OFMakeRange(1, _percentEncodedHost.length - 2)]; - - if (!OFURIIsIPv6Host(host)) - @throw [OFInvalidArgumentException exception]; - - return host; - } - - return _percentEncodedHost.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedHost -{ - return _percentEncodedHost; -} - -- (OFNumber *)port -{ - return _port; -} - -- (OFString *)user -{ - return _percentEncodedUser.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedUser -{ - return _percentEncodedUser; -} - -- (OFString *)password -{ - return _percentEncodedPassword.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedPassword -{ - return _percentEncodedPassword; -} - -- (OFString *)path -{ - return _percentEncodedPath.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedPath -{ - return _percentEncodedPath; -} - -- (OFArray *)pathComponents -{ - void *pool = objc_autoreleasePoolPush(); -#ifdef OF_HAVE_FILES - bool isFile = [_scheme isEqual: @"file"]; -#endif - OFMutableArray *ret; - size_t count; - -#ifdef OF_HAVE_FILES - if (isFile) { - OFString *path = [_percentEncodedPath - of_URIPathToPathWithPercentEncodedHost: nil]; - ret = [[path.pathComponents mutableCopy] autorelease]; - - if (![ret.firstObject isEqual: @"/"]) - [ret insertObject: @"/" atIndex: 0]; - } else -#endif - ret = [[[_percentEncodedPath componentsSeparatedByString: @"/"] - mutableCopy] autorelease]; - - count = ret.count; - - if (count > 0 && [ret.firstObject length] == 0) - [ret replaceObjectAtIndex: 0 withObject: @"/"]; - - for (size_t i = 0; i < count; i++) { - OFString *component = [ret objectAtIndex: i]; - -#ifdef OF_HAVE_FILES - if (isFile) - component = - [component of_pathComponentToURIPathComponent]; -#endif - - component = component.stringByRemovingPercentEncoding; - [ret replaceObjectAtIndex: i withObject: component]; - } - - [ret makeImmutable]; - [ret retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)lastPathComponent -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path = _percentEncodedPath; - const char *UTF8String, *lastComponent; - size_t length; - OFString *ret; - - if ([path isEqual: @"/"]) { - objc_autoreleasePoolPop(pool); - return @"/"; - } - - if ([path hasSuffix: @"/"]) - path = [path substringToIndex: path.length - 1]; - - UTF8String = lastComponent = path.UTF8String; - length = path.UTF8StringLength; - - for (size_t i = 1; i <= length; i++) { - if (UTF8String[length - i] == '/') { - lastComponent = UTF8String + (length - i) + 1; - break; - } - } - - ret = [OFString - stringWithUTF8String: lastComponent - length: length - (lastComponent - UTF8String)]; - ret = [ret.stringByRemovingPercentEncoding retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)query -{ - return _percentEncodedQuery.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedQuery -{ - return _percentEncodedQuery; -} - -- (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *)queryItems -{ - void *pool; - OFArray OF_GENERIC(OFString *) *pairs; - OFMutableArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) - *ret; - - if (_percentEncodedQuery == nil) - return nil; - - pool = objc_autoreleasePoolPush(); - pairs = [_percentEncodedQuery componentsSeparatedByString: @"&"]; - ret = [OFMutableArray arrayWithCapacity: pairs.count]; - - for (OFString *pair in pairs) { - OFArray *parts = [pair componentsSeparatedByString: @"="]; - OFString *name, *value; - - if (parts.count != 2) - @throw [OFInvalidFormatException exception]; - - name = [[parts objectAtIndex: 0] - stringByRemovingPercentEncoding]; - value = [[parts objectAtIndex: 1] - stringByRemovingPercentEncoding]; - - [ret addObject: [OFPair pairWithFirstObject: name - secondObject: value]]; - } - - [ret makeImmutable]; - [ret retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} - -- (OFString *)fragment -{ - return _percentEncodedFragment.stringByRemovingPercentEncoding; -} - -- (OFString *)percentEncodedFragment -{ - return _percentEncodedFragment; -} - -- (id)copy -{ - return [self retain]; -} - -- (id)mutableCopy -{ - OFURI *copy = [[OFMutableURI alloc] initWithScheme: _scheme]; - - @try { - copy->_percentEncodedHost = [_percentEncodedHost copy]; - copy->_port = [_port copy]; - copy->_percentEncodedUser = [_percentEncodedUser copy]; - copy->_percentEncodedPassword = [_percentEncodedPassword copy]; - copy->_percentEncodedPath = [_percentEncodedPath copy]; - copy->_percentEncodedQuery = [_percentEncodedQuery copy]; - copy->_percentEncodedFragment = [_percentEncodedFragment copy]; - } @catch (id e) { - [copy release]; - @throw e; - } - - return copy; -} - -- (OFString *)string -{ - OFMutableString *ret = [OFMutableString string]; - - [ret appendFormat: @"%@:", _scheme]; - - if (_percentEncodedHost != nil || _port != nil || - _percentEncodedUser != nil || _percentEncodedPassword != nil) - [ret appendString: @"//"]; - - if (_percentEncodedUser != nil && _percentEncodedPassword != nil) - [ret appendFormat: @"%@:%@@", - _percentEncodedUser, - _percentEncodedPassword]; - else if (_percentEncodedUser != nil) - [ret appendFormat: @"%@@", _percentEncodedUser]; - - if (_percentEncodedHost != nil) - [ret appendString: _percentEncodedHost]; - if (_port != nil) - [ret appendFormat: @":%@", _port]; - - [ret appendString: _percentEncodedPath]; - - if (_percentEncodedQuery != nil) - [ret appendFormat: @"?%@", _percentEncodedQuery]; - - if (_percentEncodedFragment != nil) - [ret appendFormat: @"#%@", _percentEncodedFragment]; - - [ret makeImmutable]; - - return ret; -} - -#ifdef OF_HAVE_FILES -- (OFString *)fileSystemRepresentation -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path; - - if (![_scheme isEqual: @"file"]) - @throw [OFInvalidArgumentException exception]; - - if (![_percentEncodedPath hasPrefix: @"/"]) - @throw [OFInvalidFormatException exception]; - - path = [self.path - of_URIPathToPathWithPercentEncodedHost: _percentEncodedHost]; - - [path retain]; - - objc_autoreleasePoolPop(pool); - - return [path autorelease]; -} -#endif - -- (OFURI *)URIByAppendingPathComponent: (OFString *)component -{ - OFMutableURI *URI = [[self mutableCopy] autorelease]; - [URI appendPathComponent: component]; - [URI makeImmutable]; - return URI; -} - -- (OFURI *)URIByAppendingPathComponent: (OFString *)component - isDirectory: (bool)isDirectory -{ - OFMutableURI *URI = [[self mutableCopy] autorelease]; - [URI appendPathComponent: component isDirectory: isDirectory]; - [URI makeImmutable]; - return URI; -} - -- (OFURI *)URIByStandardizingPath -{ - OFMutableURI *URI = [[self mutableCopy] autorelease]; - [URI standardizePath]; - [URI makeImmutable]; - return URI; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@>", - self.class, self.string]; -} - -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS - stringValue: self.string]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} -@end DELETED src/OFURIHandler.h Index: src/OFURIHandler.h ================================================================== --- src/OFURIHandler.h +++ src/OFURIHandler.h @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFFileManager.h" -#import "OFObject.h" -#import "OFString.h" - -OF_ASSUME_NONNULL_BEGIN - -@class OFArray OF_GENERIC(ObjectType); -@class OFDate; -@class OFStream; -@class OFURI; - -/** - * @class OFURIHandler OFURIHandler.h ObjFW/OFURIHandler.h - * - * @brief A handler for a URI scheme. - */ -@interface OFURIHandler: OFObject -{ - OFString *_scheme; - OF_RESERVE_IVARS(OFURIHandler, 4) -} - -/** - * @brief The scheme this OFURIHandler handles. - */ -@property (readonly, nonatomic) OFString *scheme; - -/** - * @brief Registers the specified class as the handler for the specified scheme. - * - * If the same class is specified for two schemes, one instance of it is - * created per scheme. - * - * @param class_ The class to register as the handler for the specified scheme - * @param scheme The scheme for which to register the handler - * @return Whether the class was successfully registered. If a handler for the - * same scheme is already registered, registration fails. - */ -+ (bool)registerClass: (Class)class_ forScheme: (OFString *)scheme; - -/** - * @brief Returns the handler for the specified URI. - * - * @return The handler for the specified URI. - * @throw OFUnsupportedProtocolException The specified URI is not supported - */ -+ (OFURIHandler *)handlerForURI: (OFURI *)URI; - -/** - * @brief Opens the item at the specified URI. - * - * @param URI The URI of the item which should be opened - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * @n - * Mode | Description - * ---------------|------------------------------------- - * `r` | Read-only - * `r+` | Read-write - * `w` | Write-only, create or truncate - * `wx` | Write-only, create or fail, exclusive - * `w+` | Read-write, create or truncate - * `w+x` | Read-write, create or fail, exclusive - * `a` | Write-only, create or append - * `a+` | Read-write, create or append - * @n - * The handler is allowed to not implement all modes and is also - * allowed to implement additional, scheme-specific modes. - * @return The opened stream if it was successfully opened - * @throw OFOpenItemFailedException Opening the item failed - * @throw OFUnsupportedProtocolException The specified URI is not supported - */ -+ (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes the handler for the specified scheme. - * - * @param scheme The scheme to initialize for - * @return An initialized URI handler - */ -- (instancetype)initWithScheme: (OFString *)scheme OF_DESIGNATED_INITIALIZER; - -/** - * @brief Opens the item at the specified URI. - * - * @param URI The URI of the item which should be opened - * @param mode The mode in which the file should be opened.@n - * Possible modes are: - * @n - * Mode | Description - * ---------------|------------------------------------- - * `r` | Read-only - * `r+` | Read-write - * `w` | Write-only, create or truncate - * `wx` | Write-only, create or fail, exclusive - * `w+` | Read-write, create or truncate - * `w+x` | Read-write, create or fail, exclusive - * `a` | Write-only, create or append - * `a+` | Read-write, create or append - * @n - * The handler is allowed to not implement all modes and is also - * allowed to implement additional, scheme-specific modes. - * @return The opened stream if it was successfully opened - * @throw OFOpenItemFailedException Opening the item failed - * @throw OFUnsupportedProtocolException The specified URI is not supported by - * the handler - */ -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode; - -/** - * @brief Returns the attributes for the item at the specified URI. - * - * @param URI The URI to return the attributes for - * @return A dictionary of attributes for the specified URI, with the keys of - * type @ref OFFileAttributeKey - */ -- (OFFileAttributes)attributesOfItemAtURI: (OFURI *)URI; - -/** - * @brief Sets the attributes for the item at the specified URI. - * - * All attributes not part of the dictionary are left unchanged. - * - * @param attributes The attributes to set for the specified URI - * @param URI The URI of the item to set the attributes for - */ -- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURI: (OFURI *)URI; - -/** - * @brief Checks whether a file exists at the specified URI. - * - * @param URI The URI to check - * @return A boolean whether there is a file at the specified URI - */ -- (bool)fileExistsAtURI: (OFURI *)URI; - -/** - * @brief Checks whether a directory exists at the specified URI. - * - * @param URI The URI to check - * @return A boolean whether there is a directory at the specified URI - */ -- (bool)directoryExistsAtURI: (OFURI *)URI; - -/** - * @brief Creates a directory at the specified URI. - * - * @param URI The URI of the directory to create - */ -- (void)createDirectoryAtURI: (OFURI *)URI; - -/** - * @brief Returns an array with the URIs of the items in the specified - * directory. - * - * @note `.` and `..` are not part of the returned array. - * - * @param URI The URI to the directory whose items should be returned - * @return An array with the URIs of the items in the specified directory - */ -- (OFArray OF_GENERIC(OFURI *) *)contentsOfDirectoryAtURI: (OFURI *)URI; - -/** - * @brief Removes the item at the specified URI. - * - * If the item at the specified URI is a directory, it is removed recursively. - * - * @param URI The URI to the item which should be removed - */ -- (void)removeItemAtURI: (OFURI *)URI; - -/** - * @brief Creates a hard link for the specified item. - * - * The destination URI must have a full path, which means it must include the - * name of the item. - * - * This method is not available for all URIs. - * - * @param source The URI to the item for which a link should be created - * @param destination The URI to the item which should link to the source - */ -- (void)linkItemAtURI: (OFURI *)source toURI: (OFURI *)destination; - -/** - * @brief Creates a symbolic link for an item. - * - * The destination URI must have a full path, which means it must include the - * name of the item. - * - * This method is not available for all URIs. - * - * @note On Windows, this requires at least Windows Vista and administrator - * privileges! - * - * @param URI The URI to the item which should symbolically link to the target - * @param target The target of the symbolic link - */ -- (void)createSymbolicLinkAtURI: (OFURI *)URI - withDestinationPath: (OFString *)target; - -/** - * @brief Tries to efficiently copy an item. If a copy would only be possible - * by reading the entire item and then writing it, it returns false. - * - * The destination URI must have a full path, which means it must include the - * name of the item. - * - * If an item already exists, the copy operation fails. This is also the case - * if a directory is copied and an item already exists in the destination - * directory. - * - * @param source The file, directory or symbolic link to copy - * @param destination The destination URI - * @return True if an efficient copy was performed, false if an efficient copy - * was not possible. Note that errors while performing a copy are - * reported via exceptions and not by returning false! - */ -- (bool)copyItemAtURI: (OFURI *)source toURI: (OFURI *)destination; - -/** - * @brief Tries to efficiently move an item. If a move would only be possible - * by copying the source and deleting it, it returns false. - * - * The destination URI must have a full path, which means it must include the - * name of the item. - * - * If the destination is on a different logical device or uses a different - * scheme, an efficient move is not possible and false is returned. - * - * @param source The item to rename - * @param destination The new name for the item - * @return True if an efficient move was performed, false if an efficient move - * was not possible. Note that errors while performing a move are - * reported via exceptions and not by returning false! - */ -- (bool)moveItemAtURI: (OFURI *)source toURI: (OFURI *)destination; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFURIHandler.m Index: src/OFURIHandler.m ================================================================== --- src/OFURIHandler.m +++ src/OFURIHandler.m @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFURIHandler.h" -#import "OFDictionary.h" -#import "OFNumber.h" -#import "OFURI.h" - -#ifdef OF_HAVE_THREADS -# import "OFMutex.h" -#endif - -#import "OFArchiveURIHandler.h" -#import "OFEmbeddedURIHandler.h" -#ifdef OF_HAVE_FILES -# import "OFFileURIHandler.h" -#endif -#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) -# import "OFHTTPURIHandler.h" -#endif - -#import "OFUnsupportedProtocolException.h" - -static OFMutableDictionary OF_GENERIC(OFString *, OFURIHandler *) *handlers; -#ifdef OF_HAVE_THREADS -static OFMutex *mutex; - -static void -releaseMutex(void) -{ - [mutex release]; -} -#endif - -@implementation OFURIHandler -@synthesize scheme = _scheme; - -+ (void)initialize -{ - if (self != [OFURIHandler class]) - return; - - handlers = [[OFMutableDictionary alloc] init]; -#ifdef OF_HAVE_THREADS - mutex = [[OFMutex alloc] init]; - atexit(releaseMutex); -#endif - - [self registerClass: [OFEmbeddedURIHandler class] - forScheme: @"embedded"]; -#ifdef OF_HAVE_FILES - [self registerClass: [OFFileURIHandler class] forScheme: @"file"]; -#endif -#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) - [self registerClass: [OFHTTPURIHandler class] forScheme: @"http"]; - [self registerClass: [OFHTTPURIHandler class] forScheme: @"https"]; -#endif - [self registerClass: [OFArchiveURIHandler class] forScheme: @"gzip"]; - [self registerClass: [OFArchiveURIHandler class] forScheme: @"lha"]; - [self registerClass: [OFArchiveURIHandler class] forScheme: @"tar"]; - [self registerClass: [OFArchiveURIHandler class] forScheme: @"zip"]; -} - -+ (bool)registerClass: (Class)class forScheme: (OFString *)scheme -{ -#ifdef OF_HAVE_THREADS - [mutex lock]; - @try { -#endif - OFURIHandler *handler; - - if ([handlers objectForKey: scheme] != nil) - return false; - - handler = [[class alloc] initWithScheme: scheme]; - @try { - [handlers setObject: handler forKey: scheme]; - } @finally { - [handler release]; - } -#ifdef OF_HAVE_THREADS - } @finally { - [mutex unlock]; - } -#endif - - return true; -} - -+ (OFURIHandler *)handlerForURI: (OFURI *)URI -{ - OF_KINDOF(OFURIHandler *) handler; - -#ifdef OF_HAVE_THREADS - [mutex lock]; - @try { -#endif - handler = [handlers objectForKey: URI.scheme]; -#ifdef OF_HAVE_THREADS - } @finally { - [mutex unlock]; - } -#endif - - if (handler == nil) - @throw [OFUnsupportedProtocolException exceptionWithURI: URI]; - - return handler; -} - -+ (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - return [[self handlerForURI: URI] openItemAtURI: URI mode: mode]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithScheme: (OFString *)scheme -{ - self = [super init]; - - @try { - _scheme = [scheme copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_scheme release]; - - [super dealloc]; -} - -- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (OFFileAttributes)attributesOfItemAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)setAttributes: (OFFileAttributes)attributes ofItemAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (bool)fileExistsAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (bool)directoryExistsAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)createDirectoryAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (OFArray OF_GENERIC(OFURI *) *)contentsOfDirectoryAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)removeItemAtURI: (OFURI *)URI -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)linkItemAtURI: (OFURI *)source toURI: (OFURI *)destination -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (void)createSymbolicLinkAtURI: (OFURI *)destination - withDestinationPath: (OFString *)source -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (bool)copyItemAtURI: (OFURI *)source toURI: (OFURI *)destination -{ - return false; -} - -- (bool)moveItemAtURI: (OFURI *)source toURI: (OFURI *)destination -{ - return false; -} -@end Index: src/OFUTF8String+Private.h ================================================================== --- src/OFUTF8String+Private.h +++ src/OFUTF8String+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFUTF8String.h ================================================================== --- src/OFUTF8String.h +++ src/OFUTF8String.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFUUID.h ================================================================== --- src/OFUUID.h +++ src/OFUUID.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,11 +12,10 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN @class OFString; @@ -24,11 +23,11 @@ * @class OFUUID OFUUID.h ObjFW/OFUUID.h * * @brief A UUID conforming to RFC 4122. */ OF_SUBCLASSING_RESTRICTED -@interface OFUUID: OFObject +@interface OFUUID: OFObject { unsigned char _bytes[16]; } /** Index: src/OFUUID.m ================================================================== --- src/OFUUID.m +++ src/OFUUID.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,10 @@ #include "config.h" #import "OFUUID.h" #import "OFArray.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @@ -143,33 +142,10 @@ } return self; } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool = objc_autoreleasePoolPush(); - OFString *UUIDString; - - @try { - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - UUIDString = element.stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithUUIDString: UUIDString]; - - objc_autoreleasePoolPop(pool); - - return self; -} - - (bool)isEqual: (id)object { OFUUID *UUID; if (![object isKindOfClass: [OFUUID class]]) @@ -233,20 +209,6 @@ - (OFString *)description { return self.UUIDString; } - -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS - stringValue: self.UUIDString]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} @end Index: src/OFValue.h ================================================================== --- src/OFValue.h +++ src/OFValue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFValue.m ================================================================== --- src/OFValue.m +++ src/OFValue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFWin32ConsoleStdIOStream.h ================================================================== --- src/OFWin32ConsoleStdIOStream.h +++ src/OFWin32ConsoleStdIOStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFWindowsRegistryKey.h ================================================================== --- src/OFWindowsRegistryKey.h +++ src/OFWindowsRegistryKey.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFWindowsRegistryKey.m ================================================================== --- src/OFWindowsRegistryKey.m +++ src/OFWindowsRegistryKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLAttribute.h ================================================================== --- src/OFXMLAttribute.h +++ src/OFXMLAttribute.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -90,10 +90,8 @@ * @return An initialized OFXMLAttribute with the specified parameters */ - (instancetype)initWithName: (OFString *)name namespace: (nullable OFString *)nameSpace stringValue: (OFString *)stringValue OF_DESIGNATED_INITIALIZER; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLAttribute.m ================================================================== --- src/OFXMLAttribute.m +++ src/OFXMLAttribute.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,10 @@ #import "OFXMLAttribute.h" #import "OFXMLNode+Private.h" #import "OFString.h" #import "OFDictionary.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" @implementation OFXMLAttribute @synthesize name = _name, namespace = _namespace; @@ -63,46 +62,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool; - OFString *name, *namespace, *stringValue; - - @try { - pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - name = [element attributeForName: @"name"].stringValue; - namespace = [element attributeForName: @"namespace"] - .stringValue; - stringValue = [element attributeForName: @"stringValue"] - .stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithName: name - namespace: namespace - stringValue: stringValue]; - - @try { - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { @@ -161,36 +124,13 @@ OFHashFinalize(&hash); return hash; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS]; - [element addAttributeWithName: @"name" stringValue: _name]; - - if (_namespace != nil) - [element addAttributeWithName: @"namespace" - stringValue: _namespace]; - - [element addAttributeWithName: @"stringValue" - stringValue: _stringValue]; - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (OFString *)description { return [OFString stringWithFormat: @"<%@: name=%@, namespace=%@, " @"stringValue=%@>", self.class, _name, _namespace, _stringValue]; } @end Index: src/OFXMLCDATA.h ================================================================== --- src/OFXMLCDATA.h +++ src/OFXMLCDATA.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -41,10 +41,8 @@ * * @param string The string value for the CDATA * @return An initialized OFXMLCDATA */ - (instancetype)initWithString: (OFString *)string; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLCDATA.m ================================================================== --- src/OFXMLCDATA.m +++ src/OFXMLCDATA.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,10 @@ #include "config.h" #import "OFXMLCDATA.h" #import "OFXMLNode+Private.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" @implementation OFXMLCDATA + (instancetype)CDATAWithString: (OFString *)string @@ -37,32 +36,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super of_init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - _CDATA = [element.stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { @@ -118,16 +95,6 @@ - (OFString *)description { return self.XMLString; } - -- (OFXMLElement *)XMLElementBySerializing -{ - OFXMLElement *element = - [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS]; - [element addChild: self]; - - return element; -} @end Index: src/OFXMLCharacters.h ================================================================== --- src/OFXMLCharacters.h +++ src/OFXMLCharacters.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -42,10 +42,8 @@ * * @param string The string value for the characters * @return An initialized OFXMLCharacters */ - (instancetype)initWithString: (OFString *)string; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLCharacters.m ================================================================== --- src/OFXMLCharacters.m +++ src/OFXMLCharacters.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,11 +16,10 @@ #include "config.h" #import "OFXMLCharacters.h" #import "OFXMLNode+Private.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" @implementation OFXMLCharacters + (instancetype)charactersWithString: (OFString *)string @@ -37,32 +36,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super of_init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - _characters = [element.stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { @@ -110,13 +87,6 @@ - (OFString *)description { return self.XMLString; } - -- (OFXMLElement *)XMLElementBySerializing -{ - return [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS - stringValue: _characters]; -} @end Index: src/OFXMLComment.h ================================================================== --- src/OFXMLComment.h +++ src/OFXMLComment.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -47,10 +47,8 @@ * * @param text The text for the comment * @return An initialized OFXMLComment */ - (instancetype)initWithText: (OFString *)text; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLComment.m ================================================================== --- src/OFXMLComment.m +++ src/OFXMLComment.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,11 +18,10 @@ #include #import "OFXMLComment.h" #import "OFXMLNode+Private.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFInvalidArgumentException.h" @implementation OFXMLComment @synthesize text = _text; @@ -41,32 +40,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - self = [super of_init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - _text = [element.stringValue copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { @@ -107,13 +84,6 @@ - (OFString *)description { return self.XMLString; } - -- (OFXMLElement *)XMLElementBySerializing -{ - return [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS - stringValue: _text]; -} @end DELETED src/OFXMLElement+Serialization.h Index: src/OFXMLElement+Serialization.h ================================================================== --- src/OFXMLElement+Serialization.h +++ src/OFXMLElement+Serialization.h @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFXMLElement.h" - -OF_ASSUME_NONNULL_BEGIN - -#ifdef __cplusplus -extern "C" { -#endif -extern int _OFXMLElement_Serialization_reference; -#ifdef __cplusplus -} -#endif - -@interface OFXMLElement (OFSerialization) -/** - * @brief The XML element interpreted as serialization and parsed into an - * object. - */ -@property (readonly, nonatomic) id objectByDeserializing; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFXMLElement+Serialization.m Index: src/OFXMLElement+Serialization.m ================================================================== --- src/OFXMLElement+Serialization.m +++ src/OFXMLElement+Serialization.m @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFXMLElement.h" -#import "OFXMLElement+Serialization.h" -#import "OFSerialization.h" -#import "OFString.h" - -#import "OFInvalidArgumentException.h" - -int _OFXMLElement_Serialization_reference; - -@implementation OFXMLElement (Serialization) -- (id)objectByDeserializing -{ - void *pool = objc_autoreleasePoolPush(); - Class class; - id object; - - if ((class = objc_getClass([_name cStringWithEncoding: - OFStringEncodingASCII])) == Nil) - @throw [OFInvalidArgumentException exception]; - - if (![class conformsToProtocol: @protocol(OFSerialization)]) - @throw [OFInvalidArgumentException exception]; - - object = [[class alloc] initWithSerialization: self]; - - objc_autoreleasePoolPop(pool); - - return [object autorelease]; -} -@end Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -432,7 +432,5 @@ - (OFString *)XMLStringWithDefaultNamespace: (OFString *)defaultNS indentation: (unsigned int)indentation; @end OF_ASSUME_NONNULL_END - -#import "OFXMLElement+Serialization.h" Index: src/OFXMLElement.m ================================================================== --- src/OFXMLElement.m +++ src/OFXMLElement.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -36,17 +36,10 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFMalformedXMLException.h" #import "OFUnboundNamespaceException.h" -/* References for static linking */ -void -_references_to_categories_of_OFXMLElement(void) -{ - _OFXMLElement_Serialization_reference = 1; -} - @interface OFXMLElementElementBuilderDelegate: OFObject { @public OFXMLElement *_element; @@ -265,108 +258,10 @@ [_namespaces release]; _namespaces = [element->_namespaces retain]; [_children release]; _children = [element->_children retain]; - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - void *pool; - OFString *name, *namespace; - - @try { - pool = objc_autoreleasePoolPush(); - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - name = [element attributeForName: @"name"].stringValue; - namespace = - [element attributeForName: @"namespace"].stringValue; - } @catch (id e) { - [self release]; - @throw e; - } - - self = [self initWithName: name namespace: namespace]; - - @try { - OFXMLElement *attributesElement, *namespacesElement; - OFXMLElement *childrenElement; - OFEnumerator *keyEnumerator, *objectEnumerator; - OFString *key, *object; - - attributesElement = [[element - elementForName: @"attributes" - namespace: OFSerializationNS] - elementsForNamespace: OFSerializationNS].firstObject; - namespacesElement = [[element - elementForName: @"namespaces" - namespace: OFSerializationNS] - elementsForNamespace: OFSerializationNS].firstObject; - childrenElement = [[element - elementForName: @"children" - namespace: OFSerializationNS] - elementsForNamespace: OFSerializationNS].firstObject; - - [_attributes release]; - _attributes = nil; - _attributes = [attributesElement.objectByDeserializing - mutableCopy]; - - [_namespaces release]; - _namespaces = nil; - _namespaces = [namespacesElement.objectByDeserializing - mutableCopy]; - - [_children release]; - _children = nil; - _children = [childrenElement.objectByDeserializing - mutableCopy]; - - /* Sanity checks */ - if ((_attributes != nil && ![_attributes isKindOfClass: - [OFMutableArray class]]) || (_namespaces != nil && - ![_namespaces isKindOfClass: - [OFMutableDictionary class]]) || (_children != nil && - ![_children isKindOfClass: [OFMutableArray class]])) - @throw [OFInvalidArgumentException exception]; - - for (OFXMLAttribute *attribute in _attributes) - if (![attribute isKindOfClass: [OFXMLAttribute class]]) - @throw [OFInvalidArgumentException exception]; - - keyEnumerator = [_namespaces keyEnumerator]; - objectEnumerator = [_namespaces objectEnumerator]; - while ((key = [keyEnumerator nextObject]) != nil && - (object = [objectEnumerator nextObject]) != nil) - if (![key isKindOfClass: [OFString class]] || - ![object isKindOfClass: [OFString class]]) - @throw [OFInvalidArgumentException exception]; - - for (object in _children) - if (![object isKindOfClass: [OFXMLNode class]]) - @throw [OFInvalidArgumentException exception]; - - if (_namespaces == nil) - _namespaces = [[OFMutableDictionary alloc] init]; - - [_namespaces - setObject: @"xml" - forKey: @"http://www.w3.org/XML/1998/namespace"]; - [_namespaces setObject: @"xmlns" - forKey: @"http://www.w3.org/2000/xmlns/"]; - objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } @@ -666,73 +561,10 @@ namespaces: nil indentation: indentation level: 0]; } -- (OFXMLElement *)XMLElementBySerializing -{ - void *pool = objc_autoreleasePoolPush(); - OFXMLElement *element; - - element = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS]; - - if (_name != nil) - [element addAttributeWithName: @"name" stringValue: _name]; - - if (_namespace != nil) - [element addAttributeWithName: @"namespace" - stringValue: _namespace]; - - if (_attributes != nil) { - OFXMLElement *attributesElement; - - attributesElement = - [OFXMLElement elementWithName: @"attributes" - namespace: OFSerializationNS]; - [attributesElement addChild: - _attributes.XMLElementBySerializing]; - [element addChild: attributesElement]; - } - - if (_namespaces != nil) { - OFXMLElement *namespacesElement; - OFMutableDictionary *namespacesCopy = - [[_namespaces mutableCopy] autorelease]; - - [namespacesCopy removeObjectForKey: - @"http://www.w3.org/XML/1998/namespace"]; - [namespacesCopy removeObjectForKey: - @"http://www.w3.org/2000/xmlns/"]; - - if (namespacesCopy.count > 0) { - namespacesElement = - [OFXMLElement elementWithName: @"namespaces" - namespace: OFSerializationNS]; - [namespacesElement addChild: - namespacesCopy.XMLElementBySerializing]; - [element addChild: namespacesElement]; - } - } - - if (_children != nil) { - OFXMLElement *childrenElement; - - childrenElement = - [OFXMLElement elementWithName: @"children" - namespace: OFSerializationNS]; - [childrenElement addChild: _children.XMLElementBySerializing]; - [element addChild: childrenElement]; - } - - [element retain]; - - objc_autoreleasePoolPop(pool); - - return [element autorelease]; -} - - (void)addAttribute: (OFXMLAttribute *)attribute { if (![attribute isKindOfClass: [OFXMLAttribute class]]) @throw [OFInvalidArgumentException exception]; Index: src/OFXMLElementBuilder.h ================================================================== --- src/OFXMLElementBuilder.h +++ src/OFXMLElementBuilder.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLElementBuilder.m ================================================================== --- src/OFXMLElementBuilder.m +++ src/OFXMLElementBuilder.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLNode+Private.h ================================================================== --- src/OFXMLNode+Private.h +++ src/OFXMLNode+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLNode.h ================================================================== --- src/OFXMLNode.h +++ src/OFXMLNode.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,22 +12,19 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFSerialization.h" OF_ASSUME_NONNULL_BEGIN -@class OFXMLElement; - /** * @class OFXMLNode OFXMLNode.h ObjFW/OFXMLNode.h * * @brief A class which stores an XML element. */ -@interface OFXMLNode: OFObject +@interface OFXMLNode: OFObject { OF_RESERVE_IVARS(OFXMLNode, 4) } /** @@ -75,11 +72,10 @@ * needs a prefix */ @property (readonly, nonatomic) OFString *XMLString; - (instancetype)init OF_UNAVAILABLE; -- (instancetype)initWithSerialization: (OFXMLElement *)element OF_UNAVAILABLE; /** * @brief The contents of the receiver as a `long long` value in the specified * base. * Index: src/OFXMLNode.m ================================================================== --- src/OFXMLNode.m +++ src/OFXMLNode.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,15 +24,10 @@ return [super init]; } - (instancetype)init { - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ OF_INVALID_INIT_METHOD } - (OFString *)stringValue { @@ -82,15 +77,10 @@ - (OFString *)description { return self.XMLString; } -- (OFXMLElement *)XMLElementBySerializing -{ - OF_UNRECOGNIZED_SELECTOR -} - - (id)copy { return [self retain]; } @end Index: src/OFXMLParser.h ================================================================== --- src/OFXMLParser.h +++ src/OFXMLParser.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLParser.m ================================================================== --- src/OFXMLParser.m +++ src/OFXMLParser.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFXMLProcessingInstruction.h ================================================================== --- src/OFXMLProcessingInstruction.h +++ src/OFXMLProcessingInstruction.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -58,10 +58,8 @@ * @param text The text for the processing instruction * @return An initialized OFXMLProcessingInstruction */ - (instancetype)initWithTarget: (OFString *)target text: (OFString *)text OF_DESIGNATED_INITIALIZER; - -- (instancetype)initWithSerialization: (OFXMLElement *)element; @end OF_ASSUME_NONNULL_END Index: src/OFXMLProcessingInstruction.m ================================================================== --- src/OFXMLProcessingInstruction.m +++ src/OFXMLProcessingInstruction.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,11 +18,10 @@ #include #import "OFXMLProcessingInstruction.h" #import "OFString.h" #import "OFXMLAttribute.h" -#import "OFXMLElement.h" #import "OFXMLNode+Private.h" #import "OFInvalidArgumentException.h" @implementation OFXMLProcessingInstruction @@ -46,37 +45,10 @@ } @catch (id e) { [self release]; @throw e; } - return self; -} - -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - @try { - void *pool = objc_autoreleasePoolPush(); - OFXMLAttribute *targetAttr; - - if (![element.name isEqual: self.className] || - ![element.namespace isEqual: OFSerializationNS]) - @throw [OFInvalidArgumentException exception]; - - targetAttr = [element attributeForName: @"target" - namespace: OFSerializationNS]; - if (targetAttr.stringValue.length == 0) - @throw [OFInvalidArgumentException exception]; - - self = [self initWithTarget: targetAttr.stringValue - text: element.stringValue]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - return self; } - (void)dealloc { @@ -136,21 +108,6 @@ - (OFString *)description { return self.XMLString; } - -- (OFXMLElement *)XMLElementBySerializing -{ - OFXMLElement *ret = [OFXMLElement elementWithName: self.className - namespace: OFSerializationNS - stringValue: _text]; - void *pool = objc_autoreleasePoolPush(); - - [ret addAttribute: [OFXMLAttribute attributeWithName: @"target" - stringValue: _target]]; - - objc_autoreleasePoolPop(pool); - - return ret; -} @end Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -30,11 +30,11 @@ * @brief A class for accessing and manipulating ZIP files. */ OF_SUBCLASSING_RESTRICTED @interface OFZIPArchive: OFObject { - OFStream *_stream; + OF_KINDOF(OFStream *) _stream; #ifdef OF_ZIP_ARCHIVE_M @public #endif int64_t _offset; @protected @@ -83,29 +83,29 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode; /** * @brief Creates a new OFZIPArchive object with the specified file. * - * @param URI The URI to the ZIP file + * @param IRI The IRI to the ZIP file * @param mode The mode for the ZIP file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return A new, autoreleased OFZIPArchive * @throw OFInvalidFormatException The format is not that of a valid ZIP archive */ -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode; ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** - * @brief Creates a URI for accessing a the specified file within the specified - * ZIP archive. + * @brief Creates an IRI for accessing a the specified file within the + * specified ZIP archive. * * @param path The path of the file within the archive - * @param URI The URI of the archive - * @return A URI for accessing the specified file within the specified ZIP + * @param IRI The IRI of the archive + * @return An IRI for accessing the specified file within the specified ZIP * archive */ -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI; ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI; - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFZIPArchive object with the @@ -124,18 +124,18 @@ /** * @brief Initializes an already allocated OFZIPArchive object with the * specified file. * - * @param URI The URI to the ZIP file + * @param IRI The IRI to the ZIP file * @param mode The mode for the ZIP file. Valid modes are "r" for reading, * "w" for creating a new file and "a" for appending to an existing * archive. * @return An initialized OFZIPArchive * @throw OFInvalidFormatException The format is not that of a valid ZIP archive */ -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode; +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode; /** * @brief Returns a stream for reading the specified file from the archive. * * @note This method is only available in read mode. @@ -186,13 +186,15 @@ * * Bit 3 and 11 of the general purpose bit flag. * @return A stream for writing the specified entry to the archive * @throw OFNotOpenException The archive is not open * @throw OFInvalidArgumentException The archive is not in write mode * @throw OFOpenItemFailedException Opening the specified file within the - * archive failed. If @ref errNo is `EEXIST`, - * because there is already a file with the - * same name in the archive. + * archive failed. If + * @ref OFOpenItemFailedException#errNo is + * `EEXIST`, it failed because there is + * already a file with the same name in the + * archive. * @throw OFNotImplementedException The desired compression method is not * implemented */ - (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry; Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,21 +20,21 @@ #include #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" -#import "OFArchiveURIHandler.h" +#import "OFArchiveIRIHandler.h" #import "OFArray.h" #import "OFCRC32.h" #import "OFData.h" #import "OFDictionary.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFInflate64Stream.h" #import "OFInflateStream.h" #import "OFSeekableStream.h" #import "OFStream.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" @@ -99,20 +99,23 @@ OF_DIRECT_MEMBERS @interface OFZIPArchiveFileWriteStream: OFStream { OFZIPArchive *_archive; - OFStream *_stream; + OF_KINDOF(OFStream *) _stream; uint32_t _CRC32; + OFStreamOffset _CRC32Offset, _size64Offset; @public unsigned long long _bytesWritten; OFMutableZIPArchiveEntry *_entry; } - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream - entry: (OFMutableZIPArchiveEntry *)entry; + entry: (OFMutableZIPArchiveEntry *)entry + CRC32Offset: (OFStreamOffset)CRC32Offset + size64Offset: (OFStreamOffset)size64Offset; @end uint32_t OFZIPArchiveReadField32(const uint8_t **data, uint16_t *size) { @@ -167,18 +170,18 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } -+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode ++ (instancetype)archiveWithIRI: (OFIRI *)IRI mode: (OFString *)mode { - return [[[self alloc] initWithURI: URI mode: mode] autorelease]; + return [[[self alloc] initWithIRI: IRI mode: mode] autorelease]; } -+ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI ++ (OFIRI *)IRIForFilePath: (OFString *)path inArchiveWithIRI: (OFIRI *)IRI { - return OFArchiveURIHandlerURIForFileInArchive(@"zip", path, URI); + return OFArchiveIRIHandlerIRIForFileInArchive(@"zip", path, IRI); } - (instancetype)init { OF_INVALID_INIT_METHOD @@ -210,11 +213,11 @@ [self of_readEntries]; } if (_mode == modeAppend) { _offset = _centralDirectoryOffset; - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, + seekOrThrowInvalidFormat(_stream, (OFStreamOffset)_offset, OFSeekSet); } } @catch (id e) { /* * If we are in write or append mode, we do not want -[close] @@ -229,20 +232,20 @@ } return self; } -- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); OFStream *stream; @try { if ([mode isEqual: @"a"]) - stream = [OFURIHandler openItemAtURI: URI mode: @"r+"]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: @"r+"]; else - stream = [OFURIHandler openItemAtURI: URI mode: mode]; + stream = [OFIRIHandler openItemAtIRI: IRI mode: mode]; } @catch (id e) { [self release]; @throw e; } @@ -272,12 +275,11 @@ uint16_t commentLength; OFStreamOffset offset = -22; bool valid = false; do { - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - offset, OFSeekEnd); + seekOrThrowInvalidFormat(_stream, offset, OFSeekEnd); if ([_stream readLittleEndianInt32] == 0x06054B50) { valid = true; break; } @@ -305,12 +307,11 @@ _centralDirectorySize == 0xFFFFFFFF || _centralDirectoryOffset == 0xFFFFFFFF) { int64_t offset64; uint64_t size; - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - offset - 20, OFSeekEnd); + seekOrThrowInvalidFormat(_stream, offset - 20, OFSeekEnd); if ([_stream readLittleEndianInt32] != 0x07064B50) { objc_autoreleasePoolPop(pool); return; } @@ -323,11 +324,11 @@ offset64 = [_stream readLittleEndianInt64]; if (offset64 < 0 || (OFStreamOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, + seekOrThrowInvalidFormat(_stream, (OFStreamOffset)offset64, OFSeekSet); if ([_stream readLittleEndianInt32] != 0x06064B50) @throw [OFInvalidFormatException exception]; @@ -363,11 +364,11 @@ if (_centralDirectoryOffset < 0 || (OFStreamOffset)_centralDirectoryOffset != _centralDirectoryOffset) @throw [OFOutOfRangeException exception]; - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, + seekOrThrowInvalidFormat(_stream, (OFStreamOffset)_centralDirectoryOffset, OFSeekSet); for (size_t i = 0; i < _centralDirectoryEntries; i++) { OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc] of_initWithStream: _stream] autorelease]; @@ -434,12 +435,11 @@ offset64 = entry.of_localFileHeaderOffset; if (offset64 < 0 || (OFStreamOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; - seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (OFStreamOffset)offset64, OFSeekSet); + seekOrThrowInvalidFormat(_stream, (OFStreamOffset)offset64, OFSeekSet); localFileHeader = [[[OFZIPArchiveLocalFileHeader alloc] initWithStream: _stream] autorelease]; if (![localFileHeader matchesEntry: entry]) @throw [OFInvalidFormatException exception]; @@ -463,15 +463,16 @@ return _lastReturnedStream; } - (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry_ { - /* TODO: Avoid data descriptor when _stream is an OFSeekableStream */ int64_t offsetAdd = 0; void *pool; OFMutableZIPArchiveEntry *entry; OFString *fileName; + bool seekable; + OFStreamOffset CRC32Offset = 0, size64Offset = 0; OFData *extraField; uint16_t fileNameLength, extraFieldLength; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; @@ -505,25 +506,29 @@ extraFieldLength = extraField.count; if (UINT16_MAX - extraFieldLength < 20) @throw [OFOutOfRangeException exception]; + seekable = [_stream isKindOfClass: [OFSeekableStream class]]; + entry.versionMadeBy = (entry.versionMadeBy & 0xFF00) | 45; entry.minVersionNeeded = (entry.minVersionNeeded & 0xFF00) | 45; entry.compressedSize = 0; entry.uncompressedSize = 0; entry.CRC32 = 0; - entry.generalPurposeBitFlag |= (1u << 3) | (1u << 11); + entry.generalPurposeBitFlag |= (seekable ? 0 : (1u << 3)) | (1u << 11); entry.of_localFileHeaderOffset = _offset; [_stream writeLittleEndianInt32: 0x04034B50]; [_stream writeLittleEndianInt16: entry.minVersionNeeded]; [_stream writeLittleEndianInt16: entry.generalPurposeBitFlag]; [_stream writeLittleEndianInt16: entry.compressionMethod]; [_stream writeLittleEndianInt16: entry.of_lastModifiedFileTime]; [_stream writeLittleEndianInt16: entry.of_lastModifiedFileDate]; - /* We use the data descriptor */ + /* Written later or data descriptor used instead */ + if (seekable) + CRC32Offset = [_stream seekToOffset: 0 whence: OFSeekCurrent]; [_stream writeLittleEndianInt32: 0]; /* We use ZIP64 */ [_stream writeLittleEndianInt32: 0xFFFFFFFF]; [_stream writeLittleEndianInt32: 0xFFFFFFFF]; [_stream writeLittleEndianInt16: fileNameLength]; @@ -533,11 +538,13 @@ [_stream writeString: fileName]; offsetAdd += fileNameLength; [_stream writeLittleEndianInt16: OFZIPArchiveEntryExtraFieldTagZIP64]; [_stream writeLittleEndianInt16: 16]; - /* We use the data descriptor */ + /* Written later or data descriptor used instead */ + if (seekable) + size64Offset = [_stream seekToOffset: 0 whence: OFSeekCurrent]; [_stream writeLittleEndianInt64: 0]; [_stream writeLittleEndianInt64: 0]; offsetAdd += (2 * 2) + (2 * 8); if (extraField != nil) @@ -550,11 +557,13 @@ _offset += offsetAdd; _lastReturnedStream = [[OFZIPArchiveFileWriteStream alloc] of_initWithArchive: self stream: _stream - entry: entry]; + entry: entry + CRC32Offset: CRC32Offset + size64Offset: size64Offset]; objc_autoreleasePoolPop(pool); return [_lastReturnedStream autorelease]; } @@ -863,17 +872,21 @@ @implementation OFZIPArchiveFileWriteStream - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream entry: (OFMutableZIPArchiveEntry *)entry + CRC32Offset: (OFStreamOffset)CRC32Offset + size64Offset: (OFStreamOffset)size64Offset { self = [super init]; _archive = [archive retain]; _stream = [stream retain]; _entry = [entry retain]; _CRC32 = ~0; + _CRC32Offset = CRC32Offset; + _size64Offset = size64Offset; return self; } - (void)dealloc @@ -921,30 +934,48 @@ return length; } - (void)close { + bool seekable; + if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_bytesWritten > UINT64_MAX) @throw [OFOutOfRangeException exception]; - [_stream writeLittleEndianInt32: 0x08074B50]; - [_stream writeLittleEndianInt32: _CRC32]; - [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; - [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; + seekable = [_stream isKindOfClass: [OFSeekableStream class]]; + + if (seekable) { + OFStreamOffset offset = [_stream seekToOffset: 0 + whence: OFSeekCurrent]; + + [_stream seekToOffset: _CRC32Offset whence: OFSeekSet]; + [_stream writeLittleEndianInt32: ~_CRC32]; + [_stream seekToOffset: _size64Offset whence: OFSeekSet]; + [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; + [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; + + [_stream seekToOffset: offset whence: OFSeekSet]; + } else { + [_stream writeLittleEndianInt32: 0x08074B50]; + [_stream writeLittleEndianInt32: ~_CRC32]; + [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; + [_stream writeLittleEndianInt64: (uint64_t)_bytesWritten]; + } [_stream release]; _stream = nil; _entry.CRC32 = ~_CRC32; _entry.compressedSize = _bytesWritten; _entry.uncompressedSize = _bytesWritten; [_entry makeImmutable]; - _bytesWritten += (2 * 4 + 2 * 8); + if (!seekable) + _bytesWritten += (2 * 4 + 2 * 8); [_archive->_entries addObject: _entry]; [_archive->_pathToEntryMap setObject: _entry forKey: _entry.fileName]; if (ULLONG_MAX - _archive->_offset < _bytesWritten) Index: src/OFZIPArchiveEntry+Private.h ================================================================== --- src/OFZIPArchiveEntry+Private.h +++ src/OFZIPArchiveEntry+Private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/OFZIPArchiveEntry.m ================================================================== --- src/OFZIPArchiveEntry.m +++ src/OFZIPArchiveEntry.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -43,13 +43,13 @@ #import "OFMethodSignature.h" #import "OFInvocation.h" #import "OFNumber.h" #import "OFDate.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFUUID.h" -#import "OFURI.h" -#import "OFURIHandler.h" #import "OFColor.h" #import "OFNotification.h" #import "OFNotificationCenter.h" @@ -136,15 +136,18 @@ #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFTimer.h" #import "OFRunLoop.h" +#import "OFMatrix4x4.h" + #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif #import "OFAllocFailedException.h" +#import "OFAlreadyOpenException.h" #import "OFException.h" #import "OFChangeCurrentDirectoryFailedException.h" #import "OFChecksumMismatchException.h" #import "OFCopyItemFailedException.h" #import "OFCreateDirectoryFailedException.h" @@ -191,11 +194,10 @@ #import "OFUnsupportedProtocolException.h" #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" #ifdef OF_HAVE_SOCKETS # import "OFAcceptSocketFailedException.h" -# import "OFAlreadyConnectedException.h" # import "OFBindIPSocketFailedException.h" # import "OFBindSocketFailedException.h" # import "OFConnectIPSocketFailedException.h" # import "OFConnectSocketFailedException.h" # import "OFDNSQueryFailedException.h" Index: src/bridge/NSArray+OFObject.h ================================================================== --- src/bridge/NSArray+OFObject.h +++ src/bridge/NSArray+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSArray+OFObject.m ================================================================== --- src/bridge/NSArray+OFObject.m +++ src/bridge/NSArray+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSBridging.h ================================================================== --- src/bridge/NSBridging.h +++ src/bridge/NSBridging.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSDictionary+OFObject.h ================================================================== --- src/bridge/NSDictionary+OFObject.h +++ src/bridge/NSDictionary+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSDictionary+OFObject.m ================================================================== --- src/bridge/NSDictionary+OFObject.m +++ src/bridge/NSDictionary+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSEnumerator+OFObject.h ================================================================== --- src/bridge/NSEnumerator+OFObject.h +++ src/bridge/NSEnumerator+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSEnumerator+OFObject.m ================================================================== --- src/bridge/NSEnumerator+OFObject.m +++ src/bridge/NSEnumerator+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSNumber+OFObject.h ================================================================== --- src/bridge/NSNumber+OFObject.h +++ src/bridge/NSNumber+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSNumber+OFObject.m ================================================================== --- src/bridge/NSNumber+OFObject.m +++ src/bridge/NSNumber+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFArray.h ================================================================== --- src/bridge/NSOFArray.h +++ src/bridge/NSOFArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFArray.m ================================================================== --- src/bridge/NSOFArray.m +++ src/bridge/NSOFArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFDictionary.h ================================================================== --- src/bridge/NSOFDictionary.h +++ src/bridge/NSOFDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFDictionary.m ================================================================== --- src/bridge/NSOFDictionary.m +++ src/bridge/NSOFDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFEnumerator.h ================================================================== --- src/bridge/NSOFEnumerator.h +++ src/bridge/NSOFEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFEnumerator.m ================================================================== --- src/bridge/NSOFEnumerator.m +++ src/bridge/NSOFEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFSet.h ================================================================== --- src/bridge/NSOFSet.h +++ src/bridge/NSOFSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSOFSet.m ================================================================== --- src/bridge/NSOFSet.m +++ src/bridge/NSOFSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSSet+OFObject.h ================================================================== --- src/bridge/NSSet+OFObject.h +++ src/bridge/NSSet+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSSet+OFObject.m ================================================================== --- src/bridge/NSSet+OFObject.m +++ src/bridge/NSSet+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSString+OFObject.h ================================================================== --- src/bridge/NSString+OFObject.h +++ src/bridge/NSString+OFObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/NSString+OFObject.m ================================================================== --- src/bridge/NSString+OFObject.m +++ src/bridge/NSString+OFObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFArray+NSObject.h ================================================================== --- src/bridge/OFArray+NSObject.h +++ src/bridge/OFArray+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFArray+NSObject.m ================================================================== --- src/bridge/OFArray+NSObject.m +++ src/bridge/OFArray+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFBridging.h ================================================================== --- src/bridge/OFBridging.h +++ src/bridge/OFBridging.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFDictionary+NSObject.h ================================================================== --- src/bridge/OFDictionary+NSObject.h +++ src/bridge/OFDictionary+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFDictionary+NSObject.m ================================================================== --- src/bridge/OFDictionary+NSObject.m +++ src/bridge/OFDictionary+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFEnumerator+NSObject.h ================================================================== --- src/bridge/OFEnumerator+NSObject.h +++ src/bridge/OFEnumerator+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFEnumerator+NSObject.m ================================================================== --- src/bridge/OFEnumerator+NSObject.m +++ src/bridge/OFEnumerator+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFException+Swift.h ================================================================== --- src/bridge/OFException+Swift.h +++ src/bridge/OFException+Swift.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFException+Swift.m ================================================================== --- src/bridge/OFException+Swift.m +++ src/bridge/OFException+Swift.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSArray.h ================================================================== --- src/bridge/OFNSArray.h +++ src/bridge/OFNSArray.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSArray.m ================================================================== --- src/bridge/OFNSArray.m +++ src/bridge/OFNSArray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSDictionary.h ================================================================== --- src/bridge/OFNSDictionary.h +++ src/bridge/OFNSDictionary.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSDictionary.m ================================================================== --- src/bridge/OFNSDictionary.m +++ src/bridge/OFNSDictionary.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSEnumerator.h ================================================================== --- src/bridge/OFNSEnumerator.h +++ src/bridge/OFNSEnumerator.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSEnumerator.m ================================================================== --- src/bridge/OFNSEnumerator.m +++ src/bridge/OFNSEnumerator.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSSet.h ================================================================== --- src/bridge/OFNSSet.h +++ src/bridge/OFNSSet.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNSSet.m ================================================================== --- src/bridge/OFNSSet.m +++ src/bridge/OFNSSet.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNumber+NSObject.h ================================================================== --- src/bridge/OFNumber+NSObject.h +++ src/bridge/OFNumber+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFNumber+NSObject.m ================================================================== --- src/bridge/OFNumber+NSObject.m +++ src/bridge/OFNumber+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFSet+NSObject.h ================================================================== --- src/bridge/OFSet+NSObject.h +++ src/bridge/OFSet+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFSet+NSObject.m ================================================================== --- src/bridge/OFSet+NSObject.m +++ src/bridge/OFSet+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFString+NSObject.h ================================================================== --- src/bridge/OFString+NSObject.h +++ src/bridge/OFString+NSObject.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/OFString+NSObject.m ================================================================== --- src/bridge/OFString+NSObject.m +++ src/bridge/OFString+NSObject.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/bridge/ObjFWBridge.h ================================================================== --- src/bridge/ObjFWBridge.h +++ src/bridge/ObjFWBridge.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/codepage-437.m ================================================================== --- src/encodings/codepage-437.m +++ src/encodings/codepage-437.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/codepage-850.m ================================================================== --- src/encodings/codepage-850.m +++ src/encodings/codepage-850.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/codepage-858.m ================================================================== --- src/encodings/codepage-858.m +++ src/encodings/codepage-858.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/common.h ================================================================== --- src/encodings/common.h +++ src/encodings/common.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/iso-8859-15.m ================================================================== --- src/encodings/iso-8859-15.m +++ src/encodings/iso-8859-15.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/iso-8859-2.m ================================================================== --- src/encodings/iso-8859-2.m +++ src/encodings/iso-8859-2.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/iso-8859-3.m ================================================================== --- src/encodings/iso-8859-3.m +++ src/encodings/iso-8859-3.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/koi8-r.m ================================================================== --- src/encodings/koi8-r.m +++ src/encodings/koi8-r.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/koi8-u.m ================================================================== --- src/encodings/koi8-u.m +++ src/encodings/koi8-u.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/mac-roman.m ================================================================== --- src/encodings/mac-roman.m +++ src/encodings/mac-roman.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/windows-1251.m ================================================================== --- src/encodings/windows-1251.m +++ src/encodings/windows-1251.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/encodings/windows-1252.m ================================================================== --- src/encodings/windows-1252.m +++ src/encodings/windows-1252.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -3,10 +3,11 @@ STATIC_PIC_LIB_NOINST = ${EXCEPTIONS_LIB_A} STATIC_LIB_NOINST = ${EXCEPTIONS_A} STATIC_AMIGA_LIB_NOINST = ${EXCEPTIONS_AMIGALIB_A} SRCS = OFAllocFailedException.m \ + OFAlreadyOpenException.m \ OFChecksumMismatchException.m \ OFCopyItemFailedException.m \ OFCreateDirectoryFailedException.m \ OFCreateSymbolicLinkFailedException.m \ OFEnumerationMutationException.m \ @@ -53,11 +54,10 @@ ${USE_SRCS_WINDOWS} SRCS_FILES = OFChangeCurrentDirectoryFailedException.m \ OFGetCurrentDirectoryFailedException.m SRCS_PLUGINS = OFLoadPluginFailedException.m SRCS_SOCKETS = OFAcceptSocketFailedException.m \ - OFAlreadyConnectedException.m \ OFBindIPSocketFailedException.m \ OFBindSocketFailedException.m \ OFConnectIPSocketFailedException.m \ OFConnectSocketFailedException.m \ OFDNSQueryFailedException.m \ Index: src/exceptions/OFAcceptSocketFailedException.h ================================================================== --- src/exceptions/OFAcceptSocketFailedException.h +++ src/exceptions/OFAcceptSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFAcceptSocketFailedException.m ================================================================== --- src/exceptions/OFAcceptSocketFailedException.m +++ src/exceptions/OFAcceptSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFActivateSandboxFailedException.h ================================================================== --- src/exceptions/OFActivateSandboxFailedException.h +++ src/exceptions/OFActivateSandboxFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFActivateSandboxFailedException.m ================================================================== --- src/exceptions/OFActivateSandboxFailedException.m +++ src/exceptions/OFActivateSandboxFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFAllocFailedException.h ================================================================== --- src/exceptions/OFAllocFailedException.h +++ src/exceptions/OFAllocFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFAllocFailedException.m ================================================================== --- src/exceptions/OFAllocFailedException.m +++ src/exceptions/OFAllocFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/exceptions/OFAlreadyConnectedException.h Index: src/exceptions/OFAlreadyConnectedException.h ================================================================== --- src/exceptions/OFAlreadyConnectedException.h +++ src/exceptions/OFAlreadyConnectedException.h @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFException.h" - -#ifndef OF_HAVE_SOCKETS -# error No sockets available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFAlreadyConnectedException \ - * OFAlreadyConnectedException.h ObjFW/OFAlreadyConnectedException.h - * - * @brief An exception indicating an attempt to connect or bind an already - * connected or bound socket. - */ -@interface OFAlreadyConnectedException: OFException -{ - id _socket; - OF_RESERVE_IVARS(OFAlreadyConnectedException, 4) -} - -/** - * @brief The socket which is already connected. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id socket; - -/** - * @brief Creates a new, autoreleased already connected exception. - * - * @param socket The socket which is already connected - * @return A new, autoreleased already connected exception - */ -+ (instancetype)exceptionWithSocket: (nullable id)socket; - -/** - * @brief Initializes an already allocated already connected exception. - * - * @param socket The socket which is already connected - * @return An initialized already connected exception - */ -- (instancetype)initWithSocket: (nullable id)socket OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFAlreadyConnectedException.m Index: src/exceptions/OFAlreadyConnectedException.m ================================================================== --- src/exceptions/OFAlreadyConnectedException.m +++ src/exceptions/OFAlreadyConnectedException.m @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFAlreadyConnectedException.h" -#import "OFString.h" - -@implementation OFAlreadyConnectedException -@synthesize socket = _socket; - -+ (instancetype)exceptionWithSocket: (id)sock -{ - return [[[self alloc] initWithSocket: sock] autorelease]; -} - -- (instancetype)init -{ - return [self initWithSocket: nil]; -} - -- (instancetype)initWithSocket: (id)sock -{ - self = [super init]; - - _socket = [sock retain]; - - return self; -} - -- (void)dealloc -{ - [_socket release]; - - [super dealloc]; -} - -- (OFString *)description -{ - if (_socket) - return [OFString stringWithFormat: - @"The socket of type %@ is already connected or bound and " - @"thus can't be connected or bound again!", - [_socket class]]; - else - return @"A connection has already been established!"; -} -@end ADDED src/exceptions/OFAlreadyOpenException.h Index: src/exceptions/OFAlreadyOpenException.h ================================================================== --- src/exceptions/OFAlreadyOpenException.h +++ src/exceptions/OFAlreadyOpenException.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFAlreadyOpenException \ + * OFAlreadyOpenException.h ObjFW/OFAlreadyOpenException.h + * + * @brief An exception indicating that an object is already open and thus + * cannot be opened again. + */ +@interface OFAlreadyOpenException: OFException +{ + id _object; + OF_RESERVE_IVARS(OFAlreadyOpenException, 4) +} + +/** + * @brief The object which is already open. + */ +@property (readonly, nonatomic) id object; + +/** + * @brief Creates a new, autoreleased already open exception. + * + * @param object The object which is already open + * @return A new, autoreleased already open exception + */ ++ (instancetype)exceptionWithObject: (id)object; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated already open exception. + * + * @param object The object which is already open + * @return An initialized already open exception + */ +- (instancetype)initWithObject: (id)object OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFAlreadyOpenException.m Index: src/exceptions/OFAlreadyOpenException.m ================================================================== --- src/exceptions/OFAlreadyOpenException.m +++ src/exceptions/OFAlreadyOpenException.m @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFAlreadyOpenException.h" +#import "OFString.h" + +@implementation OFAlreadyOpenException +@synthesize object = _object; + ++ (instancetype)exceptionWithObject: (id)object +{ + return [[[self alloc] initWithObject: object] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithObject: (id)object +{ + self = [super init]; + + _object = [object retain]; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_object release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"An object of type %@ is already open and thus cannot be opened " + @"again!", + [_object class]]; +} +@end Index: src/exceptions/OFBindDDPSocketFailedException.h ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.h +++ src/exceptions/OFBindDDPSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindDDPSocketFailedException.m ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.m +++ src/exceptions/OFBindDDPSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -72,11 +72,11 @@ - (OFString *)description { return [OFString stringWithFormat: @"Binding to port %" @PRIx8 @" of node %" @PRIx8 @" on network " - @"%" PRIx16 @" with protocol type %" @PRIx8 @" failed in socket of " - @"type %@: %@", + @"%" PRIx16 @" with protocol type 0x%" @PRIX8 @" failed in socket " + @"of type %@: %@", _port, _node, _network, _protocolType, [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFBindIPSocketFailedException.h ================================================================== --- src/exceptions/OFBindIPSocketFailedException.h +++ src/exceptions/OFBindIPSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindIPSocketFailedException.m ================================================================== --- src/exceptions/OFBindIPSocketFailedException.m +++ src/exceptions/OFBindIPSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindIPXSocketFailedException.h ================================================================== --- src/exceptions/OFBindIPXSocketFailedException.h +++ src/exceptions/OFBindIPXSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindIPXSocketFailedException.m ================================================================== --- src/exceptions/OFBindIPXSocketFailedException.m +++ src/exceptions/OFBindIPXSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -78,14 +78,13 @@ memcpy(node, _node, sizeof(_node)); } - (OFString *)description { - OFData *node = [OFData dataWithItems: _node count: sizeof(_node)]; - return [OFString stringWithFormat: - @"Binding to network %" @PRIx16 " on node %@ with port %" @PRIx16 - @" failed for packet type %" @PRIx8 " in socket of type %@: %@", - _network, node, _port, _packetType, [_socket class], - OFStrError(_errNo)]; + @"Binding to network %" @PRIx16 " on node " + @"%02X:%02X:%02X:%02X:%02X:%02X with port %" @PRIx16 @" failed for " + @"packet type %" @PRIx8 " in socket of type %@: %@", + _network, _node[0], _node[1], _node[2], _node[3], _node[4], + _node[5], _port, _packetType, [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFBindSocketFailedException.h ================================================================== --- src/exceptions/OFBindSocketFailedException.h +++ src/exceptions/OFBindSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindSocketFailedException.m ================================================================== --- src/exceptions/OFBindSocketFailedException.m +++ src/exceptions/OFBindSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindUNIXSocketFailedException.h ================================================================== --- src/exceptions/OFBindUNIXSocketFailedException.h +++ src/exceptions/OFBindUNIXSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBindUNIXSocketFailedException.m ================================================================== --- src/exceptions/OFBindUNIXSocketFailedException.m +++ src/exceptions/OFBindUNIXSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBroadcastConditionFailedException.h ================================================================== --- src/exceptions/OFBroadcastConditionFailedException.h +++ src/exceptions/OFBroadcastConditionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFBroadcastConditionFailedException.m ================================================================== --- src/exceptions/OFBroadcastConditionFailedException.m +++ src/exceptions/OFBroadcastConditionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFChangeCurrentDirectoryFailedException.h ================================================================== --- src/exceptions/OFChangeCurrentDirectoryFailedException.h +++ src/exceptions/OFChangeCurrentDirectoryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFChangeCurrentDirectoryFailedException.m ================================================================== --- src/exceptions/OFChangeCurrentDirectoryFailedException.m +++ src/exceptions/OFChangeCurrentDirectoryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFChecksumMismatchException.h ================================================================== --- src/exceptions/OFChecksumMismatchException.h +++ src/exceptions/OFChecksumMismatchException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFChecksumMismatchException.m ================================================================== --- src/exceptions/OFChecksumMismatchException.m +++ src/exceptions/OFChecksumMismatchException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConditionStillWaitingException.h ================================================================== --- src/exceptions/OFConditionStillWaitingException.h +++ src/exceptions/OFConditionStillWaitingException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConditionStillWaitingException.m ================================================================== --- src/exceptions/OFConditionStillWaitingException.m +++ src/exceptions/OFConditionStillWaitingException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectIPSocketFailedException.h ================================================================== --- src/exceptions/OFConnectIPSocketFailedException.h +++ src/exceptions/OFConnectIPSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectIPSocketFailedException.m ================================================================== --- src/exceptions/OFConnectIPSocketFailedException.m +++ src/exceptions/OFConnectIPSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectSPXSocketFailedException.h ================================================================== --- src/exceptions/OFConnectSPXSocketFailedException.h +++ src/exceptions/OFConnectSPXSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectSPXSocketFailedException.m ================================================================== --- src/exceptions/OFConnectSPXSocketFailedException.m +++ src/exceptions/OFConnectSPXSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -72,13 +72,13 @@ memcpy(node, _node, sizeof(_node)); } - (OFString *)description { - OFData *node = [OFData dataWithItems: _node count: sizeof(_node)]; - return [OFString stringWithFormat: - @"A connection to %@ port %" @PRIu16 @" on network %" @PRIX32 - " could not be established in socket of type %@: %@", - node, _port, _network, [_socket class], OFStrError(_errNo)]; + @"A connection to %02X:%02X:%02X:%02X:%02X:%02X port %" @PRIu16 + @" on network %" @PRIX32 " could not be established in socket of " + @"type %@: %@", + _node[0], _node[1], _node[2], _node[3], _node[4], _node[5], _port, + _network, [_socket class], OFStrError(_errNo)]; } @end Index: src/exceptions/OFConnectSocketFailedException.h ================================================================== --- src/exceptions/OFConnectSocketFailedException.h +++ src/exceptions/OFConnectSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectSocketFailedException.m ================================================================== --- src/exceptions/OFConnectSocketFailedException.m +++ src/exceptions/OFConnectSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectUNIXSocketFailedException.h ================================================================== --- src/exceptions/OFConnectUNIXSocketFailedException.h +++ src/exceptions/OFConnectUNIXSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFConnectUNIXSocketFailedException.m ================================================================== --- src/exceptions/OFConnectUNIXSocketFailedException.m +++ src/exceptions/OFConnectUNIXSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFCopyItemFailedException.h ================================================================== --- src/exceptions/OFCopyItemFailedException.h +++ src/exceptions/OFCopyItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,65 +15,65 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFCopyItemFailedException \ * OFCopyItemFailedException.h ObjFW/OFCopyItemFailedException.h * * @brief An exception indicating that copying a item failed. */ @interface OFCopyItemFailedException: OFException { - OFURI *_sourceURI, *_destinationURI; + OFIRI *_sourceIRI, *_destinationIRI; int _errNo; OF_RESERVE_IVARS(OFCopyItemFailedException, 4) } /** - * @brief The URI of the source item. + * @brief The IRI of the source item. */ -@property (readonly, nonatomic) OFURI *sourceURI; +@property (readonly, nonatomic) OFIRI *sourceIRI; /** - * @brief The destination URI. + * @brief The destination IRI. */ -@property (readonly, nonatomic) OFURI *destinationURI; +@property (readonly, nonatomic) OFIRI *destinationIRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased copy item failed exception. * - * @param sourceURI The URI of the source item - * @param destinationURI The destination URI + * @param sourceIRI The IRI of the source item + * @param destinationIRI The destination IRI * @param errNo The errno of the error that occurred * @return A new, autoreleased copy item failed exception */ -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated copy item failed exception. * - * @param sourceURI The URI of the source item - * @param destinationURI The destination URI + * @param sourceIRI The IRI of the source item + * @param destinationIRI The destination IRI * @param errNo The errno of the error that occurred * @return An initialized copy item failed exception */ -- (instancetype)initWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCopyItemFailedException.m ================================================================== --- src/exceptions/OFCopyItemFailedException.m +++ src/exceptions/OFCopyItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,45 +14,45 @@ */ #include "config.h" #import "OFCopyItemFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFCopyItemFailedException -@synthesize sourceURI = _sourceURI, destinationURI = _destinationURI; +@synthesize sourceIRI = _sourceIRI, destinationIRI = _destinationIRI; @synthesize errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { - return [[[self alloc] initWithSourceURI: sourceURI - destinationURI: destinationURI + return [[[self alloc] initWithSourceIRI: sourceIRI + destinationIRI: destinationIRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { self = [super init]; @try { - _sourceURI = [sourceURI copy]; - _destinationURI = [destinationURI copy]; + _sourceIRI = [sourceIRI copy]; + _destinationIRI = [destinationIRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -60,17 +60,17 @@ return self; } - (void)dealloc { - [_sourceURI release]; - [_destinationURI release]; + [_sourceIRI release]; + [_destinationIRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: @"Failed to copy item %@ to %@: %@", - _sourceURI, _destinationURI, OFStrError(_errNo)]; + _sourceIRI, _destinationIRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateDirectoryFailedException.h ================================================================== --- src/exceptions/OFCreateDirectoryFailedException.h +++ src/exceptions/OFCreateDirectoryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFCreateDirectoryFailedException \ * OFCreateDirectoryFailedException.h \ * ObjFW/OFCreateDirectoryFailedException.h @@ -26,45 +26,45 @@ * * @brief An exception indicating a directory couldn't be created. */ @interface OFCreateDirectoryFailedException: OFException { - OFURI *_URI; + OFIRI *_IRI; int _errNo; OF_RESERVE_IVARS(OFCreateDirectoryFailedException, 4) } /** - * @brief The URI of the directory which couldn't be created. + * @brief The IRI of the directory which couldn't be created. */ -@property (readonly, nonatomic) OFURI *URI; +@property (readonly, nonatomic) OFIRI *IRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased create directory failed exception. * - * @param URI The URI of the directory which could not be created + * @param IRI The IRI of the directory which could not be created * @param errNo The errno of the error that occurred * @return A new, autoreleased create directory failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo; ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create directory failed exception. * - * @param URI The URI of the directory which could not be created + * @param IRI The IRI of the directory which could not be created * @param errNo The errno of the error that occurred * @return An initialized create directory failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCreateDirectoryFailedException.m ================================================================== --- src/exceptions/OFCreateDirectoryFailedException.m +++ src/exceptions/OFCreateDirectoryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,37 +14,37 @@ */ #include "config.h" #import "OFCreateDirectoryFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFCreateDirectoryFailedException -@synthesize URI = _URI, errNo = _errNo; +@synthesize IRI = _IRI, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo { - return [[[self alloc] initWithURI: URI errNo: errNo] autorelease]; + return [[[self alloc] initWithIRI: IRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI errNo: (int)errNo +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -52,16 +52,16 @@ return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to create directory %@: %@", _URI, OFStrError(_errNo)]; + @"Failed to create directory %@: %@", _IRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateSymbolicLinkFailedException.h ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.h +++ src/exceptions/OFCreateSymbolicLinkFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFCreateSymbolicLinkFailedException \ * OFCreateSymbolicLinkFailedException.h \ * ObjFW/OFCreateSymbolicLinkFailedException.h @@ -26,20 +26,20 @@ * * @brief An exception indicating that creating a symbolic link failed. */ @interface OFCreateSymbolicLinkFailedException: OFException { - OFURI *_URI; + OFIRI *_IRI; OFString *_target; int _errNo; OF_RESERVE_IVARS(OFCreateSymbolicLinkFailedException, 4) } /** - * @brief The URI at which the symlink should have been created. + * @brief The IRI at which the symlink should have been created. */ -@property (readonly, nonatomic) OFURI *URI; +@property (readonly, nonatomic) OFIRI *IRI; /** * @brief The target for the symlink. */ @property (readonly, nonatomic) OFString *target; @@ -50,33 +50,33 @@ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased create symbolic link failed exception. * - * @param URI The URI where the symlink should have been created + * @param IRI The IRI where the symlink should have been created * @param target The target for the symbolic link * @param errNo The errno of the error that occurred * @return A new, autoreleased create symbolic link failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI target: (OFString *)target errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated create symbolic link failed * exception. * - * @param URI The URI where the symlink should have been created + * @param IRI The IRI where the symlink should have been created * @param target The target for the symbolic link * @param errNo The errno of the error that occurred * @return An initialized create symbolic link failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI target: (OFString *)target errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFCreateSymbolicLinkFailedException.m ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.m +++ src/exceptions/OFCreateSymbolicLinkFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,43 +14,43 @@ */ #include "config.h" #import "OFCreateSymbolicLinkFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFCreateSymbolicLinkFailedException -@synthesize URI = _URI, target = _target, errNo = _errNo; +@synthesize IRI = _IRI, target = _target, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI target: (OFString *)target errNo: (int)errNo { - return [[[self alloc] initWithURI: URI + return [[[self alloc] initWithIRI: IRI target: target errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI target: (OFString *)target errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _target = [target copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; @@ -59,18 +59,18 @@ return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [_target release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: @"Failed to create symbolic link %@ with target %@: %@", - _URI, _target, OFStrError(_errNo)]; + _IRI, _target, OFStrError(_errNo)]; } @end Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.h +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFCreateWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFCreateWindowsRegistryKeyFailedException.m +++ src/exceptions/OFCreateWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDNSQueryFailedException.h ================================================================== --- src/exceptions/OFDNSQueryFailedException.h +++ src/exceptions/OFDNSQueryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDNSQueryFailedException.m ================================================================== --- src/exceptions/OFDNSQueryFailedException.m +++ src/exceptions/OFDNSQueryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.h +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFDeleteWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFDeleteWindowsRegistryValueFailedException.m +++ src/exceptions/OFDeleteWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFEnumerationMutationException.h ================================================================== --- src/exceptions/OFEnumerationMutationException.h +++ src/exceptions/OFEnumerationMutationException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFEnumerationMutationException.m ================================================================== --- src/exceptions/OFEnumerationMutationException.m +++ src/exceptions/OFEnumerationMutationException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFException.h ================================================================== --- src/exceptions/OFException.h +++ src/exceptions/OFException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFGetCurrentDirectoryFailedException.h ================================================================== --- src/exceptions/OFGetCurrentDirectoryFailedException.h +++ src/exceptions/OFGetCurrentDirectoryFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFGetCurrentDirectoryFailedException.m ================================================================== --- src/exceptions/OFGetCurrentDirectoryFailedException.m +++ src/exceptions/OFGetCurrentDirectoryFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFGetItemAttributesFailedException.h ================================================================== --- src/exceptions/OFGetItemAttributesFailedException.h +++ src/exceptions/OFGetItemAttributesFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFGetItemAttributesFailedException \ * OFGetItemAttributesFailedException.h \ * ObjFW/OFGetItemAttributesFailedException.h @@ -26,46 +26,46 @@ * * @brief An exception indicating an item's attributes could not be retrieved. */ @interface OFGetItemAttributesFailedException: OFException { - OFURI *_URI; + OFIRI *_IRI; int _errNo; OF_RESERVE_IVARS(OFGetItemAttributesFailedException, 4) } /** - * @brief The URI of the item whose attributes could not be retrieved. + * @brief The IRI of the item whose attributes could not be retrieved. */ -@property (readonly, nonatomic) OFURI *URI; +@property (readonly, nonatomic) OFIRI *IRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased retrieve item attributes failed exception. * - * @param URI The URI of the item whose attributes could not be retrieved + * @param IRI The IRI of the item whose attributes could not be retrieved * @param errNo The errno of the error that occurred * @return A new, autoreleased retrieve item attributes failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo; ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated retrieve item attributes failed * exception. * - * @param URI The URI of the item whose attributes could not be retrieved + * @param IRI The IRI of the item whose attributes could not be retrieved * @param errNo The errno of the error that occurred * @return An initialized retrieve item attributes failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetItemAttributesFailedException.m ================================================================== --- src/exceptions/OFGetItemAttributesFailedException.m +++ src/exceptions/OFGetItemAttributesFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,37 +14,37 @@ */ #include "config.h" #import "OFGetItemAttributesFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFGetItemAttributesFailedException -@synthesize URI = _URI, errNo = _errNo; +@synthesize IRI = _IRI, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo { - return [[[self alloc] initWithURI: URI errNo: errNo] autorelease]; + return [[[self alloc] initWithIRI: IRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI errNo: (int)errNo +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -52,17 +52,17 @@ return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: @"Failed to get attributes for item %@: %@", - _URI, OFStrError(_errNo)]; + _IRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFGetOptionFailedException.h ================================================================== --- src/exceptions/OFGetOptionFailedException.h +++ src/exceptions/OFGetOptionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,19 +23,19 @@ * * @brief An exception indicating that getting an option for an object failed. */ @interface OFGetOptionFailedException: OFException { - id _object; + id _Nullable _object; int _errNo; OF_RESERVE_IVARS(OFGetOptionFailedException, 4) } /** * @brief The object for which the option could not be retrieved. */ -@property (readonly, nonatomic) id object; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -45,11 +45,11 @@ * * @param object The object for which the option could not be retrieved * @param errNo The errno of the error that occurred * @return A new, autoreleased get option failed exception */ -+ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo; ++ (instancetype)exceptionWithObject: (nullable id)object errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated get option failed exception. @@ -56,12 +56,12 @@ * * @param object The object for which the option could not be retrieved * @param errNo The errno of the error that occurred * @return An initialized get option failed exception */ -- (instancetype)initWithObject: (id)object +- (instancetype)initWithObject: (nullable id)object errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFGetOptionFailedException.m ================================================================== --- src/exceptions/OFGetOptionFailedException.m +++ src/exceptions/OFGetOptionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -53,10 +53,14 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"Getting an option in an object of type %@ failed: %@", - [_object class], OFStrError(_errNo)]; + if (_object != nil) + return [OFString stringWithFormat: + @"Getting an option in an object of type %@ failed: %@", + [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Getting an option failed: %@", OFStrError(_errNo)]; } @end Index: src/exceptions/OFGetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.h +++ src/exceptions/OFGetWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFGetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFGetWindowsRegistryValueFailedException.m +++ src/exceptions/OFGetWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFHTTPRequestFailedException.h ================================================================== --- src/exceptions/OFHTTPRequestFailedException.h +++ src/exceptions/OFHTTPRequestFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFHTTPRequestFailedException.m ================================================================== --- src/exceptions/OFHTTPRequestFailedException.m +++ src/exceptions/OFHTTPRequestFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -62,9 +62,9 @@ - (OFString *)description { const char *method = OFHTTPRequestMethodName(_request.method); return [OFString stringWithFormat: - @"An HTTP %s request with URI %@ failed with code %hd!", method, - _request.URI, _response.statusCode]; + @"An HTTP %s request with IRI %@ failed with code %hd!", method, + _request.IRI, _response.statusCode]; } @end Index: src/exceptions/OFHashAlreadyCalculatedException.h ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.h +++ src/exceptions/OFHashAlreadyCalculatedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFHashAlreadyCalculatedException.m ================================================================== --- src/exceptions/OFHashAlreadyCalculatedException.m +++ src/exceptions/OFHashAlreadyCalculatedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFHashNotCalculatedException.h ================================================================== --- src/exceptions/OFHashNotCalculatedException.h +++ src/exceptions/OFHashNotCalculatedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFHashNotCalculatedException.m ================================================================== --- src/exceptions/OFHashNotCalculatedException.m +++ src/exceptions/OFHashNotCalculatedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInitializationFailedException.h ================================================================== --- src/exceptions/OFInitializationFailedException.h +++ src/exceptions/OFInitializationFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInitializationFailedException.m ================================================================== --- src/exceptions/OFInitializationFailedException.m +++ src/exceptions/OFInitializationFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidArgumentException.h ================================================================== --- src/exceptions/OFInvalidArgumentException.h +++ src/exceptions/OFInvalidArgumentException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidArgumentException.m ================================================================== --- src/exceptions/OFInvalidArgumentException.m +++ src/exceptions/OFInvalidArgumentException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidEncodingException.h ================================================================== --- src/exceptions/OFInvalidEncodingException.h +++ src/exceptions/OFInvalidEncodingException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidEncodingException.m ================================================================== --- src/exceptions/OFInvalidEncodingException.m +++ src/exceptions/OFInvalidEncodingException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidFormatException.h ================================================================== --- src/exceptions/OFInvalidFormatException.h +++ src/exceptions/OFInvalidFormatException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidFormatException.m ================================================================== --- src/exceptions/OFInvalidFormatException.m +++ src/exceptions/OFInvalidFormatException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidJSONException.h ================================================================== --- src/exceptions/OFInvalidJSONException.h +++ src/exceptions/OFInvalidJSONException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidJSONException.m ================================================================== --- src/exceptions/OFInvalidJSONException.m +++ src/exceptions/OFInvalidJSONException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidServerResponseException.h ================================================================== --- src/exceptions/OFInvalidServerResponseException.h +++ src/exceptions/OFInvalidServerResponseException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFInvalidServerResponseException.m ================================================================== --- src/exceptions/OFInvalidServerResponseException.m +++ src/exceptions/OFInvalidServerResponseException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFJoinThreadFailedException.h ================================================================== --- src/exceptions/OFJoinThreadFailedException.h +++ src/exceptions/OFJoinThreadFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFJoinThreadFailedException.m ================================================================== --- src/exceptions/OFJoinThreadFailedException.m +++ src/exceptions/OFJoinThreadFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFLinkItemFailedException.h ================================================================== --- src/exceptions/OFLinkItemFailedException.h +++ src/exceptions/OFLinkItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,65 +15,65 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFLinkItemFailedException \ * OFLinkItemFailedException.h ObjFW/OFLinkItemFailedException.h * * @brief An exception indicating that creating a link failed. */ @interface OFLinkItemFailedException: OFException { - OFURI *_sourceURI, *_destinationURI; + OFIRI *_sourceIRI, *_destinationIRI; int _errNo; OF_RESERVE_IVARS(OFLinkItemFailedException, 4) } /** - * @brief A URI with the source for the link. + * @brief An IRI with the source for the link. */ -@property (readonly, nonatomic) OFURI *sourceURI; +@property (readonly, nonatomic) OFIRI *sourceIRI; /** - * @brief A URI with the destination for the link. + * @brief An IRI with the destination for the link. */ -@property (readonly, nonatomic) OFURI *destinationURI; +@property (readonly, nonatomic) OFIRI *destinationIRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased link failed exception. * - * @param sourceURI The source for the link - * @param destinationURI The destination for the link + * @param sourceIRI The source for the link + * @param destinationIRI The destination for the link * @param errNo The errno of the error that occurred * @return A new, autoreleased link failed exception */ -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated link failed exception. * - * @param sourceURI The source for the link - * @param destinationURI The destination for the link + * @param sourceIRI The source for the link + * @param destinationIRI The destination for the link * @param errNo The errno of the error that occurred * @return An initialized link failed exception */ -- (instancetype)initWithSourceURI: (OFURI*)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI*)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLinkItemFailedException.m ================================================================== --- src/exceptions/OFLinkItemFailedException.m +++ src/exceptions/OFLinkItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,45 +14,45 @@ */ #include "config.h" #import "OFLinkItemFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFLinkItemFailedException -@synthesize sourceURI = _sourceURI, destinationURI = _destinationURI; +@synthesize sourceIRI = _sourceIRI, destinationIRI = _destinationIRI; @synthesize errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { - return [[[self alloc] initWithSourceURI: sourceURI - destinationURI: destinationURI + return [[[self alloc] initWithSourceIRI: sourceIRI + destinationIRI: destinationIRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { self = [super init]; @try { - _sourceURI = [sourceURI copy]; - _destinationURI = [destinationURI copy]; + _sourceIRI = [sourceIRI copy]; + _destinationIRI = [destinationIRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -60,17 +60,17 @@ return self; } - (void)dealloc { - [_sourceURI release]; - [_destinationURI release]; + [_sourceIRI release]; + [_destinationIRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: @"Failed to link file %@ to %@: %@", - _sourceURI, _destinationURI, OFStrError(_errNo)]; + _sourceIRI, _destinationIRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFListenOnSocketFailedException.h ================================================================== --- src/exceptions/OFListenOnSocketFailedException.h +++ src/exceptions/OFListenOnSocketFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFListenOnSocketFailedException.m ================================================================== --- src/exceptions/OFListenOnSocketFailedException.m +++ src/exceptions/OFListenOnSocketFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFLoadPluginFailedException.h ================================================================== --- src/exceptions/OFLoadPluginFailedException.h +++ src/exceptions/OFLoadPluginFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFLoadPluginFailedException.m ================================================================== --- src/exceptions/OFLoadPluginFailedException.m +++ src/exceptions/OFLoadPluginFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFLockFailedException.h ================================================================== --- src/exceptions/OFLockFailedException.h +++ src/exceptions/OFLockFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFLockFailedException.m ================================================================== --- src/exceptions/OFLockFailedException.m +++ src/exceptions/OFLockFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFMalformedXMLException.h ================================================================== --- src/exceptions/OFMalformedXMLException.h +++ src/exceptions/OFMalformedXMLException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFMalformedXMLException.m ================================================================== --- src/exceptions/OFMalformedXMLException.m +++ src/exceptions/OFMalformedXMLException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFMoveItemFailedException.h ================================================================== --- src/exceptions/OFMoveItemFailedException.h +++ src/exceptions/OFMoveItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,65 +15,65 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFMoveItemFailedException \ * OFMoveItemFailedException.h ObjFW/OFMoveItemFailedException.h * * @brief An exception indicating that moving an item failed. */ @interface OFMoveItemFailedException: OFException { - OFURI *_sourceURI, *_destinationURI; + OFIRI *_sourceIRI, *_destinationIRI; int _errNo; OF_RESERVE_IVARS(OFMoveItemFailedException, 4) } /** - * @brief The original URI. + * @brief The original IRI. */ -@property (readonly, nonatomic) OFURI *sourceURI; +@property (readonly, nonatomic) OFIRI *sourceIRI; /** - * @brief The new URI. + * @brief The new IRI. */ -@property (readonly, nonatomic) OFURI *destinationURI; +@property (readonly, nonatomic) OFIRI *destinationIRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased move item failed exception. * - * @param sourceURI The original URI - * @param destinationURI The new URI + * @param sourceIRI The original IRI + * @param destinationIRI The new IRI * @param errNo The errno of the error that occurred * @return A new, autoreleased move item failed exception */ -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated move item failed exception. * - * @param sourceURI The original URI - * @param destinationURI The new URI + * @param sourceIRI The original IRI + * @param destinationIRI The new IRI * @param errNo The errno of the error that occurred * @return An initialized move item failed exception */ -- (instancetype)initWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFMoveItemFailedException.m ================================================================== --- src/exceptions/OFMoveItemFailedException.m +++ src/exceptions/OFMoveItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,45 +14,45 @@ */ #include "config.h" #import "OFMoveItemFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFMoveItemFailedException -@synthesize sourceURI = _sourceURI, destinationURI = _destinationURI; +@synthesize sourceIRI = _sourceIRI, destinationIRI = _destinationIRI; @synthesize errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI ++ (instancetype)exceptionWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { - return [[[self alloc] initWithSourceURI: sourceURI - destinationURI: destinationURI + return [[[self alloc] initWithSourceIRI: sourceIRI + destinationIRI: destinationIRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSourceURI: (OFURI *)sourceURI - destinationURI: (OFURI *)destinationURI +- (instancetype)initWithSourceIRI: (OFIRI *)sourceIRI + destinationIRI: (OFIRI *)destinationIRI errNo: (int)errNo { self = [super init]; @try { - _sourceURI = [sourceURI copy]; - _destinationURI = [destinationURI copy]; + _sourceIRI = [sourceIRI copy]; + _destinationIRI = [destinationIRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -60,18 +60,18 @@ return self; } - (void)dealloc { - [_sourceURI release]; - [_destinationURI release]; + [_sourceIRI release]; + [_destinationIRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: @"Failed to move item at %@ to %@: %@", - _sourceURI, _destinationURI, OFStrError(_errNo)]; + _sourceIRI, _destinationIRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFNotImplementedException.h ================================================================== --- src/exceptions/OFNotImplementedException.h +++ src/exceptions/OFNotImplementedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFNotImplementedException.m ================================================================== --- src/exceptions/OFNotImplementedException.m +++ src/exceptions/OFNotImplementedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFNotOpenException.h ================================================================== --- src/exceptions/OFNotOpenException.h +++ src/exceptions/OFNotOpenException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFNotOpenException.m ================================================================== --- src/exceptions/OFNotOpenException.m +++ src/exceptions/OFNotOpenException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFObserveKernelEventsFailedException.h ================================================================== --- src/exceptions/OFObserveKernelEventsFailedException.h +++ src/exceptions/OFObserveKernelEventsFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFObserveKernelEventsFailedException.m ================================================================== --- src/exceptions/OFObserveKernelEventsFailedException.m +++ src/exceptions/OFObserveKernelEventsFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOpenItemFailedException.h ================================================================== --- src/exceptions/OFOpenItemFailedException.h +++ src/exceptions/OFOpenItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,31 +15,31 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFOpenItemFailedException \ * OFOpenItemFailedException.h ObjFW/OFOpenItemFailedException.h * * @brief An exception indicating an item could not be opened. */ @interface OFOpenItemFailedException: OFException { - OFURI *_Nullable _URI; + OFIRI *_Nullable _IRI; OFString *_Nullable _path; OFString *_mode; int _errNo; OF_RESERVE_IVARS(OFOpenItemFailedException, 4) } /** - * @brief The URI of the item which could not be opened. + * @brief The IRI of the item which could not be opened. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFURI *URI; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFIRI *IRI; /** * @brief The path of the item which could not be opened. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; @@ -55,16 +55,16 @@ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased open item failed exception. * - * @param URI The URI of the item which could not be opened + * @param IRI The IRI of the item which could not be opened * @param mode A string with the mode in which the item should have been opened * @param errNo The errno of the error that occurred * @return A new, autoreleased open item failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI mode: (nullable OFString *)mode errNo: (int)errNo; /** * @brief Creates a new, autoreleased open item failed exception. @@ -81,16 +81,16 @@ + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated open item failed exception. * - * @param URI The URI of the item which could not be opened + * @param IRI The IRI of the item which could not be opened * @param mode A string with the mode in which the item should have been opened * @param errNo The errno of the error that occurred * @return An initialized open item failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (nullable OFString *)mode errNo: (int)errNo; /** * @brief Initializes an already allocated open item failed exception. Index: src/exceptions/OFOpenItemFailedException.m ================================================================== --- src/exceptions/OFOpenItemFailedException.m +++ src/exceptions/OFOpenItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,21 +14,21 @@ */ #include "config.h" #import "OFOpenItemFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFOpenItemFailedException -@synthesize URI = _URI, path = _path, mode = _mode, errNo = _errNo; +@synthesize IRI = _IRI, path = _path, mode = _mode, errNo = _errNo; -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI mode: (OFString *)mode errNo: (int)errNo { - return [[[self alloc] initWithURI: URI + return [[[self alloc] initWithIRI: IRI mode: mode errNo: errNo] autorelease]; } + (instancetype)exceptionWithPath: (OFString *)path @@ -43,18 +43,18 @@ + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI mode: (OFString *)mode errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _mode = [mode copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; @@ -86,11 +86,11 @@ OF_INVALID_INIT_METHOD } - (void)dealloc { - [_URI release]; + [_IRI release]; [_path release]; [_mode release]; [super dealloc]; } @@ -97,12 +97,12 @@ - (OFString *)description { id item = nil; - if (_URI != nil) - item = _URI; + if (_IRI != nil) + item = _IRI; else if (_path != nil) item = _path; if (_mode != nil) return [OFString stringWithFormat: Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.h ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.h +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOpenWindowsRegistryKeyFailedException.m ================================================================== --- src/exceptions/OFOpenWindowsRegistryKeyFailedException.m +++ src/exceptions/OFOpenWindowsRegistryKeyFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOutOfMemoryException.h ================================================================== --- src/exceptions/OFOutOfMemoryException.h +++ src/exceptions/OFOutOfMemoryException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOutOfMemoryException.m ================================================================== --- src/exceptions/OFOutOfMemoryException.m +++ src/exceptions/OFOutOfMemoryException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOutOfRangeException.h ================================================================== --- src/exceptions/OFOutOfRangeException.h +++ src/exceptions/OFOutOfRangeException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFOutOfRangeException.m ================================================================== --- src/exceptions/OFOutOfRangeException.m +++ src/exceptions/OFOutOfRangeException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFReadFailedException.h ================================================================== --- src/exceptions/OFReadFailedException.h +++ src/exceptions/OFReadFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFReadFailedException.m ================================================================== --- src/exceptions/OFReadFailedException.m +++ src/exceptions/OFReadFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFReadOrWriteFailedException.h ================================================================== --- src/exceptions/OFReadOrWriteFailedException.h +++ src/exceptions/OFReadOrWriteFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFReadOrWriteFailedException.m ================================================================== --- src/exceptions/OFReadOrWriteFailedException.m +++ src/exceptions/OFReadOrWriteFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFRemoveItemFailedException.h ================================================================== --- src/exceptions/OFRemoveItemFailedException.h +++ src/exceptions/OFRemoveItemFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,55 +15,55 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFRemoveItemFailedException \ * OFRemoveItemFailedException.h ObjFW/OFRemoveItemFailedException.h * * @brief An exception indicating that removing an item failed. */ @interface OFRemoveItemFailedException: OFException { - OFURI *_URI; + OFIRI *_IRI; int _errNo; OF_RESERVE_IVARS(OFRemoveItemFailedException, 4) } /** - * @brief The URI of the item which could not be removed. + * @brief The IRI of the item which could not be removed. */ -@property (readonly, nonatomic) OFURI *URI; +@property (readonly, nonatomic) OFIRI *IRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased remove failed exception. * - * @param URI The URI of the item which could not be removed + * @param IRI The IRI of the item which could not be removed * @param errNo The errno of the error that occurred * @return A new, autoreleased remove item failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo; ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated remove failed exception. * - * @param URI The URI of the item which could not be removed + * @param IRI The IRI of the item which could not be removed * @param errNo The errno of the error that occurred * @return An initialized remove item failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFRemoveItemFailedException.m ================================================================== --- src/exceptions/OFRemoveItemFailedException.m +++ src/exceptions/OFRemoveItemFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,37 +14,37 @@ */ #include "config.h" #import "OFRemoveItemFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFRemoveItemFailedException -@synthesize URI = _URI, errNo = _errNo; +@synthesize IRI = _IRI, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURI: (OFURI *)URI errNo: (int)errNo ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI errNo: (int)errNo { - return [[[self alloc] initWithURI: URI errNo: errNo] autorelease]; + return [[[self alloc] initWithIRI: IRI errNo: errNo] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI errNo: (int)errNo +- (instancetype)initWithIRI: (OFIRI *)IRI errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _errNo = errNo; } @catch (id e) { [self release]; @throw e; } @@ -52,16 +52,16 @@ return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [super dealloc]; } - (OFString *)description { return [OFString stringWithFormat: - @"Failed to remove item at URI %@: %@", _URI, OFStrError(_errNo)]; + @"Failed to remove item at IRI %@: %@", _IRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFResolveHostFailedException.h ================================================================== --- src/exceptions/OFResolveHostFailedException.h +++ src/exceptions/OFResolveHostFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFResolveHostFailedException.m ================================================================== --- src/exceptions/OFResolveHostFailedException.m +++ src/exceptions/OFResolveHostFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSeekFailedException.h ================================================================== --- src/exceptions/OFSeekFailedException.h +++ src/exceptions/OFSeekFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSeekFailedException.m ================================================================== --- src/exceptions/OFSeekFailedException.m +++ src/exceptions/OFSeekFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSetItemAttributesFailedException.h ================================================================== --- src/exceptions/OFSetItemAttributesFailedException.h +++ src/exceptions/OFSetItemAttributesFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,15 +12,15 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFException.h" -#import "OFURIHandler.h" +#import "OFIRIHandler.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFSetItemAttributesFailedException \ * OFSetItemAttributesFailedException.h \ * ObjFW/OFSetItemAttributesFailedException.h @@ -27,21 +27,21 @@ * * @brief An exception indicating an item's attributes could not be set. */ @interface OFSetItemAttributesFailedException: OFException { - OFURI *_URI; + OFIRI *_IRI; OFFileAttributes _attributes; OFFileAttributeKey _failedAttribute; int _errNo; OF_RESERVE_IVARS(OFSetItemAttributesFailedException, 4) } /** - * @brief The URI of the item whose attributes could not be set. + * @brief The IRI of the item whose attributes could not be set. */ -@property (readonly, nonatomic) OFURI *URI; +@property (readonly, nonatomic) OFIRI *IRI; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -57,38 +57,38 @@ @property (readonly, nonatomic) OFFileAttributeKey failedAttribute; /** * @brief Creates a new, autoreleased set item attributes failed exception. * - * @param URI The URI of the item whose attributes could not be set + * @param IRI The IRI of the item whose attributes could not be set * @param attributes The attributes that should have been set for the specified * item. * @param failedAttribute The first attribute that could not be set * @param errNo The errno of the error that occurred * @return A new, autoreleased set item attributes failed exception */ -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set item attributes failed exception. * - * @param URI The URI of the item whose attributes could not be set + * @param IRI The IRI of the item whose attributes could not be set * @param attributes The attributes that should have been set for the specified * item. * @param failedAttribute The first attribute that could not be set * @param errNo The errno of the error that occurred * @return An initialized set item attributes failed exception */ -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetItemAttributesFailedException.m ================================================================== --- src/exceptions/OFSetItemAttributesFailedException.m +++ src/exceptions/OFSetItemAttributesFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,28 +14,28 @@ */ #include "config.h" #import "OFSetItemAttributesFailedException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFSetItemAttributesFailedException -@synthesize URI = _URI, attributes = _attributes; +@synthesize IRI = _IRI, attributes = _attributes; @synthesize failedAttribute = _failedAttribute, errNo = _errNo; + (instancetype)exception { OF_UNRECOGNIZED_SELECTOR } -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo { - return [[[self alloc] initWithURI: URI + return [[[self alloc] initWithIRI: IRI attributes: attributes failedAttribute: failedAttribute errNo: errNo] autorelease]; } @@ -42,19 +42,19 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI attributes: (OFFileAttributes)attributes failedAttribute: (OFFileAttributeKey)failedAttribute errNo: (int)errNo { self = [super init]; @try { - _URI = [URI copy]; + _IRI = [IRI copy]; _attributes = [attributes copy]; _failedAttribute = [failedAttribute copy]; _errNo = errNo; } @catch (id e) { [self release]; @@ -64,11 +64,11 @@ return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [_attributes release]; [_failedAttribute release]; [super dealloc]; } @@ -75,8 +75,8 @@ - (OFString *)description { return [OFString stringWithFormat: @"Failed to set attribute %@ for item %@: %@", - _failedAttribute, _URI, OFStrError(_errNo)]; + _failedAttribute, _IRI, OFStrError(_errNo)]; } @end Index: src/exceptions/OFSetOptionFailedException.h ================================================================== --- src/exceptions/OFSetOptionFailedException.h +++ src/exceptions/OFSetOptionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -23,19 +23,19 @@ * * @brief An exception indicating that setting an option for an object failed. */ @interface OFSetOptionFailedException: OFException { - id _object; + id _Nullable _object; int _errNo; OF_RESERVE_IVARS(OFSetOptionFailedException, 4) } /** * @brief The object for which the option could not be set. */ -@property (readonly, nonatomic) id object; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) id object; /** * @brief The errno of the error that occurred. */ @property (readonly, nonatomic) int errNo; @@ -45,11 +45,11 @@ * * @param object The object for which the option could not be set * @param errNo The errno of the error that occurred * @return A new, autoreleased set option failed exception */ -+ (instancetype)exceptionWithObject: (id)object errNo: (int)errNo; ++ (instancetype)exceptionWithObject: (nullable id)object errNo: (int)errNo; + (instancetype)exception OF_UNAVAILABLE; /** * @brief Initializes an already allocated set option failed exception. @@ -56,12 +56,12 @@ * * @param object The object for which the option could not be set * @param errNo The errno of the error that occurred * @return An initialized set option failed exception */ -- (instancetype)initWithObject: (id)object +- (instancetype)initWithObject: (nullable id)object errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFSetOptionFailedException.m ================================================================== --- src/exceptions/OFSetOptionFailedException.m +++ src/exceptions/OFSetOptionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -53,10 +53,14 @@ [super dealloc]; } - (OFString *)description { - return [OFString stringWithFormat: - @"Setting an option in an object of type %@ failed: %@", - [_object class], OFStrError(_errNo)]; + if (_object != nil) + return [OFString stringWithFormat: + @"Setting an option in an object of type %@ failed: %@", + [_object class], OFStrError(_errNo)]; + else + return [OFString stringWithFormat: + @"Setting an option failed: %@", OFStrError(_errNo)]; } @end Index: src/exceptions/OFSetWindowsRegistryValueFailedException.h ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.h +++ src/exceptions/OFSetWindowsRegistryValueFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSetWindowsRegistryValueFailedException.m ================================================================== --- src/exceptions/OFSetWindowsRegistryValueFailedException.m +++ src/exceptions/OFSetWindowsRegistryValueFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSignalConditionFailedException.h ================================================================== --- src/exceptions/OFSignalConditionFailedException.h +++ src/exceptions/OFSignalConditionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFSignalConditionFailedException.m ================================================================== --- src/exceptions/OFSignalConditionFailedException.m +++ src/exceptions/OFSignalConditionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFStartThreadFailedException.h ================================================================== --- src/exceptions/OFStartThreadFailedException.h +++ src/exceptions/OFStartThreadFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFStartThreadFailedException.m ================================================================== --- src/exceptions/OFStartThreadFailedException.m +++ src/exceptions/OFStartThreadFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFStillLockedException.h ================================================================== --- src/exceptions/OFStillLockedException.h +++ src/exceptions/OFStillLockedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFStillLockedException.m ================================================================== --- src/exceptions/OFStillLockedException.m +++ src/exceptions/OFStillLockedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFTLSHandshakeFailedException.h ================================================================== --- src/exceptions/OFTLSHandshakeFailedException.h +++ src/exceptions/OFTLSHandshakeFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFTLSHandshakeFailedException.m ================================================================== --- src/exceptions/OFTLSHandshakeFailedException.m +++ src/exceptions/OFTLSHandshakeFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFThreadStillRunningException.h ================================================================== --- src/exceptions/OFThreadStillRunningException.h +++ src/exceptions/OFThreadStillRunningException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFThreadStillRunningException.m ================================================================== --- src/exceptions/OFThreadStillRunningException.m +++ src/exceptions/OFThreadStillRunningException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFTruncatedDataException.h ================================================================== --- src/exceptions/OFTruncatedDataException.h +++ src/exceptions/OFTruncatedDataException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFTruncatedDataException.m ================================================================== --- src/exceptions/OFTruncatedDataException.m +++ src/exceptions/OFTruncatedDataException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnboundNamespaceException.h ================================================================== --- src/exceptions/OFUnboundNamespaceException.h +++ src/exceptions/OFUnboundNamespaceException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnboundNamespaceException.m ================================================================== --- src/exceptions/OFUnboundNamespaceException.m +++ src/exceptions/OFUnboundNamespaceException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnboundPrefixException.h ================================================================== --- src/exceptions/OFUnboundPrefixException.h +++ src/exceptions/OFUnboundPrefixException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnboundPrefixException.m ================================================================== --- src/exceptions/OFUnboundPrefixException.m +++ src/exceptions/OFUnboundPrefixException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUndefinedKeyException.h ================================================================== --- src/exceptions/OFUndefinedKeyException.h +++ src/exceptions/OFUndefinedKeyException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUndefinedKeyException.m ================================================================== --- src/exceptions/OFUndefinedKeyException.m +++ src/exceptions/OFUndefinedKeyException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnknownXMLEntityException.h ================================================================== --- src/exceptions/OFUnknownXMLEntityException.h +++ src/exceptions/OFUnknownXMLEntityException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnknownXMLEntityException.m ================================================================== --- src/exceptions/OFUnknownXMLEntityException.m +++ src/exceptions/OFUnknownXMLEntityException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnlockFailedException.h ================================================================== --- src/exceptions/OFUnlockFailedException.h +++ src/exceptions/OFUnlockFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnlockFailedException.m ================================================================== --- src/exceptions/OFUnlockFailedException.m +++ src/exceptions/OFUnlockFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnsupportedProtocolException.h ================================================================== --- src/exceptions/OFUnsupportedProtocolException.h +++ src/exceptions/OFUnsupportedProtocolException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,44 +15,44 @@ #import "OFException.h" OF_ASSUME_NONNULL_BEGIN -@class OFURI; +@class OFIRI; /** * @class OFUnsupportedProtocolException \ * OFUnsupportedProtocolException.h \ * ObjFW/OFUnsupportedProtocolException.h * - * @brief An exception indicating that the protocol specified by the URI is not + * @brief An exception indicating that the protocol specified by the IRI is not * supported. */ @interface OFUnsupportedProtocolException: OFException { - OFURI *_Nullable _URI; + OFIRI *_Nullable _IRI; OF_RESERVE_IVARS(OFUnsupportedProtocolException, 4) } /** - * @brief The URI whose protocol is unsupported. + * @brief The IRI whose protocol is unsupported. */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFURI *URI; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFIRI *IRI; /** * @brief Creates a new, autoreleased unsupported protocol exception. * - * @param URI The URI whose protocol is unsupported + * @param IRI The IRI whose protocol is unsupported * @return A new, autoreleased unsupported protocol exception */ -+ (instancetype)exceptionWithURI: (nullable OFURI*)URI; ++ (instancetype)exceptionWithIRI: (nullable OFIRI*)IRI; /** * @brief Initializes an already allocated unsupported protocol exception * - * @param URI The URI whose protocol is unsupported + * @param IRI The IRI whose protocol is unsupported * @return An initialized unsupported protocol exception */ -- (instancetype)initWithURI: (nullable OFURI*)URI OF_DESIGNATED_INITIALIZER; +- (instancetype)initWithIRI: (nullable OFIRI*)IRI OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnsupportedProtocolException.m ================================================================== --- src/exceptions/OFUnsupportedProtocolException.m +++ src/exceptions/OFUnsupportedProtocolException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,41 +14,41 @@ */ #include "config.h" #import "OFUnsupportedProtocolException.h" +#import "OFIRI.h" #import "OFString.h" -#import "OFURI.h" @implementation OFUnsupportedProtocolException -@synthesize URI = _URI; +@synthesize IRI = _IRI; -+ (instancetype)exceptionWithURI: (OFURI *)URI ++ (instancetype)exceptionWithIRI: (OFIRI *)IRI { - return [[[self alloc] initWithURI: URI] autorelease]; + return [[[self alloc] initWithIRI: IRI] autorelease]; } -- (instancetype)initWithURI: (OFURI *)URI +- (instancetype)initWithIRI: (OFIRI *)IRI { self = [super init]; - _URI = [URI retain]; + _IRI = [IRI retain]; return self; } - (void)dealloc { - [_URI release]; + [_IRI release]; [super dealloc]; } - (OFString *)description { - if (_URI != nil) + if (_IRI != nil) return [OFString stringWithFormat: - @"The protocol of URI %@ is not supported!", _URI]; + @"The protocol of IRI %@ is not supported!", _IRI]; else return @"The requested protocol is unsupported!"; } @end Index: src/exceptions/OFUnsupportedVersionException.h ================================================================== --- src/exceptions/OFUnsupportedVersionException.h +++ src/exceptions/OFUnsupportedVersionException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFUnsupportedVersionException.m ================================================================== --- src/exceptions/OFUnsupportedVersionException.m +++ src/exceptions/OFUnsupportedVersionException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFWaitForConditionFailedException.h ================================================================== --- src/exceptions/OFWaitForConditionFailedException.h +++ src/exceptions/OFWaitForConditionFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFWaitForConditionFailedException.m ================================================================== --- src/exceptions/OFWaitForConditionFailedException.m +++ src/exceptions/OFWaitForConditionFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFWriteFailedException.h ================================================================== --- src/exceptions/OFWriteFailedException.h +++ src/exceptions/OFWriteFailedException.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/exceptions/OFWriteFailedException.m ================================================================== --- src/exceptions/OFWriteFailedException.m +++ src/exceptions/OFWriteFailedException.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/forwarding/apple-forwarding-amd64.S Index: src/forwarding/apple-forwarding-amd64.S ================================================================== --- src/forwarding/apple-forwarding-amd64.S +++ src/forwarding/apple-forwarding-amd64.S @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +.globl _OFForward +.globl _OFForward_stret + +.section __TEXT, __objc_methname, cstring_literals +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section __DATA, __objc_selrefs, literal_pointers, no_dead_strip +sel_forwardingTargetForSelector_: + .quad str_forwardingTargetForSelector_ + +.section __DATA, __objc_imageinfo, regular, no_dead_strip + .long 0, 0 + +.section __TEXT, __text, regular, pure_instructions +_OFForward: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + call _object_getClass + + movq %rax, %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + call _class_respondsToSelector + + testq %rax, %rax + jz 0f + + movq -0x10(%rbp), %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x18(%rbp), %rdx + call _objc_msgSend + + testq %rax, %rax + jz 0f + cmpq -0x10(%rbp), %rax + je 0f + + movq %rax, %rdi + + /* Restore all arguments, except %rdi */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x18(%rbp), %rsi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmp _objc_msgSend + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + + movq %rbp, %rsp + popq %rbp + + jmp _OFMethodNotFound + +_OFForward_stret: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + movq %rsi, %rdi + call _object_getClass + + movq %rax, %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + call _class_respondsToSelector + testq %rax, %rax + jz 0f + + movq -0x18(%rbp), %rdi + movq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x20(%rbp), %rdx + call _objc_msgSend + + testq %rax, %rax + jz 0f + cmpq -0x18(%rbp), %rax + je 0f + + movq %rax, %rsi + + /* Restore all arguments, except %rsi */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x10(%rbp), %rdi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmp _objc_msgSend_stret + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + movq -0x20(%rbp), %rdx + + movq %rbp, %rsp + popq %rbp + + jmp _OFMethodNotFound_stret Index: src/forwarding/apple-forwarding-arm.S ================================================================== --- src/forwarding/apple-forwarding-arm.S +++ src/forwarding/apple-forwarding-arm.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/forwarding/apple-forwarding-arm64.S ================================================================== --- src/forwarding/apple-forwarding-arm64.S +++ src/forwarding/apple-forwarding-arm64.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/forwarding/apple-forwarding-i386.S Index: src/forwarding/apple-forwarding-i386.S ================================================================== --- src/forwarding/apple-forwarding-i386.S +++ src/forwarding/apple-forwarding-i386.S @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -.globl _OFForward -.globl _OFForward_stret - -.section __TEXT, __cstring, cstring_literals -str_forwardingTargetForSelector_: - .asciz "forwardingTargetForSelector:" - -.section __OBJC, __message_refs, literal_pointers, no_dead_strip -sel_forwardingTargetForSelector_: - .long str_forwardingTargetForSelector_ - -.section __OBJC, __image_info - .long 0, 0 - -.section __TEXT, __text, regular, pure_instructions -_OFForward: - pushl %ebp - movl %esp, %ebp - - pushl %ebx - subl $20, %esp - - call get_eip -0: - - movl 8(%ebp), %eax - movl %eax, (%esp) - call _object_getClass - - movl %eax, (%esp) - movl sel_forwardingTargetForSelector_-0b(%ebx), %eax - movl %eax, 4(%esp) - call _class_respondsToSelector - - testl %eax, %eax - jz 0f - - movl 8(%ebp), %eax - movl %eax, (%esp) - movl sel_forwardingTargetForSelector_-0b(%ebx), %eax - movl %eax, 4(%esp) - movl 12(%ebp), %eax - movl %eax, 8(%esp) - call _objc_msgSend - - testl %eax, %eax - jz 0f - cmpl 8(%ebp), %eax - je 0f - - movl %eax, 8(%ebp) - - addl $20, %esp - popl %ebx - popl %ebp - - jmp _objc_msgSend - -0: - addl $20, %esp - popl %ebx - popl %ebp - - jmp _OFMethodNotFound - -_OFForward_stret: - pushl %ebp - movl %esp, %ebp - - pushl %ebx - subl $20, %esp - - call get_eip -0: - - movl 12(%ebp), %eax - movl %eax, (%esp) - call _object_getClass - - movl %eax, (%esp) - movl sel_forwardingTargetForSelector_-0b(%ebx), %eax - movl %eax, 4(%esp) - call _class_respondsToSelector - - testl %eax, %eax - jz 0f - - movl 12(%ebp), %eax - movl %eax, (%esp) - movl sel_forwardingTargetForSelector_-0b(%ebx), %eax - movl %eax, 4(%esp) - movl 16(%ebp), %eax - movl %eax, 8(%esp) - call _objc_msgSend - - testl %eax, %eax - jz 0f - cmpl 12(%ebp), %eax - je 0f - - movl %eax, 12(%ebp) - - addl $20, %esp - popl %ebx - popl %ebp - - jmp _objc_msgSend_stret - -0: - addl $20, %esp - popl %ebx - popl %ebp - - jmp _OFMethodNotFound_stret - -get_eip: - movl (%esp), %ebx - ret Index: src/forwarding/apple-forwarding-powerpc.S ================================================================== --- src/forwarding/apple-forwarding-powerpc.S +++ src/forwarding/apple-forwarding-powerpc.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/forwarding/apple-forwarding-x86.S Index: src/forwarding/apple-forwarding-x86.S ================================================================== --- src/forwarding/apple-forwarding-x86.S +++ src/forwarding/apple-forwarding-x86.S @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +.globl _OFForward +.globl _OFForward_stret + +.section __TEXT, __cstring, cstring_literals +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section __OBJC, __message_refs, literal_pointers, no_dead_strip +sel_forwardingTargetForSelector_: + .long str_forwardingTargetForSelector_ + +.section __OBJC, __image_info + .long 0, 0 + +.section __TEXT, __text, regular, pure_instructions +_OFForward: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + call get_eip +0: + + movl 8(%ebp), %eax + movl %eax, (%esp) + call _object_getClass + + movl %eax, (%esp) + movl sel_forwardingTargetForSelector_-0b(%ebx), %eax + movl %eax, 4(%esp) + call _class_respondsToSelector + + testl %eax, %eax + jz 0f + + movl 8(%ebp), %eax + movl %eax, (%esp) + movl sel_forwardingTargetForSelector_-0b(%ebx), %eax + movl %eax, 4(%esp) + movl 12(%ebp), %eax + movl %eax, 8(%esp) + call _objc_msgSend + + testl %eax, %eax + jz 0f + cmpl 8(%ebp), %eax + je 0f + + movl %eax, 8(%ebp) + + addl $20, %esp + popl %ebx + popl %ebp + + jmp _objc_msgSend + +0: + addl $20, %esp + popl %ebx + popl %ebp + + jmp _OFMethodNotFound + +_OFForward_stret: + pushl %ebp + movl %esp, %ebp + + pushl %ebx + subl $20, %esp + + call get_eip +0: + + movl 12(%ebp), %eax + movl %eax, (%esp) + call _object_getClass + + movl %eax, (%esp) + movl sel_forwardingTargetForSelector_-0b(%ebx), %eax + movl %eax, 4(%esp) + call _class_respondsToSelector + + testl %eax, %eax + jz 0f + + movl 12(%ebp), %eax + movl %eax, (%esp) + movl sel_forwardingTargetForSelector_-0b(%ebx), %eax + movl %eax, 4(%esp) + movl 16(%ebp), %eax + movl %eax, 8(%esp) + call _objc_msgSend + + testl %eax, %eax + jz 0f + cmpl 12(%ebp), %eax + je 0f + + movl %eax, 12(%ebp) + + addl $20, %esp + popl %ebx + popl %ebp + + jmp _objc_msgSend_stret + +0: + addl $20, %esp + popl %ebx + popl %ebp + + jmp _OFMethodNotFound_stret + +get_eip: + movl (%esp), %ebx + ret DELETED src/forwarding/apple-forwarding-x86_64.S Index: src/forwarding/apple-forwarding-x86_64.S ================================================================== --- src/forwarding/apple-forwarding-x86_64.S +++ src/forwarding/apple-forwarding-x86_64.S @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -.globl _OFForward -.globl _OFForward_stret - -.section __TEXT, __objc_methname, cstring_literals -str_forwardingTargetForSelector_: - .asciz "forwardingTargetForSelector:" - -.section __DATA, __objc_selrefs, literal_pointers, no_dead_strip -sel_forwardingTargetForSelector_: - .quad str_forwardingTargetForSelector_ - -.section __DATA, __objc_imageinfo, regular, no_dead_strip - .long 0, 0 - -.section __TEXT, __text, regular, pure_instructions -_OFForward: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - call _object_getClass - - movq %rax, %rdi - movq sel_forwardingTargetForSelector_(%rip), %rsi - call _class_respondsToSelector - - testq %rax, %rax - jz 0f - - movq -0x10(%rbp), %rdi - movq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x18(%rbp), %rdx - call _objc_msgSend - - testq %rax, %rax - jz 0f - cmpq -0x10(%rbp), %rax - je 0f - - movq %rax, %rdi - - /* Restore all arguments, except %rdi */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x18(%rbp), %rsi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmp _objc_msgSend - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - - movq %rbp, %rsp - popq %rbp - - jmp _OFMethodNotFound - -_OFForward_stret: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - movq %rsi, %rdi - call _object_getClass - - movq %rax, %rdi - movq sel_forwardingTargetForSelector_(%rip), %rsi - call _class_respondsToSelector - testq %rax, %rax - jz 0f - - movq -0x18(%rbp), %rdi - movq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x20(%rbp), %rdx - call _objc_msgSend - - testq %rax, %rax - jz 0f - cmpq -0x18(%rbp), %rax - je 0f - - movq %rax, %rsi - - /* Restore all arguments, except %rsi */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x10(%rbp), %rdi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmp _objc_msgSend_stret - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - movq -0x20(%rbp), %rdx - - movq %rbp, %rsp - popq %rbp - - jmp _OFMethodNotFound_stret ADDED src/forwarding/forwarding-amd64-elf.S Index: src/forwarding/forwarding-amd64-elf.S ================================================================== --- src/forwarding/forwarding-amd64-elf.S +++ src/forwarding/forwarding-amd64-elf.S @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include "platform.h" + +.globl OFForward +.globl OFForward_stret + +.section .text +OFForward: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + call object_getClass@PLT + + movq %rax, %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call class_respondsToSelector@PLT + + testq %rax, %rax + jz 0f + + movq -0x10(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call objc_msg_lookup@PLT + + movq -0x10(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x18(%rbp), %rdx + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x10(%rbp), %rax + je 0f + + movq %rax, -0x10(%rbp) + + movq %rax, %rdi + movq -0x18(%rbp), %rsi + call objc_msg_lookup@PLT + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x18(%rbp), %rsi + movq -0x10(%rbp), %rdi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + + movq %rbp, %rsp + popq %rbp + + jmp OFMethodNotFound@PLT +.type OFForward, %function +.size OFForward, .-OFForward + +OFForward_stret: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + movq %rsi, %rdi + call object_getClass@PLT + + movq %rax, %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call class_respondsToSelector@PLT + + testq %rax, %rax + jz 0f + + movq -0x18(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call objc_msg_lookup@PLT + + movq -0x18(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x20(%rbp), %rdx + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x18(%rbp), %rax + je 0f + + movq %rax, -0x18(%rbp) + + movq %rax, %rdi + movq -0x20(%rbp), %rsi + call objc_msg_lookup_stret@PLT + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x18(%rbp), %rsi + movq -0x10(%rbp), %rdi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + movq -0x20(%rbp), %rdx + + movq %rbp, %rsp + popq %rbp + + jmp OFMethodNotFound_stret@PLT +.type OFForward_stret, %function +.size OFForward_stret, .-OFForward_stret + +init: + leaq module(%rip), %rdi + jmp __objc_exec_class@PLT + +#ifdef OF_SOLARIS +.section .init_array, "aw" +#else +.section .ctors, "aw", %progbits +#endif + .quad init + +.section .rodata +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section .data +sel_forwardingTargetForSelector_: + .quad str_forwardingTargetForSelector_, 0 + .quad 0, 0 +symtab: + .quad 0, sel_forwardingTargetForSelector_ + .short 0, 0 + .long 0 + .quad 0 +module: + .quad 8, 32, 0, symtab + +#if defined(OF_LINUX) || defined(OF_HURD) +.section .note.GNU-stack, "", %progbits +#endif ADDED src/forwarding/forwarding-amd64-macho.S Index: src/forwarding/forwarding-amd64-macho.S ================================================================== --- src/forwarding/forwarding-amd64-macho.S +++ src/forwarding/forwarding-amd64-macho.S @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include "platform.h" + +.globl _OFForward +.globl _OFForward_stret + +.section __TEXT, __text, regular, pure_instructions +_OFForward: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + call _object_getClass + + movq %rax, %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call _class_respondsToSelector + + testq %rax, %rax + jz 0f + + movq -0x10(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call _objc_msg_lookup + + movq -0x10(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x18(%rbp), %rdx + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x10(%rbp), %rax + je 0f + + movq %rax, -0x10(%rbp) + + movq %rax, %rdi + movq -0x18(%rbp), %rsi + call _objc_msg_lookup + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x18(%rbp), %rsi + movq -0x10(%rbp), %rdi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + + movq %rbp, %rsp + popq %rbp + + jmp _OFMethodNotFound + +_OFForward_stret: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0xC0, %rsp /* 16-byte alignment */ + movq %rax, -0x8(%rbp) + movq %rdi, -0x10(%rbp) + movq %rsi, -0x18(%rbp) + movq %rdx, -0x20(%rbp) + movq %rcx, -0x28(%rbp) + movq %r8, -0x30(%rbp) + movq %r9, -0x38(%rbp) + movaps %xmm0, -0x50(%rbp) + movaps %xmm1, -0x60(%rbp) + movaps %xmm2, -0x70(%rbp) + movaps %xmm3, -0x80(%rbp) + movaps %xmm4, -0x90(%rbp) + movaps %xmm5, -0xA0(%rbp) + movaps %xmm6, -0xB0(%rbp) + movaps %xmm7, -0xC0(%rbp) + + movq %rsi, %rdi + call _object_getClass + + movq %rax, %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call _class_respondsToSelector + + testq %rax, %rax + jz 0f + + movq -0x18(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + call _objc_msg_lookup + + movq -0x18(%rbp), %rdi + leaq sel_forwardingTargetForSelector_(%rip), %rsi + movq -0x20(%rbp), %rdx + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x18(%rbp), %rax + je 0f + + movq %rax, -0x18(%rbp) + + movq %rax, %rdi + movq -0x20(%rbp), %rsi + call _objc_msg_lookup_stret + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0xC0(%rbp), %xmm7 + movaps -0xB0(%rbp), %xmm6 + movaps -0xA0(%rbp), %xmm5 + movaps -0x90(%rbp), %xmm4 + movaps -0x80(%rbp), %xmm3 + movaps -0x70(%rbp), %xmm2 + movaps -0x60(%rbp), %xmm1 + movaps -0x50(%rbp), %xmm0 + movq -0x38(%rbp), %r9 + movq -0x30(%rbp), %r8 + movq -0x28(%rbp), %rcx + movq -0x20(%rbp), %rdx + movq -0x18(%rbp), %rsi + movq -0x10(%rbp), %rdi + movq -0x8(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x10(%rbp), %rdi + movq -0x18(%rbp), %rsi + movq -0x20(%rbp), %rdx + + movq %rbp, %rsp + popq %rbp + + jmp _OFMethodNotFound_stret + +init: + leaq module(%rip), %rdi + jmp ___objc_exec_class + +.section __DATA, __mod_init_func, mod_init_funcs + .quad init + +.section __TEXT, __cstring, cstring_literals +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section __DATA, __data +sel_forwardingTargetForSelector_: + .quad str_forwardingTargetForSelector_, 0 + .quad 0, 0 +symtab: + .quad 0, sel_forwardingTargetForSelector_ + .short 0, 0 + .long 0 + .quad 0 +module: + .quad 8, 32, 0, symtab ADDED src/forwarding/forwarding-amd64-win64.S Index: src/forwarding/forwarding-amd64-win64.S ================================================================== --- src/forwarding/forwarding-amd64-win64.S +++ src/forwarding/forwarding-amd64-win64.S @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +.globl OFForward +.globl OFForward_stret + +.section .text +OFForward: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0x90, %rsp /* 16-byte alignment */ + movq %rax, -0x28(%rbp) + movq %rcx, -0x30(%rbp) + movq %rdx, -0x38(%rbp) + movq %r8, -0x40(%rbp) + movq %r9, -0x48(%rbp) + movaps %xmm0, -0x60(%rbp) + movaps %xmm1, -0x70(%rbp) + movaps %xmm2, -0x80(%rbp) + movaps %xmm3, -0x90(%rbp) + + call object_getClass + + movq %rax, %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + call class_respondsToSelector + + testq %rax, %rax + jz 0f + + movq -0x30(%rbp), %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + call objc_msg_lookup + + movq -0x30(%rbp), %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + movq -0x38(%rbp), %r8 + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x30(%rbp), %rax + je 0f + + movq %rax, -0x30(%rbp) + + movq %rax, %rcx + movq -0x38(%rbp), %rdx + call objc_msg_lookup + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0x90(%rbp), %xmm3 + movaps -0x80(%rbp), %xmm2 + movaps -0x70(%rbp), %xmm1 + movaps -0x60(%rbp), %xmm0 + movq -0x48(%rbp), %r9 + movq -0x40(%rbp), %r8 + movq -0x38(%rbp), %rdx + movq -0x30(%rbp), %rcx + movq -0x28(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x30(%rbp), %rcx + movq -0x38(%rbp), %rdx + + movq %rbp, %rsp + popq %rbp + + jmp OFMethodNotFound +.def OFForward +.scl 2 +.type 32 +.endef + +OFForward_stret: + pushq %rbp + movq %rsp, %rbp + + /* Save all arguments */ + subq $0x90, %rsp /* 16-byte alignment */ + movq %rax, -0x28(%rbp) + movq %rcx, -0x30(%rbp) + movq %rdx, -0x38(%rbp) + movq %r8, -0x40(%rbp) + movq %r9, -0x48(%rbp) + movaps %xmm0, -0x60(%rbp) + movaps %xmm1, -0x70(%rbp) + movaps %xmm2, -0x80(%rbp) + movaps %xmm3, -0x90(%rbp) + + movq %rdx, %rcx + call object_getClass + + movq %rax, %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + call class_respondsToSelector + + testq %rax, %rax + jz 0f + + movq -0x38(%rbp), %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + call objc_msg_lookup + + movq -0x38(%rbp), %rcx + leaq sel_forwardingTargetForSelector_(%rip), %rdx + movq -0x40(%rbp), %r8 + call *%rax + + testq %rax, %rax + jz 0f + cmpq -0x38(%rbp), %rax + je 0f + + movq %rax, -0x38(%rbp) + + movq %rax, %rcx + movq -0x40(%rbp), %rdx + call objc_msg_lookup_stret + movq %rax, %r11 + + /* Restore all arguments */ + movaps -0x90(%rbp), %xmm3 + movaps -0x80(%rbp), %xmm2 + movaps -0x70(%rbp), %xmm1 + movaps -0x60(%rbp), %xmm0 + movq -0x48(%rbp), %r9 + movq -0x40(%rbp), %r8 + movq -0x38(%rbp), %rdx + movq -0x30(%rbp), %rcx + movq -0x28(%rbp), %rax + + movq %rbp, %rsp + popq %rbp + + jmpq *%r11 + +0: + movq -0x30(%rbp), %rcx + movq -0x38(%rbp), %rdx + movq -0x40(%rbp), %r8 + + movq %rbp, %rsp + popq %rbp + + jmp OFMethodNotFound_stret +.def OFForward_stret +.scl 2 +.type 32 +.endef + +init: + leaq module(%rip), %rcx + jmp __objc_exec_class + +.section .ctors, "aw" + .quad init + +.section .rodata +str_forwardingTargetForSelector_: + .asciz "forwardingTargetForSelector:" + +.section .data +sel_forwardingTargetForSelector_: + .quad str_forwardingTargetForSelector_, 0 + .quad 0, 0 +symtab: + .long 0, 0 + .quad sel_forwardingTargetForSelector_ + .short 0, 0 + .long 0 + .quad 0 +module: + .long 8, 32 + .quad 0, symtab Index: src/forwarding/forwarding-arm-elf.S ================================================================== --- src/forwarding/forwarding-arm-elf.S +++ src/forwarding/forwarding-arm-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -166,8 +166,8 @@ .long 0 .long 0 module: .long 8, 16, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-arm64-elf.S ================================================================== --- src/forwarding/forwarding-arm64-elf.S +++ src/forwarding/forwarding-arm64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -124,8 +124,8 @@ .long 4 .xword 0 module: .xword 8, 32, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-mips-elf.S ================================================================== --- src/forwarding/forwarding-mips-elf.S +++ src/forwarding/forwarding-mips-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -322,8 +322,8 @@ .long 0 .long 0 module: .long 8, 16, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-powerpc-elf.S ================================================================== --- src/forwarding/forwarding-powerpc-elf.S +++ src/forwarding/forwarding-powerpc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -355,8 +355,8 @@ .long OFMethodNotFound .Lgot_OFMethodNotFound_stret: .long OFMethodNotFound_stret #endif -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", @progbits #endif Index: src/forwarding/forwarding-sparc-elf.S ================================================================== --- src/forwarding/forwarding-sparc-elf.S +++ src/forwarding/forwarding-sparc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -188,8 +188,8 @@ .word 0 .word 0 module: .word 8, 16, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-sparc64-elf.S ================================================================== --- src/forwarding/forwarding-sparc64-elf.S +++ src/forwarding/forwarding-sparc64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -248,8 +248,8 @@ .word 0 .xword 0 module: .xword 8, 32, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-x86-elf.S ================================================================== --- src/forwarding/forwarding-x86-elf.S +++ src/forwarding/forwarding-x86-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -26,11 +26,11 @@ movl %esp, %ebp pushl %ebx subl $20, %esp - call get_eip + call getEIP addl $_GLOBAL_OFFSET_TABLE_, %ebx movl 8(%ebp), %eax movl %eax, (%esp) call object_getClass@PLT @@ -73,11 +73,11 @@ popl %ebp jmp *%eax 0: - leal OFMethodNotFound@GOTOFF(%ebx), %eax + movl OFMethodNotFound@GOT(%ebx), %eax addl $20, %esp popl %ebx popl %ebp @@ -90,11 +90,11 @@ movl %esp, %ebp pushl %ebx subl $20, %esp - call get_eip + call getEIP addl $_GLOBAL_OFFSET_TABLE_, %ebx movl 12(%ebp), %eax movl %eax, (%esp) call object_getClass@PLT @@ -137,11 +137,11 @@ popl %ebp jmp *%eax 0: - leal OFMethodNotFound_stret@GOTOFF(%ebx), %eax + movl OFMethodNotFound_stret@GOT(%ebx), %eax addl $20, %esp popl %ebx popl %ebp @@ -154,11 +154,11 @@ movl %esp, %ebp pushl %ebx subl $4, %esp - call get_eip + call getEIP addl $_GLOBAL_OFFSET_TABLE_, %ebx leal module@GOTOFF(%ebx), %eax movl %eax, (%esp) call __objc_exec_class@PLT @@ -166,11 +166,11 @@ addl $4, %esp popl %ebx popl %ebp ret -get_eip: +getEIP: movl (%esp), %ebx ret #ifdef OF_SOLARIS .section .init_array, "aw" @@ -193,8 +193,8 @@ .long 0 .long 0 module: .long 8, 16, 0, symtab -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/forwarding/forwarding-x86-win32.S ================================================================== --- src/forwarding/forwarding-x86-win32.S +++ src/forwarding/forwarding-x86-win32.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/forwarding/forwarding-x86_64-elf.S Index: src/forwarding/forwarding-x86_64-elf.S ================================================================== --- src/forwarding/forwarding-x86_64-elf.S +++ src/forwarding/forwarding-x86_64-elf.S @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include "platform.h" - -.globl OFForward -.globl OFForward_stret - -.section .text -OFForward: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - call object_getClass@PLT - - movq %rax, %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call class_respondsToSelector@PLT - - testq %rax, %rax - jz 0f - - movq -0x10(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call objc_msg_lookup@PLT - - movq -0x10(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x18(%rbp), %rdx - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x10(%rbp), %rax - je 0f - - movq %rax, -0x10(%rbp) - - movq %rax, %rdi - movq -0x18(%rbp), %rsi - call objc_msg_lookup@PLT - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x18(%rbp), %rsi - movq -0x10(%rbp), %rdi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - - movq %rbp, %rsp - popq %rbp - - jmp OFMethodNotFound@PLT -.type OFForward, %function -.size OFForward, .-OFForward - -OFForward_stret: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - movq %rsi, %rdi - call object_getClass@PLT - - movq %rax, %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call class_respondsToSelector@PLT - - testq %rax, %rax - jz 0f - - movq -0x18(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call objc_msg_lookup@PLT - - movq -0x18(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x20(%rbp), %rdx - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x18(%rbp), %rax - je 0f - - movq %rax, -0x18(%rbp) - - movq %rax, %rdi - movq -0x20(%rbp), %rsi - call objc_msg_lookup_stret@PLT - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x18(%rbp), %rsi - movq -0x10(%rbp), %rdi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - movq -0x20(%rbp), %rdx - - movq %rbp, %rsp - popq %rbp - - jmp OFMethodNotFound_stret@PLT -.type OFForward_stret, %function -.size OFForward_stret, .-OFForward_stret - -init: - leaq module(%rip), %rdi - jmp __objc_exec_class@PLT - -#ifdef OF_SOLARIS -.section .init_array, "aw" -#else -.section .ctors, "aw", %progbits -#endif - .quad init - -.section .rodata -str_forwardingTargetForSelector_: - .asciz "forwardingTargetForSelector:" - -.section .data -sel_forwardingTargetForSelector_: - .quad str_forwardingTargetForSelector_, 0 - .quad 0, 0 -symtab: - .quad 0, sel_forwardingTargetForSelector_ - .short 0, 0 - .long 0 - .quad 0 -module: - .quad 8, 32, 0, symtab - -#ifdef OF_LINUX -.section .note.GNU-stack, "", %progbits -#endif DELETED src/forwarding/forwarding-x86_64-macho.S Index: src/forwarding/forwarding-x86_64-macho.S ================================================================== --- src/forwarding/forwarding-x86_64-macho.S +++ src/forwarding/forwarding-x86_64-macho.S @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include "platform.h" - -.globl _OFForward -.globl _OFForward_stret - -.section __TEXT, __text, regular, pure_instructions -_OFForward: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - call _object_getClass - - movq %rax, %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call _class_respondsToSelector - - testq %rax, %rax - jz 0f - - movq -0x10(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call _objc_msg_lookup - - movq -0x10(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x18(%rbp), %rdx - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x10(%rbp), %rax - je 0f - - movq %rax, -0x10(%rbp) - - movq %rax, %rdi - movq -0x18(%rbp), %rsi - call _objc_msg_lookup - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x18(%rbp), %rsi - movq -0x10(%rbp), %rdi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - - movq %rbp, %rsp - popq %rbp - - jmp _OFMethodNotFound - -_OFForward_stret: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0xC0, %rsp /* 16-byte alignment */ - movq %rax, -0x8(%rbp) - movq %rdi, -0x10(%rbp) - movq %rsi, -0x18(%rbp) - movq %rdx, -0x20(%rbp) - movq %rcx, -0x28(%rbp) - movq %r8, -0x30(%rbp) - movq %r9, -0x38(%rbp) - movaps %xmm0, -0x50(%rbp) - movaps %xmm1, -0x60(%rbp) - movaps %xmm2, -0x70(%rbp) - movaps %xmm3, -0x80(%rbp) - movaps %xmm4, -0x90(%rbp) - movaps %xmm5, -0xA0(%rbp) - movaps %xmm6, -0xB0(%rbp) - movaps %xmm7, -0xC0(%rbp) - - movq %rsi, %rdi - call _object_getClass - - movq %rax, %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call _class_respondsToSelector - - testq %rax, %rax - jz 0f - - movq -0x18(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - call _objc_msg_lookup - - movq -0x18(%rbp), %rdi - leaq sel_forwardingTargetForSelector_(%rip), %rsi - movq -0x20(%rbp), %rdx - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x18(%rbp), %rax - je 0f - - movq %rax, -0x18(%rbp) - - movq %rax, %rdi - movq -0x20(%rbp), %rsi - call _objc_msg_lookup_stret - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0xC0(%rbp), %xmm7 - movaps -0xB0(%rbp), %xmm6 - movaps -0xA0(%rbp), %xmm5 - movaps -0x90(%rbp), %xmm4 - movaps -0x80(%rbp), %xmm3 - movaps -0x70(%rbp), %xmm2 - movaps -0x60(%rbp), %xmm1 - movaps -0x50(%rbp), %xmm0 - movq -0x38(%rbp), %r9 - movq -0x30(%rbp), %r8 - movq -0x28(%rbp), %rcx - movq -0x20(%rbp), %rdx - movq -0x18(%rbp), %rsi - movq -0x10(%rbp), %rdi - movq -0x8(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x10(%rbp), %rdi - movq -0x18(%rbp), %rsi - movq -0x20(%rbp), %rdx - - movq %rbp, %rsp - popq %rbp - - jmp _OFMethodNotFound_stret - -init: - leaq module(%rip), %rdi - jmp ___objc_exec_class - -.section __DATA, __mod_init_func, mod_init_funcs - .quad init - -.section __TEXT, __cstring, cstring_literals -str_forwardingTargetForSelector_: - .asciz "forwardingTargetForSelector:" - -.section __DATA, __data -sel_forwardingTargetForSelector_: - .quad str_forwardingTargetForSelector_, 0 - .quad 0, 0 -symtab: - .quad 0, sel_forwardingTargetForSelector_ - .short 0, 0 - .long 0 - .quad 0 -module: - .quad 8, 32, 0, symtab DELETED src/forwarding/forwarding-x86_64-win64.S Index: src/forwarding/forwarding-x86_64-win64.S ================================================================== --- src/forwarding/forwarding-x86_64-win64.S +++ src/forwarding/forwarding-x86_64-win64.S @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -.globl OFForward -.globl OFForward_stret - -.section .text -OFForward: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0x90, %rsp /* 16-byte alignment */ - movq %rax, -0x28(%rbp) - movq %rcx, -0x30(%rbp) - movq %rdx, -0x38(%rbp) - movq %r8, -0x40(%rbp) - movq %r9, -0x48(%rbp) - movaps %xmm0, -0x60(%rbp) - movaps %xmm1, -0x70(%rbp) - movaps %xmm2, -0x80(%rbp) - movaps %xmm3, -0x90(%rbp) - - call object_getClass - - movq %rax, %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - call class_respondsToSelector - - testq %rax, %rax - jz 0f - - movq -0x30(%rbp), %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - call objc_msg_lookup - - movq -0x30(%rbp), %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - movq -0x38(%rbp), %r8 - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x30(%rbp), %rax - je 0f - - movq %rax, -0x30(%rbp) - - movq %rax, %rcx - movq -0x38(%rbp), %rdx - call objc_msg_lookup - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0x90(%rbp), %xmm3 - movaps -0x80(%rbp), %xmm2 - movaps -0x70(%rbp), %xmm1 - movaps -0x60(%rbp), %xmm0 - movq -0x48(%rbp), %r9 - movq -0x40(%rbp), %r8 - movq -0x38(%rbp), %rdx - movq -0x30(%rbp), %rcx - movq -0x28(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x30(%rbp), %rcx - movq -0x38(%rbp), %rdx - - movq %rbp, %rsp - popq %rbp - - jmp OFMethodNotFound -.def OFForward -.scl 2 -.type 32 -.endef - -OFForward_stret: - pushq %rbp - movq %rsp, %rbp - - /* Save all arguments */ - subq $0x90, %rsp /* 16-byte alignment */ - movq %rax, -0x28(%rbp) - movq %rcx, -0x30(%rbp) - movq %rdx, -0x38(%rbp) - movq %r8, -0x40(%rbp) - movq %r9, -0x48(%rbp) - movaps %xmm0, -0x60(%rbp) - movaps %xmm1, -0x70(%rbp) - movaps %xmm2, -0x80(%rbp) - movaps %xmm3, -0x90(%rbp) - - movq %rdx, %rcx - call object_getClass - - movq %rax, %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - call class_respondsToSelector - - testq %rax, %rax - jz 0f - - movq -0x38(%rbp), %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - call objc_msg_lookup - - movq -0x38(%rbp), %rcx - leaq sel_forwardingTargetForSelector_(%rip), %rdx - movq -0x40(%rbp), %r8 - call *%rax - - testq %rax, %rax - jz 0f - cmpq -0x38(%rbp), %rax - je 0f - - movq %rax, -0x38(%rbp) - - movq %rax, %rcx - movq -0x40(%rbp), %rdx - call objc_msg_lookup_stret - movq %rax, %r11 - - /* Restore all arguments */ - movaps -0x90(%rbp), %xmm3 - movaps -0x80(%rbp), %xmm2 - movaps -0x70(%rbp), %xmm1 - movaps -0x60(%rbp), %xmm0 - movq -0x48(%rbp), %r9 - movq -0x40(%rbp), %r8 - movq -0x38(%rbp), %rdx - movq -0x30(%rbp), %rcx - movq -0x28(%rbp), %rax - - movq %rbp, %rsp - popq %rbp - - jmpq *%r11 - -0: - movq -0x30(%rbp), %rcx - movq -0x38(%rbp), %rdx - movq -0x40(%rbp), %r8 - - movq %rbp, %rsp - popq %rbp - - jmp OFMethodNotFound_stret -.def OFForward_stret -.scl 2 -.type 32 -.endef - -init: - leaq module(%rip), %rcx - jmp __objc_exec_class - -.section .ctors, "aw" - .quad init - -.section .rodata -str_forwardingTargetForSelector_: - .asciz "forwardingTargetForSelector:" - -.section .data -sel_forwardingTargetForSelector_: - .quad str_forwardingTargetForSelector_, 0 - .quad 0, 0 -symtab: - .long 0, 0 - .quad sel_forwardingTargetForSelector_ - .short 0, 0 - .long 0 - .quad 0 -module: - .long 8, 32 - .quad 0, symtab Index: src/forwarding/forwarding.S ================================================================== --- src/forwarding/forwarding.S +++ src/forwarding/forwarding.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,25 +16,25 @@ #include "config.h" #include "platform.h" #ifdef OF_APPLE_RUNTIME -# if defined(OF_X86_64) -# include "apple-forwarding-x86_64.S" +# if defined(OF_AMD64) +# include "apple-forwarding-amd64.S" # elif defined(OF_X86) -# include "apple-forwarding-i386.S" +# include "apple-forwarding-x86.S" # elif defined(OF_ARM64) # include "apple-forwarding-arm64.S" # elif defined(OF_ARM) # include "apple-forwarding-arm.S" # elif defined(OF_POWERPC) # include "apple-forwarding-powerpc.S" # endif #else # if defined(OF_ELF) -# if defined(OF_X86_64) -# include "forwarding-x86_64-elf.S" +# if defined(OF_AMD64) +# include "forwarding-amd64-elf.S" # elif defined(OF_X86) # include "forwarding-x86-elf.S" # elif defined(OF_ARM64) # include "forwarding-arm64-elf.S" # elif defined(OF_ARM) @@ -47,16 +47,16 @@ # include "forwarding-sparc64-elf.S" # elif defined(OF_SPARC) # include "forwarding-sparc-elf.S" # endif # elif defined(OF_MACH_O) -# if defined(OF_X86_64) -# include "forwarding-x86_64-macho.S" +# if defined(OF_AMD64) +# include "forwarding-amd64-macho.S" # endif # elif defined(OF_WINDOWS) -# if defined(OF_X86_64) -# include "forwarding-x86_64-win64.S" +# if defined(OF_AMD64) +# include "forwarding-amd64-win64.S" # elif defined(OF_X86) # include "forwarding-x86-win32.S" # endif # endif #endif Index: src/libbases.m ================================================================== --- src/libbases.m +++ src/libbases.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -13,11 +13,13 @@ * file. */ #include "config.h" +#define Class IntuitionClass #include +#undef Class #import "OFInitializationFailedException.h" #import "macros.h" Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -320,34 +320,34 @@ extern int *_Nonnull OFErrNo(void); # define errno (*OFErrNo()) #endif #ifdef OF_APPLE_RUNTIME -# if defined(OF_X86_64) || defined(OF_X86) || defined(OF_ARM64) || \ +# if defined(OF_AMD64) || defined(OF_X86) || defined(OF_ARM64) || \ defined(OF_ARM) || defined(OF_POWERPC) # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET # endif #else # if defined(OF_ELF) -# if defined(OF_X86_64) || defined(OF_X86) || \ +# if defined(OF_AMD64) || defined(OF_X86) || \ defined(OF_ARM64) || defined(OF_ARM) || defined(OF_POWERPC) || \ defined(OF_MIPS) || defined(OF_SPARC64) || defined(OF_SPARC) # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR # if __OBJFW_RUNTIME_ABI__ >= 800 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET # endif # endif # elif defined(OF_MACH_O) -# if defined(OF_X86_64) +# if defined(OF_AMD64) # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR # if __OBJFW_RUNTIME_ABI__ >= 800 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET # endif # endif # elif defined(OF_WINDOWS) -# if defined(OF_X86_64) || defined(OF_X86) +# if defined(OF_AMD64) || defined(OF_X86) # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR # if __OBJFW_RUNTIME_ABI__ >= 800 # define OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET # endif # endif @@ -454,11 +454,11 @@ static OF_INLINE uint16_t OF_CONST_FUNC OFByteSwap16NonConst(uint16_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP16) return __builtin_bswap16(i); -#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +#elif (defined(OF_AMD64) || defined(OF_X86)) && defined(__GNUC__) __asm__ ( "xchgb %h0, %b0" : "=Q"(i) : "0"(i) ); @@ -484,11 +484,11 @@ static OF_INLINE uint32_t OF_CONST_FUNC OFByteSwap32NonConst(uint32_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP32) return __builtin_bswap32(i); -#elif (defined(OF_X86_64) || defined(OF_X86)) && defined(__GNUC__) +#elif (defined(OF_AMD64) || defined(OF_X86)) && defined(__GNUC__) __asm__ ( "bswap %0" : "=q"(i) : "0"(i) ); @@ -516,11 +516,11 @@ static OF_INLINE uint64_t OF_CONST_FUNC OFByteSwap64NonConst(uint64_t i) { #if defined(OF_HAVE_BUILTIN_BSWAP64) return __builtin_bswap64(i); -#elif defined(OF_X86_64) && defined(__GNUC__) +#elif defined(OF_AMD64) && defined(__GNUC__) __asm__ ( "bswap %0" : "=r"(i) : "0"(i) ); Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,7 +1,8 @@ #undef OF_APPLE_RUNTIME #undef OF_BIG_ENDIAN +#undef OF_CLASSIC_MACOS #undef OF_FLOAT_BIG_ENDIAN #undef OF_HAVE_AFUNIX_H #undef OF_HAVE_APPLETALK #undef OF_HAVE_ATOMIC_BUILTINS #undef OF_HAVE_ATOMIC_OPS @@ -29,10 +30,11 @@ #undef OF_HAVE_PLUGINS #undef OF_HAVE_PTHREADS #undef OF_HAVE_PTHREAD_SPINLOCKS #undef OF_HAVE_RECURSIVE_PTHREAD_MUTEXES #undef OF_HAVE_SCHED_YIELD +#undef OF_HAVE_SOCKADDR_STORAGE #undef OF_HAVE_SOCKETS #undef OF_HAVE_STDNORETURN #undef OF_HAVE_SUBPROCESSES #undef OF_HAVE_SYMLINK #undef OF_HAVE_SYNC_BUILTINS Index: src/platform.h ================================================================== --- src/platform.h +++ src/platform.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,11 +24,11 @@ # error OF_UNIVERSAL defined, but neither __BIG_ENDIAN__ nor __LITTLE_ENDIAN__! # endif #endif #if defined(__x86_64__) || defined(__amd64__) -# define OF_X86_64 +# define OF_AMD64 #elif defined(__i386__) # define OF_X86 #elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) # define OF_POWERPC64 #elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) @@ -149,10 +149,16 @@ # define OF_MSDOS #elif defined(__riscos__) # define OF_ACORN_RISC_OS #elif defined(__MINT__) # define OF_MINT +#elif defined(__gnu_hurd__) +# define OF_HURD +#endif + +#ifdef __GLIBC__ +# define OF_GLIBC #endif #if defined(__ELF__) # define OF_ELF #elif defined(__MACH__) Index: src/platform/AmigaOS/OFPlainCondition.m ================================================================== --- src/platform/AmigaOS/OFPlainCondition.m +++ src/platform/AmigaOS/OFPlainCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,15 +17,17 @@ #include #import "OFPlainCondition.h" +#define Class IntuitionClass #include #include #ifndef OF_AMIGAOS4 # include #endif +#undef Class int OFPlainConditionNew(OFPlainCondition *condition) { condition->waitingTasks = NULL; Index: src/platform/AmigaOS/OFPlainMutex.m ================================================================== --- src/platform/AmigaOS/OFPlainMutex.m +++ src/platform/AmigaOS/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,13 @@ #include #import "OFPlainMutex.h" +#define Class IntuitionClass #include +#undef Class int OFPlainMutexNew(OFPlainMutex *mutex) { InitSemaphore(mutex); Index: src/platform/AmigaOS/OFPlainThread.m ================================================================== --- src/platform/AmigaOS/OFPlainThread.m +++ src/platform/AmigaOS/OFPlainThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,13 +20,15 @@ #import "OFPlainThread.h" #import "OFData.h" #import "OFString.h" #import "OFTLSKey.h" +#define Class IntuitionClass #include #include #include +#undef Class #ifndef OF_MORPHOS extern void OFTLSKeyThreadExited(void); #endif static OFTLSKey threadKey; Index: src/platform/AmigaOS/OFString+PathAdditions.m ================================================================== --- src/platform/AmigaOS/OFString+PathAdditions.m +++ src/platform/AmigaOS/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" -#import "OFFileURIHandler.h" +#import "OFFileIRIHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -291,14 +291,14 @@ } - (bool)of_isDirectoryPath { return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || - [OFFileURIHandler of_directoryExistsAtPath: self]); + [OFFileIRIHandler of_directoryExistsAtPath: self]); } -- (OFString *)of_pathToURIPathWithPercentEncodedHost: +- (OFString *)of_pathToIRIPathWithPercentEncodedHost: (OFString **)percentEncodedHost { OFArray OF_GENERIC(OFString *) *components = self.pathComponents; OFMutableString *ret = [OFMutableString string]; @@ -317,11 +317,11 @@ [ret makeImmutable]; return ret; } -- (OFString *)of_URIPathToPathWithPercentEncodedHost: +- (OFString *)of_IRIPathToPathWithPercentEncodedHost: (OFString *)percentEncodedHost { OFString *path = self; if (path.length > 1 && [path hasSuffix: @"/"]) @@ -351,10 +351,10 @@ } return [OFString pathWithComponents: components]; } -- (OFString *)of_pathComponentToURIPathComponent +- (OFString *)of_pathComponentToIRIPathComponent { return self; } @end Index: src/platform/AmigaOS/OFTLSKey.m ================================================================== --- src/platform/AmigaOS/OFTLSKey.m +++ src/platform/AmigaOS/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,12 +15,14 @@ #include "config.h" #import "OFTLSKey.h" +#define Class IntuitionClass #include #include +#undef Class /* * As we use this file in both the runtime and ObjFW, and since AmigaOS always * has the runtime, use the hashtable from the runtime. */ Index: src/platform/GCC4.7/OFAtomic.h ================================================================== --- src/platform/GCC4.7/OFAtomic.h +++ src/platform/GCC4.7/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/GCC4/OFAtomic.h ================================================================== --- src/platform/GCC4/OFAtomic.h +++ src/platform/GCC4/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/MorphOS/OFTLSKey.m ================================================================== --- src/platform/MorphOS/OFTLSKey.m +++ src/platform/MorphOS/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/POSIX/OFPlainCondition.m ================================================================== --- src/platform/POSIX/OFPlainCondition.m +++ src/platform/POSIX/OFPlainCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/POSIX/OFPlainMutex.m ================================================================== --- src/platform/POSIX/OFPlainMutex.m +++ src/platform/POSIX/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/POSIX/OFPlainThread.m ================================================================== --- src/platform/POSIX/OFPlainThread.m +++ src/platform/POSIX/OFPlainThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/POSIX/OFString+PathAdditions.m ================================================================== --- src/platform/POSIX/OFString+PathAdditions.m +++ src/platform/POSIX/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" -#import "OFFileURIHandler.h" +#import "OFFileIRIHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -336,20 +336,20 @@ } - (bool)of_isDirectoryPath { return ([self hasSuffix: @"/"] || - [OFFileURIHandler of_directoryExistsAtPath: self]); + [OFFileIRIHandler of_directoryExistsAtPath: self]); } -- (OFString *)of_pathToURIPathWithPercentEncodedHost: +- (OFString *)of_pathToIRIPathWithPercentEncodedHost: (OFString **)percentEncodedHost { return self; } -- (OFString *)of_URIPathToPathWithPercentEncodedHost: +- (OFString *)of_IRIPathToPathWithPercentEncodedHost: (OFString *)percentEncodedHost { OFString *path = self; if (path.length > 1 && [path hasSuffix: @"/"]) @@ -356,10 +356,10 @@ path = [path substringToIndex: path.length - 1]; return path; } -- (OFString *)of_pathComponentToURIPathComponent +- (OFString *)of_pathComponentToIRIPathComponent { return self; } @end Index: src/platform/POSIX/OFSubprocess.m ================================================================== --- src/platform/POSIX/OFSubprocess.m +++ src/platform/POSIX/OFSubprocess.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -39,11 +39,11 @@ #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" -#ifndef HAVE_POSIX_SPAWNP +#if !defined(HAVE_POSIX_SPAWNP) || !defined(HAVE_SPAWN_H) extern char **environ; #endif @interface OFSubprocess () - (void)of_getArgv: (char ***)argv @@ -141,11 +141,11 @@ forProgramName: programName andArguments: arguments]; @try { env = [self of_environmentForDictionary: environment]; -#ifdef HAVE_POSIX_SPAWNP +#if defined(HAVE_POSIX_SPAWNP) && defined(HAVE_SPAWN_H) posix_spawn_file_actions_t actions; posix_spawnattr_t attr; if (posix_spawn_file_actions_init(&actions) != 0) @throw [OFInitializationFailedException ADDED src/platform/POSIX/OFSystemInfo+NetworkInterfaces.m Index: src/platform/POSIX/OFSystemInfo+NetworkInterfaces.m ================================================================== --- src/platform/POSIX/OFSystemInfo+NetworkInterfaces.m +++ src/platform/POSIX/OFSystemInfo+NetworkInterfaces.m @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef OF_HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NET_IF_H +# include +#endif +#ifdef HAVE_NET_IF_ARP_H +# include +#endif +#ifdef HAVE_NET_IF_DL_H +# include +#endif +#ifdef HAVE_NET_IF_TYPES_H +# include +#endif + +#import "OFSystemInfo.h" +#import "OFSystemInfo+NetworkInterfaces.h" +#import "OFArray.h" +#import "OFData.h" +#import "OFDictionary.h" +#ifdef OF_HAVE_FILES + #import "OFFile.h" +#endif +#import "OFLocale.h" +#import "OFNumber.h" +#import "OFSocket.h" +#import "OFSocket+Private.h" +#import "OFString.h" + +#import "OFInvalidFormatException.h" +#import "OFOpenItemFailedException.h" + +@implementation OFSystemInfo (NetworkInterfaces) +static bool +queryNetworkInterfaceIndices(OFMutableDictionary *ret) +{ +#ifdef HAVE_IF_NAMEINDEX + OFStringEncoding encoding = [OFLocale encoding]; + struct if_nameindex *nameindex = if_nameindex(); + + if (nameindex == NULL) + return false; + + @try { + for (size_t i = 0; nameindex[i].if_index != 0; i++) { + OFString *name = [OFString + stringWithCString: nameindex[i].if_name + encoding: encoding]; + OFNumber *index = [OFNumber + numberWithUnsignedInt: nameindex[i].if_index]; + OFMutableDictionary *interface = + [ret objectForKey: name]; + + if (interface == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + [interface setObject: index + forKey: OFNetworkInterfaceIndex]; + } + } @finally { + if_freenameindex(nameindex); + } + + return true; +#else + return false; +#endif +} + +#if defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) +static bool +queryNetworkInterfaceAddresses(OFMutableDictionary *ret, + OFNetworkInterfaceKey key, OFSocketAddressFamily addressFamily, int family, + size_t sockaddrSize) +{ + OFStringEncoding encoding = [OFLocale encoding]; + int sock = socket(family, SOCK_DGRAM, 0); + struct ifconf ifc; + struct ifreq *ifrs; + OFMutableDictionary *interface; + OFEnumerator *enumerator; + + if (sock < 0) + return false; + + ifrs = malloc(128 * sizeof(struct ifreq)); + if (ifrs == NULL) { + closesocket(sock); + return false; + } + + @try { + char *buffer; + + memset(&ifc, 0, sizeof(ifc)); + ifc.ifc_buf = (void *)ifrs; + ifc.ifc_len = 128 * sizeof(struct ifreq); + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + return false; + + buffer = ifc.ifc_buf; + while (buffer < (char *)ifc.ifc_buf + ifc.ifc_len) { + struct ifreq *current = (struct ifreq *)(void *)buffer; + OFString *name; + OFMutableData *addresses; + OFSocketAddress address; + + if (current->ifr_addr.sa_family != family) + goto next; + + name = [OFString stringWithCString: current->ifr_name + encoding: encoding]; + if ((interface = [ret objectForKey: name]) == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + addresses = [interface objectForKey: key]; + if (addresses == nil) { + addresses = [OFMutableData + dataWithItemSize: sizeof(OFSocketAddress)]; + [interface setObject: addresses forKey: key]; + } + + memset(&address, 0, sizeof(address)); + address.family = addressFamily; + memcpy(&address.sockaddr.in, ¤t->ifr_addr, + sockaddrSize); + + [addresses addItem: &address]; + +next: +# ifdef _SIZEOF_ADDR_IFREQ + buffer += _SIZEOF_ADDR_IFREQ(*current); +# else + buffer += sizeof(struct ifreq); +# endif + } + } @finally { + free(ifrs); + closesocket(sock); + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [[interface objectForKey: key] makeImmutable]; + + return true; +} +#endif + +static bool +queryNetworkInterfaceIPv4Addresses(OFMutableDictionary *ret) +{ +#if defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) + return queryNetworkInterfaceAddresses(ret, + OFNetworkInterfaceIPv4Addresses, OFSocketAddressFamilyIPv4, + AF_INET, sizeof(struct sockaddr_in)); +#else + return false; +#endif +} + +#ifdef OF_HAVE_IPV6 +static bool +queryNetworkInterfaceIPv6Addresses(OFMutableDictionary *ret) +{ +# if defined(OF_LINUX) && defined(OF_HAVE_FILES) + OFFile *file; + OFString *line; + OFMutableDictionary *interface; + OFEnumerator *enumerator; + + @try { + file = [OFFile fileWithPath: @"/proc/net/if_inet6" mode: @"r"]; + } @catch (OFOpenItemFailedException *e) { + return false; + } + + while ((line = [file readLine]) != nil) { + OFArray *components = [line + componentsSeparatedByString: @" " + options: OFStringSkipEmptyComponents]; + OFString *addressString, *name; + OFSocketAddress address; + OFMutableData *addresses; + + if (components.count < 6) + continue; + + addressString = [components objectAtIndex: 0]; + name = [components objectAtIndex: 5]; + + if (addressString.length != 32) + continue; + + if ((interface = [ret objectForKey: name]) == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + memset(&address, 0, sizeof(address)); + address.family = OFSocketAddressFamilyIPv6; + + for (size_t i = 0; i < 32; i += 2) { + unsigned long long byte; + + @try { + byte = [[addressString + substringWithRange: OFMakeRange(i, 2)] + unsignedLongLongValueWithBase: 16]; + } @catch (OFInvalidFormatException *e) { + goto next_line; + } + + if (byte > 0xFF) + goto next_line; + + address.sockaddr.in6.sin6_addr.s6_addr[i / 2] = + (unsigned char)byte; + } + + if ((addresses = [interface + objectForKey: OFNetworkInterfaceIPv6Addresses]) == nil) { + addresses = [OFMutableData + dataWithItemSize: sizeof(OFSocketAddress)]; + [interface setObject: addresses + forKey: OFNetworkInterfaceIPv6Addresses]; + } + + [addresses addItem: &address]; + +next_line: + continue; + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [[interface objectForKey: OFNetworkInterfaceIPv6Addresses] + makeImmutable]; + + return false; +# elif defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) + return queryNetworkInterfaceAddresses(ret, + OFNetworkInterfaceIPv6Addresses, OFSocketAddressFamilyIPv6, + AF_INET6, sizeof(struct sockaddr_in6)); +# else + return false; +# endif +} +#endif + +#ifdef OF_HAVE_IPX +static bool +queryNetworkInterfaceIPXAddresses(OFMutableDictionary *ret) +{ +# if defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) + return queryNetworkInterfaceAddresses(ret, + OFNetworkInterfaceIPXAddresses, OFSocketAddressFamilyIPX, + AF_IPX, sizeof(struct sockaddr_ipx)); +# else + return false; +# endif +} +#endif + +#ifdef OF_HAVE_APPLETALK +static bool +queryNetworkInterfaceAppleTalkAddresses(OFMutableDictionary *ret) +{ +# if defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) + return queryNetworkInterfaceAddresses(ret, + OFNetworkInterfaceAppleTalkAddresses, + OFSocketAddressFamilyAppleTalk, AF_APPLETALK, + sizeof(struct sockaddr_at)); +# else + return false; +# endif +} +#endif + +static bool +queryNetworkInterfaceHardwareAddress(OFMutableDictionary *ret) +{ +#if defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) && defined(SIOCGIFHWADDR) + OFStringEncoding encoding = [OFLocale encoding]; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) + return false; + + for (OFString *name in ret) { + size_t nameLength = [name cStringLengthWithEncoding: encoding]; + struct ifreq ifr; + OFData *hardwareAddress; + + if (nameLength > IFNAMSIZ) + continue; + + memset(&ifr, 0, sizeof(ifr)); + memcpy(&ifr.ifr_name, [name cStringWithEncoding: encoding], + nameLength); + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + continue; + + if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) + continue; + + hardwareAddress = [OFData dataWithItems: ifr.ifr_hwaddr.sa_data + count: 6]; + [[ret objectForKey: name] + setObject: hardwareAddress + forKey: OFNetworkInterfaceHardwareAddress]; + } + + return true; +#elif defined(HAVE_IOCTL) && defined(HAVE_NET_IF_H) && \ + defined(HAVE_STRUCT_SOCKADDR_DL) + OFStringEncoding encoding = [OFLocale encoding]; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + struct ifconf ifc; + struct ifreq *ifrs; + + if (sock < 0) + return false; + + ifrs = malloc(128 * sizeof(struct ifreq)); + if (ifrs == NULL) { + closesocket(sock); + return false; + } + + @try { + char *buffer; + + memset(&ifc, 0, sizeof(ifc)); + ifc.ifc_buf = (void *)ifrs; + ifc.ifc_len = 128 * sizeof(struct ifreq); + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + return false; + + buffer = ifc.ifc_buf; + while (buffer < (char *)ifc.ifc_buf + ifc.ifc_len) { + struct ifreq *current = (struct ifreq *)(void *)buffer; + struct sockaddr_dl *sdl; + OFString *name; + OFMutableDictionary *interface; + OFData *hardwareAddress; + + if (current->ifr_addr.sa_family != AF_LINK) + goto next; + + sdl = (struct sockaddr_dl *)(void *)¤t->ifr_addr; + if (sdl->sdl_type != IFT_ETHER) + goto next; + + name = [OFString stringWithCString: current->ifr_name + encoding: encoding]; + if ((interface = [ret objectForKey: name]) == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + hardwareAddress = [OFData dataWithItems: LLADDR(sdl) + count: sdl->sdl_alen]; + [interface + setObject: hardwareAddress + forKey: OFNetworkInterfaceHardwareAddress]; + +next: +# ifdef _SIZEOF_ADDR_IFREQ + buffer += _SIZEOF_ADDR_IFREQ(*current); +# else + buffer += sizeof(struct ifreq); +# endif + } + } @finally { + free(ifrs); + closesocket(sock); + } + + return true; +#else + return false; +#endif +} + ++ (OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *)networkInterfaces +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + bool success = false; + OFEnumerator *enumerator; + OFMutableDictionary *interface; + + success |= queryNetworkInterfaceIndices(ret); + success |= queryNetworkInterfaceIPv4Addresses(ret); +#ifdef OF_HAVE_IPV6 + success |= queryNetworkInterfaceIPv6Addresses(ret); +#endif +#ifdef OF_HAVE_IPX + success |= queryNetworkInterfaceIPXAddresses(ret); +#endif +#ifdef OF_HAVE_APPLETALK + success |= queryNetworkInterfaceAppleTalkAddresses(ret); +#endif + success |= queryNetworkInterfaceHardwareAddress(ret); + + if (!success) { + objc_autoreleasePoolPop(pool); + return nil; + } + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [interface makeImmutable]; + + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} +@end Index: src/platform/POSIX/OFTLSKey.m ================================================================== --- src/platform/POSIX/OFTLSKey.m +++ src/platform/POSIX/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/PowerPC/OFAtomic.h ================================================================== --- src/platform/PowerPC/OFAtomic.h +++ src/platform/PowerPC/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/Windows/OFPlainCondition.m ================================================================== --- src/platform/Windows/OFPlainCondition.m +++ src/platform/Windows/OFPlainCondition.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,10 +16,11 @@ #include "config.h" #include #import "OFPlainCondition.h" +#import "OFConstantString.h" #include int OFPlainConditionNew(OFPlainCondition *condition) Index: src/platform/Windows/OFPlainMutex.m ================================================================== --- src/platform/Windows/OFPlainMutex.m +++ src/platform/Windows/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/Windows/OFPlainThread.m ================================================================== --- src/platform/Windows/OFPlainThread.m +++ src/platform/Windows/OFPlainThread.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,12 +16,11 @@ #include "config.h" #include #import "OFPlainThread.h" - -#import "macros.h" +#import "OFConstantString.h" #include struct ThreadContext { void (*function)(id); Index: src/platform/Windows/OFString+PathAdditions.m ================================================================== --- src/platform/Windows/OFString+PathAdditions.m +++ src/platform/Windows/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -20,12 +20,12 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" -#import "OFFileURIHandler.h" -#import "OFURI.h" +#import "OFFileIRIHandler.h" +#import "OFIRI.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -341,14 +341,14 @@ } - (bool)of_isDirectoryPath { return ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"] || - [OFFileURIHandler of_directoryExistsAtPath: self]); + [OFFileIRIHandler of_directoryExistsAtPath: self]); } -- (OFString *)of_pathToURIPathWithPercentEncodedHost: +- (OFString *)of_pathToIRIPathWithPercentEncodedHost: (OFString **)percentEncodedHost { OFString *path = self; if ([path hasPrefix: @"\\\\"]) { @@ -357,11 +357,11 @@ if (components.count < 2) @throw [OFInvalidFormatException exception]; *percentEncodedHost = [[components objectAtIndex: 1] stringByAddingPercentEncodingWithAllowedCharacters: - [OFCharacterSet URIHostAllowedCharacterSet]]; + [OFCharacterSet IRIHostAllowedCharacterSet]]; path = [OFString pathWithComponents: [components objectsInRange: OFMakeRange(2, components.count - 2)]]; } path = [path stringByReplacingOccurrencesOfString: @"\\" @@ -369,11 +369,11 @@ path = [@"/" stringByAppendingString: path]; return path; } -- (OFString *)of_URIPathToPathWithPercentEncodedHost: +- (OFString *)of_IRIPathToPathWithPercentEncodedHost: (OFString *)percentEncodedHost { OFString *path = self; if (path.length > 1 && [path hasSuffix: @"/"] && @@ -396,11 +396,11 @@ } return path; } -- (OFString *)of_pathComponentToURIPathComponent +- (OFString *)of_pathComponentToIRIPathComponent { return [self stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]; } @end Index: src/platform/Windows/OFSubprocess.m ================================================================== --- src/platform/Windows/OFSubprocess.m +++ src/platform/Windows/OFSubprocess.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/platform/Windows/OFSystemInfo+NetworkInterfaces.m Index: src/platform/Windows/OFSystemInfo+NetworkInterfaces.m ================================================================== --- src/platform/Windows/OFSystemInfo+NetworkInterfaces.m +++ src/platform/Windows/OFSystemInfo+NetworkInterfaces.m @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFSystemInfo.h" +#import "OFSystemInfo+NetworkInterfaces.h" +#import "OFData.h" +#import "OFDictionary.h" +#import "OFLocale.h" +#import "OFNumber.h" +#import "OFOnce.h" +#import "OFSocket.h" +#import "OFString.h" + +#include +#define interface struct +#include +#undef interface + +static WINAPI ULONG (*GetAdaptersAddressesFuncPtr)(ULONG, ULONG, PVOID, + PIP_ADAPTER_ADDRESSES, PULONG); + +static void +init(void) +{ + HMODULE module; + + if ((module = LoadLibrary("iphlpapi.dll")) != NULL) + GetAdaptersAddressesFuncPtr = (WINAPI ULONG (*)(ULONG, ULONG, + PVOID, PIP_ADAPTER_ADDRESSES, PULONG)) + GetProcAddress(module, "GetAdaptersAddresses"); + +} + +static OFMutableDictionary OF_GENERIC(OFString *, OFNetworkInterface) * +networkInterfacesFromGetAdaptersAddresses(void) +{ + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + OFStringEncoding encoding = [OFLocale encoding]; + ULONG adapterAddressesSize = sizeof(IP_ADAPTER_ADDRESSES); + PIP_ADAPTER_ADDRESSES adapterAddresses; + + if ((adapterAddresses = malloc(adapterAddressesSize)) == NULL) + return nil; + + @try { + ULONG error = GetAdaptersAddressesFuncPtr(AF_UNSPEC, 0, NULL, + adapterAddresses, &adapterAddressesSize); + + if (error == ERROR_BUFFER_OVERFLOW) { + PIP_ADAPTER_ADDRESSES newAdapterAddresses = + realloc(adapterAddresses, adapterAddressesSize); + + if (newAdapterAddresses == NULL) + return nil; + + adapterAddresses = newAdapterAddresses; + error = GetAdaptersAddressesFuncPtr(AF_UNSPEC, 0, NULL, + adapterAddresses, &adapterAddressesSize); + } + + if (error != ERROR_SUCCESS) + return nil; + + for (PIP_ADAPTER_ADDRESSES iter = adapterAddresses; + iter != NULL; iter = iter->Next) { + OFString *name; + OFMutableDictionary *interface; + OFNumber *index; + + name = [OFString stringWithCString: iter->AdapterName + encoding: encoding]; + + if ((interface = [ret objectForKey: name]) == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + index = [OFNumber numberWithUnsignedInt: iter->IfIndex]; + [interface setObject: index + forKey: OFNetworkInterfaceIndex]; + + if (iter->PhysicalAddressLength > 0) { + const OFNetworkInterfaceKey key = + OFNetworkInterfaceHardwareAddress; + OFData *address = [OFData + dataWithItems: iter->PhysicalAddress + count: iter->PhysicalAddressLength]; + [interface setObject: address forKey: key]; + } + + for (PIP_ADAPTER_UNICAST_ADDRESS_LH addrIter = + iter->FirstUnicastAddress; addrIter != NULL; + addrIter = addrIter->Next) { + OFSocketAddress address; + int length; + OFNetworkInterfaceKey key; + OFMutableData *addresses; + + length = (int)sizeof(address.sockaddr); + if (length > addrIter->Address.iSockaddrLength) + length = + addrIter->Address.iSockaddrLength; + + memset(&address, 0, sizeof(OFSocketAddress)); + memcpy(&address.sockaddr, + addrIter->Address.lpSockaddr, + (size_t)length); + + switch (address.sockaddr.in.sin_family) { + case AF_INET: + address.family = + OFSocketAddressFamilyIPv4; + key = OFNetworkInterfaceIPv4Addresses; + break; + case AF_INET6: + address.family = + OFSocketAddressFamilyIPv6; + key = OFNetworkInterfaceIPv6Addresses; + break; + default: + continue; + } + + addresses = [interface objectForKey: key]; + if (addresses == nil) { + addresses = [OFMutableData + dataWithItemSize: + sizeof(OFSocketAddress)]; + [interface setObject: addresses + forKey: key]; + } + + [addresses addItem: &address]; + } + + [[interface objectForKey: + OFNetworkInterfaceIPv4Addresses] makeImmutable]; + [[interface objectForKey: + OFNetworkInterfaceIPv6Addresses] makeImmutable]; + } + } @finally { + free(adapterAddresses); + } + + return ret; +} + +static OFMutableDictionary OF_GENERIC(OFString *, OFNetworkInterface) * +networkInterfacesFromGetAdaptersInfo(void) +{ + OFMutableDictionary *ret = [OFMutableDictionary dictionary]; + OFStringEncoding encoding = [OFLocale encoding]; + ULONG adapterInfoSize = sizeof(IP_ADAPTER_INFO); + PIP_ADAPTER_INFO adapterInfo; + + if ((adapterInfo = malloc(adapterInfoSize)) == NULL) + return nil; + + @try { + ULONG error = GetAdaptersInfo(adapterInfo, &adapterInfoSize); + + if (error == ERROR_BUFFER_OVERFLOW) { + PIP_ADAPTER_INFO newAdapterInfo = + realloc(adapterInfo, adapterInfoSize); + + if (newAdapterInfo == NULL) + return nil; + + adapterInfo = newAdapterInfo; + error = GetAdaptersInfo(adapterInfo, &adapterInfoSize); + } + + if (error != ERROR_SUCCESS) + return nil; + + for (PIP_ADAPTER_INFO iter = adapterInfo; iter != NULL; + iter = iter->Next) { + OFMutableDictionary *interface; + OFString *name, *IPString; + OFNumber *index; + OFSocketAddress IPv4Address; + OFData *addresses; + + name = [OFString stringWithCString: iter->AdapterName + encoding: encoding]; + + if ((interface = [ret objectForKey: name]) == nil) { + interface = [OFMutableDictionary dictionary]; + [ret setObject: interface forKey: name]; + } + + index = [OFNumber numberWithUnsignedInt: iter->Index]; + [interface setObject: index + forKey: OFNetworkInterfaceIndex]; + + if (iter->AddressLength > 0) { + const OFNetworkInterfaceKey key = + OFNetworkInterfaceHardwareAddress; + OFData *address = [OFData + dataWithItems: iter->Address + count: iter->AddressLength]; + [interface setObject: address forKey: key]; + } + + IPString = [OFString + stringWithCString: iter->IpAddressList.IpAddress + .String + encoding: encoding]; + + if ([IPString isEqual: @"0.0.0.0"]) + continue; + + IPv4Address = OFSocketAddressParseIPv4(IPString, 0); + addresses = [OFData dataWithItems: &IPv4Address + count: 1 + itemSize: sizeof(IPv4Address)]; + [interface setObject: addresses + forKey: OFNetworkInterfaceIPv4Addresses]; + } + } @finally { + free(adapterInfo); + } + + return ret; +} + +@implementation OFSystemInfo (NetworkInterfaces) ++ (OFDictionary OF_GENERIC(OFString *, OFNetworkInterface) *)networkInterfaces +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *ret; + OFEnumerator *enumerator; + OFMutableDictionary *interface; + + OFOnce(&onceControl, init); + + if (GetAdaptersAddressesFuncPtr != NULL) + ret = networkInterfacesFromGetAdaptersAddresses(); + else + ret = networkInterfacesFromGetAdaptersInfo(); + + enumerator = [ret objectEnumerator]; + while ((interface = [enumerator nextObject]) != nil) + [interface makeImmutable]; + + [ret makeImmutable]; + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} +@end Index: src/platform/Windows/OFTLSKey.m ================================================================== --- src/platform/Windows/OFTLSKey.m +++ src/platform/Windows/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/Windows/OFWin32ConsoleStdIOStream.m ================================================================== --- src/platform/Windows/OFWin32ConsoleStdIOStream.m +++ src/platform/Windows/OFWin32ConsoleStdIOStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/libfat/OFString+PathAdditions.m ================================================================== --- src/platform/libfat/OFString+PathAdditions.m +++ src/platform/libfat/OFString+PathAdditions.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -15,11 +15,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" -#import "OFFileURIHandler.h" +#import "OFFileIRIHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -337,20 +337,20 @@ } - (bool)of_isDirectoryPath { return ([self hasSuffix: @"/"] || - [OFFileURIHandler of_directoryExistsAtPath: self]); + [OFFileIRIHandler of_directoryExistsAtPath: self]); } -- (OFString *)of_pathToURIPathWithPercentEncodedHost: +- (OFString *)of_pathToIRIPathWithPercentEncodedHost: (OFString **)percentEncodedHost { return [@"/" stringByAppendingString: self]; } -- (OFString *)of_URIPathToPathWithPercentEncodedHost: +- (OFString *)of_IRIPathToPathWithPercentEncodedHost: (OFString *)percentEncodedHost { OFString *path = self; if (path.length > 1 && [path hasSuffix: @"/"]) @@ -357,10 +357,10 @@ path = [path substringToIndex: path.length - 1]; return [path substringFromIndex: 1]; } -- (OFString *)of_pathComponentToURIPathComponent +- (OFString *)of_pathComponentToIRIPathComponent { return self; } @end Index: src/platform/macOS/OFAtomic.h ================================================================== --- src/platform/macOS/OFAtomic.h +++ src/platform/macOS/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/platform/x86/OFAtomic.h ================================================================== --- src/platform/x86/OFAtomic.h +++ src/platform/x86/OFAtomic.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,11 +24,11 @@ "xaddl %0, %2\n\t" "addl %1, %0" : "+&r"(i) : "r"(i), "m"(*p) ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "lock\n\t" "xaddq %0, %2\n\t" "addq %1, %0" @@ -57,11 +57,11 @@ } static OF_INLINE void *_Nullable OFAtomicPointerAdd(void *volatile _Nullable *_Nonnull p, intptr_t i) { -#if defined(OF_X86_64) +#if defined(OF_AMD64) __asm__ __volatile__ ( "lock\n\t" "xaddq %0, %2\n\t" "addq %1, %0" : "+&r"(i) @@ -92,11 +92,11 @@ "xaddl %0, %2\n\t" "subl %1, %0" : "+&r"(i) : "r"(i), "m"(*p) ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "negq %0\n\t" "lock\n\t" "xaddq %0, %2\n\t" @@ -127,11 +127,11 @@ } static OF_INLINE void *_Nullable OFAtomicPointerSubtract(void *volatile _Nullable *_Nonnull p, intptr_t i) { -#if defined(OF_X86_64) +#if defined(OF_AMD64) __asm__ __volatile__ ( "negq %0\n\t" "lock\n\t" "xaddq %0, %2\n\t" "subq %1, %0" @@ -167,11 +167,11 @@ "xaddl %0, %1\n\t" "incl %0" : "=&r"(i) : "m"(*p) ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "xorq %0, %0\n\t" "incq %0\n\t" "lock\n\t" @@ -218,11 +218,11 @@ "xaddl %0, %1\n\t" "decl %0" : "=&r"(i) : "m"(*p) ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "xorq %0, %0\n\t" "decq %0\n\t" "lock\n\t" @@ -270,11 +270,11 @@ "jne 0b" : "=&r"(i) : "r"(i), "m"(*p) : "eax", "cc" ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "0:\n\t" "movq %2, %0\n\t" "movq %0, %%rax\n\t" @@ -326,11 +326,11 @@ "jne 0b" : "=&r"(i) : "r"(i), "m"(*p) : "eax", "cc" ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "0:\n\t" "movq %2, %0\n\t" "movq %0, %%rax\n\t" @@ -382,11 +382,11 @@ "jne 0b" : "=&r"(i) : "r"(i), "m"(*p) : "eax", "cc" ); -#ifdef OF_X86_64 +#ifdef OF_AMD64 else if (sizeof(int) == 8) __asm__ __volatile__ ( "0:\n\t" "movq %2, %0\n\t" "movq %0, %%rax\n\t" @@ -480,13 +480,19 @@ } static OF_INLINE void OFMemoryBarrier(void) { +#ifdef OF_AMD64 + __asm__ __volatile__ ( + "lock orq $0, (%%rsp)" ::: "memory", "cc" + ); +#else __asm__ __volatile__ ( - "mfence" ::: "memory" + "lock orl $0, (%%esp)" ::: "memory", "cc" ); +#endif } static OF_INLINE void OFAcquireMemoryBarrier(void) { Index: src/runtime/OFOnce.m ================================================================== --- src/runtime/OFOnce.m +++ src/runtime/OFOnce.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/OFPlainMutex.m ================================================================== --- src/runtime/OFPlainMutex.m +++ src/runtime/OFPlainMutex.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/OFTLSKey.m ================================================================== --- src/runtime/OFTLSKey.m +++ src/runtime/OFTLSKey.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/amiga-end.m ================================================================== --- src/runtime/amiga-end.m +++ src/runtime/amiga-end.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/amiga-funcarray.inc ================================================================== --- src/runtime/amiga-funcarray.inc +++ src/runtime/amiga-funcarray.inc @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/amiga-glue.h ================================================================== --- src/runtime/amiga-glue.h +++ src/runtime/amiga-glue.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,14 +18,16 @@ #import "ObjFWRT.h" #import "private.h" #import "amiga-glue.h" +#define Class IntuitionClass #include #include #include #include +#undef Class #define CONCAT_VERSION2(major, minor) #major "." #minor #define CONCAT_VERSION(major, minor) CONCAT_VERSION2(major, minor) #define VERSION_STRING CONCAT_VERSION(OBJFWRT_LIB_MAJOR, OBJFWRT_LIB_MINOR) @@ -593,11 +595,11 @@ .rt_Version = OBJFWRT_LIB_MAJOR, .rt_Type = NT_LIBRARY, .rt_Pri = 0, .rt_Name = (char *)OBJFWRT_AMIGA_LIB, .rt_IdString = (char *)"ObjFWRT " VERSION_STRING - " \xA9 2008-2022 Jonathan Schleifer", + " \xA9 2008-2023 Jonathan Schleifer", .rt_Init = &init_table, #ifdef OF_MORPHOS .rt_Revision = OBJFWRT_LIB_MINOR, .rt_Tags = NULL, #endif Index: src/runtime/arc.m ================================================================== --- src/runtime/arc.m +++ src/runtime/arc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/autorelease.m ================================================================== --- src/runtime/autorelease.m +++ src/runtime/autorelease.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/category.m ================================================================== --- src/runtime/category.m +++ src/runtime/category.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -56,18 +56,18 @@ objc_globalMutex_lock(); if (classes == NULL) { objc_globalMutex_unlock(); - return NO; + return false; } objc_hashtable_set(classes, name, (Class)((uintptr_t)class | 1)); objc_globalMutex_unlock(); - return YES; + return true; } static void registerSelectors(Class class) { @@ -90,25 +90,25 @@ /* * Fast path * * Instead of looking up the string in a dictionary, which needs * locking, we use a sparse array to look up the pointer. If - * objc_classname_to_class() gets called a lot, it is most likely that + * objc_classnameToClass() gets called a lot, it is most likely that * the GCC ABI is used, which always calls into objc_lookup_class(), or * that it is used in a loop by the user. In both cases, it is very * likely that the same string pointer is passed again and again. * - * This is not used before objc_classname_to_class() has been called a + * This is not used before objc_classnameToClass() has been called a * certain amount of times, so that no memory is wasted if it is only * used rarely, for example if the ObjFW ABI is used and the user does * not call it in a loop. * * Runtime internal usage does not use the fast path and does not count - * as a call into objc_classname_to_class(). The reason for this is - * that if the runtime calls into objc_classname_to_class(), it already - * has the lock and thus the performance gain would be small, but it - * would waste memory. + * as a call into objc_classnameToClass(). The reason for this is that + * if the runtime calls into objc_classnameToClass(), it already has + * the lock and thus the performance gain would be small, but it would + * waste memory. */ if (cache && fastPath != NULL) { class = objc_sparsearray_get(fastPath, (uintptr_t)name); if (class != Nil) @@ -778,11 +778,12 @@ objc_updateDTable(class); } Method -#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ <= 7 +#if defined(__clang__) && __has_attribute(__optnone__) && \ + __clang_major__ == 3 && __clang_minor__ <= 7 /* Work around an ICE in Clang 3.7.0 on Windows/x86 */ __attribute__((__optnone__)) #endif class_getInstanceMethod(Class class, SEL selector) { Index: src/runtime/dtable.m ================================================================== --- src/runtime/dtable.m +++ src/runtime/dtable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/exception.m ================================================================== --- src/runtime/exception.m +++ src/runtime/exception.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/hashtable.m ================================================================== --- src/runtime/hashtable.m +++ src/runtime/hashtable.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/init.m ================================================================== --- src/runtime/init.m +++ src/runtime/init.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/instance.m ================================================================== --- src/runtime/instance.m +++ src/runtime/instance.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/linklib/init.m ================================================================== --- src/runtime/linklib/init.m +++ src/runtime/linklib/init.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,12 +18,14 @@ #import "ObjFWRT.h" #import "private.h" #import "amiga-library.h" #define USE_INLINE_STDARG +#define Class IntuitionClass #include #include +#undef Class #include #include #if defined(OF_AMIGAOS_M68K) Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED src/runtime/lookup-asm/lookup-asm-amd64-elf.S Index: src/runtime/lookup-asm/lookup-asm-amd64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-amd64-elf.S +++ src/runtime/lookup-asm/lookup-asm-amd64-elf.S @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include "platform.h" + +.globl objc_msg_lookup +.globl objc_msg_lookup_stret +.globl objc_msg_lookup_super +.globl objc_msg_lookup_super_stret + +.section .text +.macro GENERATE_LOOKUP name notFound +\name: + testq %rdi, %rdi + jz returnNilMethod + + testb $1, %dil + jnz .LtaggedPointer_\name + + movq (%rdi), %r8 + movq 64(%r8), %r8 + +.Lmain_\name: + movq (%rsi), %rax + movzbl %ah, %ecx + movzbl %al, %edx +#ifdef OF_SELUID24 + shrl $16, %eax + + movq (%r8,%rax,8), %r8 +#endif + movq (%r8,%rcx,8), %r8 + movq (%r8,%rdx,8), %rax + + testq %rax, %rax + jz \notFound@PLT + + ret + +.LtaggedPointer_\name: + movq objc_taggedPointerSecret@GOTPCREL(%rip), %rax + xorq (%rax), %rdi + andb $0xE, %dil + movzbl %dil, %r8d + + movq objc_taggedPointerClasses@GOTPCREL(%rip), %rax + movq (%rax,%r8,4), %r8 + movq 64(%r8), %r8 + + jmp .Lmain_\name +.type \name, %function +.size \name, .-\name +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +\name: + movq %rdi, %r8 + movq (%rdi), %rdi + testq %rdi, %rdi + jz returnNilMethod + + movq 8(%r8), %r8 + movq 64(%r8), %r8 + jmp .Lmain_\lookup +.type \name, %function +.size \name, .-\name +.endm + +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret + +returnNilMethod: + leaq nilMethod(%rip), %rax + ret + +nilMethod: + xorq %rax, %rax + ret + +#if defined(OF_LINUX) || defined(OF_HURD) +.section .note.GNU-stack, "", %progbits +#endif ADDED src/runtime/lookup-asm/lookup-asm-amd64-macho.S Index: src/runtime/lookup-asm/lookup-asm-amd64-macho.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-amd64-macho.S +++ src/runtime/lookup-asm/lookup-asm-amd64-macho.S @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +.globl _objc_msg_lookup +.globl _objc_msg_lookup_stret +.globl _objc_msg_lookup_super +.globl _objc_msg_lookup_super_stret + +.section __TEXT, __text, regular, pure_instructions +.macro GENERATE_LOOKUP +$0: + testq %rdi, %rdi + jz returnNilMethod + + testb $$1, %dil + jnz LtaggedPointer_$0 + + movq (%rdi), %r8 + movq 64(%r8), %r8 + +Lmain_$0: + movq (%rsi), %rax + movzbl %ah, %ecx + movzbl %al, %edx +#ifdef OF_SELUID24 + shrl $$16, %eax + + movq (%r8,%rax,8), %r8 +#endif + movq (%r8,%rcx,8), %r8 + movq (%r8,%rdx,8), %rax + + testq %rax, %rax + jz $1 + + ret + +LtaggedPointer_$0: + movq _objc_taggedPointerSecret@GOTPCREL(%rip), %rax + xorq (%rax), %rdi + andb $$0xE, %dil + movzbl %dil, %r8d + + movq _objc_taggedPointerClasses@GOTPCREL(%rip), %rax + movq (%rax,%r8,4), %r8 + movq 64(%r8), %r8 + + jmp Lmain_$0 +.endmacro + +.macro GENERATE_LOOKUP_SUPER +$0: + movq %rdi, %r8 + movq (%rdi), %rdi + testq %rdi, %rdi + jz returnNilMethod + + movq 8(%r8), %r8 + movq 64(%r8), %r8 + jmp Lmain_$1 +.endmacro + +GENERATE_LOOKUP _objc_msg_lookup, _objc_methodNotFound +GENERATE_LOOKUP _objc_msg_lookup_stret, _objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super, _objc_msg_lookup +GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret, _objc_msg_lookup_stret + +returnNilMethod: + leaq nilMethod(%rip), %rax + ret + +nilMethod: + xorq %rax, %rax + ret ADDED src/runtime/lookup-asm/lookup-asm-amd64-win64.S Index: src/runtime/lookup-asm/lookup-asm-amd64-win64.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-amd64-win64.S +++ src/runtime/lookup-asm/lookup-asm-amd64-win64.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +.globl objc_msg_lookup +.globl objc_msg_lookup_stret +.globl objc_msg_lookup_super +.globl objc_msg_lookup_super_stret + +.section .text +.macro GENERATE_LOOKUP name notFound +\name: + testq %rcx, %rcx + jz returnNilMethod + + testb $1, %cl + jnz .LtaggedPointer_\name + + movq (%rcx), %r8 + movq 56(%r8), %r8 + +.Lmain_\name: + movq %rcx, %r10 + movq %rdx, %r11 + + movq (%rdx), %rax + movzbl %ah, %ecx + movzbl %al, %edx +#ifdef OF_SELUID24 + shrl $16, %eax + + movq (%r8,%rax,8), %r8 +#endif + movq (%r8,%rcx,8), %r8 + movq (%r8,%rdx,8), %rax + + testq %rax, %rax + jz 0f + + ret + +0: + movq %r10, %rcx + movq %r11, %rdx + jmp \notFound + +.LtaggedPointer_\name: + xorq objc_taggedPointerSecret(%rip), %rcx + andb $0xE, %cl + movzbl %cl, %r8d + + leaq objc_taggedPointerClasses(%rip), %rax + movq (%rax,%r8,4), %r8 + movq 56(%r8), %r8 + + jmp .Lmain_\name +.def \name +.scl 2 +.type 32 +.endef +.endm + +.macro GENERATE_LOOKUP_SUPER name lookup +\name: + movq %rcx, %r8 + movq (%rcx), %rcx + testq %rcx, %rcx + jz returnNilMethod + + movq 8(%r8), %r8 + movq 56(%r8), %r8 + jmp .Lmain_\lookup +.def \name +.scl 2 +.type 32 +.endef +.endm + +GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound +GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret +GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup +GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret + +returnNilMethod: + leaq nilMethod(%rip), %rax + ret + +nilMethod: + xorq %rax, %rax + ret Index: src/runtime/lookup-asm/lookup-asm-arm-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-arm-elf.S +++ src/runtime/lookup-asm/lookup-asm-arm-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -113,8 +113,8 @@ nilMethod: mov r0, #0 bx lr -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-arm64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-arm64-elf.S +++ src/runtime/lookup-asm/lookup-asm-arm64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -91,8 +91,8 @@ nilMethod: mov x0, #0 ret -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-mips-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-mips-elf.S +++ src/runtime/lookup-asm/lookup-asm-mips-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -152,8 +152,8 @@ nilMethod: move $v0, $zero jr $ra -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S +++ src/runtime/lookup-asm/lookup-asm-mips64-n64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -132,8 +132,8 @@ nilMethod: move $v0, $zero jr $ra -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-powerpc-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-powerpc-elf.S +++ src/runtime/lookup-asm/lookup-asm-powerpc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -166,8 +166,8 @@ .long objc_taggedPointerSecret .Lgot_objc_taggedPointerClasses: .long objc_taggedPointerClasses #endif -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", @progbits #endif Index: src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S +++ src/runtime/lookup-asm/lookup-asm-powerpc64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -156,8 +156,8 @@ li %r3, 0 blr .type nilMethod, @function .size nilMethod, .-.Lbegin_nilMethod -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", @progbits #endif Index: src/runtime/lookup-asm/lookup-asm-sparc-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-sparc-elf.S +++ src/runtime/lookup-asm/lookup-asm-sparc-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -142,8 +142,8 @@ nilMethod: retl clr %o0 -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-sparc64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-sparc64-elf.S +++ src/runtime/lookup-asm/lookup-asm-sparc64-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -139,8 +139,8 @@ nilMethod: retl clr %o0 -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-x86-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86-elf.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -53,23 +53,23 @@ ret 0: call getEIP addl $_GLOBAL_OFFSET_TABLE_, %eax - lea \notFound@GOTOFF(%eax), %eax + movl \notFound@GOT(%eax), %eax jmp *%eax .LtaggedPointer_\name: call getEIP addl $_GLOBAL_OFFSET_TABLE_, %eax - leal objc_taggedPointerSecret@GOTOFF(%eax), %ecx + movl objc_taggedPointerSecret@GOT(%eax), %ecx xorl (%ecx), %edx andb $0xE, %dl movzbl %dl, %edx - leal objc_taggedPointerClasses@GOTOFF(%eax), %eax + movl objc_taggedPointerClasses@GOT(%eax), %eax movl (%eax,%edx,2), %edx movl 32(%edx), %edx jmp .Lmain_\name .type \name, %function @@ -108,8 +108,8 @@ getEIP: movl (%esp), %eax ret -#ifdef OF_LINUX +#if defined(OF_LINUX) || defined(OF_HURD) .section .note.GNU-stack, "", %progbits #endif Index: src/runtime/lookup-asm/lookup-asm-x86-win32.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86-win32.S +++ src/runtime/lookup-asm/lookup-asm-x86-win32.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED src/runtime/lookup-asm/lookup-asm-x86_64-elf.S Index: src/runtime/lookup-asm/lookup-asm-x86_64-elf.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-elf.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-elf.S @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include "platform.h" - -.globl objc_msg_lookup -.globl objc_msg_lookup_stret -.globl objc_msg_lookup_super -.globl objc_msg_lookup_super_stret - -.section .text -.macro GENERATE_LOOKUP name notFound -\name: - testq %rdi, %rdi - jz returnNilMethod - - testb $1, %dil - jnz .LtaggedPointer_\name - - movq (%rdi), %r8 - movq 64(%r8), %r8 - -.Lmain_\name: - movq (%rsi), %rax - movzbl %ah, %ecx - movzbl %al, %edx -#ifdef OF_SELUID24 - shrl $16, %eax - - movq (%r8,%rax,8), %r8 -#endif - movq (%r8,%rcx,8), %r8 - movq (%r8,%rdx,8), %rax - - testq %rax, %rax - jz \notFound@PLT - - ret - -.LtaggedPointer_\name: - movq objc_taggedPointerSecret@GOTPCREL(%rip), %rax - xorq (%rax), %rdi - andb $0xE, %dil - movzbl %dil, %r8d - - movq objc_taggedPointerClasses@GOTPCREL(%rip), %rax - movq (%rax,%r8,4), %r8 - movq 64(%r8), %r8 - - jmp .Lmain_\name -.type \name, %function -.size \name, .-\name -.endm - -.macro GENERATE_LOOKUP_SUPER name lookup -\name: - movq %rdi, %r8 - movq (%rdi), %rdi - testq %rdi, %rdi - jz returnNilMethod - - movq 8(%r8), %r8 - movq 64(%r8), %r8 - jmp .Lmain_\lookup -.type \name, %function -.size \name, .-\name -.endm - -GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound -GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret -GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup -GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret - -returnNilMethod: - leaq nilMethod(%rip), %rax - ret - -nilMethod: - xorq %rax, %rax - ret - -#ifdef OF_LINUX -.section .note.GNU-stack, "", %progbits -#endif DELETED src/runtime/lookup-asm/lookup-asm-x86_64-macho.S Index: src/runtime/lookup-asm/lookup-asm-x86_64-macho.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-macho.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-macho.S @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -.globl _objc_msg_lookup -.globl _objc_msg_lookup_stret -.globl _objc_msg_lookup_super -.globl _objc_msg_lookup_super_stret - -.section __TEXT, __text, regular, pure_instructions -.macro GENERATE_LOOKUP -$0: - testq %rdi, %rdi - jz returnNilMethod - - testb $$1, %dil - jnz LtaggedPointer_$0 - - movq (%rdi), %r8 - movq 64(%r8), %r8 - -Lmain_$0: - movq (%rsi), %rax - movzbl %ah, %ecx - movzbl %al, %edx -#ifdef OF_SELUID24 - shrl $$16, %eax - - movq (%r8,%rax,8), %r8 -#endif - movq (%r8,%rcx,8), %r8 - movq (%r8,%rdx,8), %rax - - testq %rax, %rax - jz $1 - - ret - -LtaggedPointer_$0: - movq _objc_taggedPointerSecret@GOTPCREL(%rip), %rax - xorq (%rax), %rdi - andb $$0xE, %dil - movzbl %dil, %r8d - - movq _objc_taggedPointerClasses@GOTPCREL(%rip), %rax - movq (%rax,%r8,4), %r8 - movq 64(%r8), %r8 - - jmp Lmain_$0 -.endmacro - -.macro GENERATE_LOOKUP_SUPER -$0: - movq %rdi, %r8 - movq (%rdi), %rdi - testq %rdi, %rdi - jz returnNilMethod - - movq 8(%r8), %r8 - movq 64(%r8), %r8 - jmp Lmain_$1 -.endmacro - -GENERATE_LOOKUP _objc_msg_lookup, _objc_methodNotFound -GENERATE_LOOKUP _objc_msg_lookup_stret, _objc_methodNotFound_stret -GENERATE_LOOKUP_SUPER _objc_msg_lookup_super, _objc_msg_lookup -GENERATE_LOOKUP_SUPER _objc_msg_lookup_super_stret, _objc_msg_lookup_stret - -returnNilMethod: - leaq nilMethod(%rip), %rax - ret - -nilMethod: - xorq %rax, %rax - ret DELETED src/runtime/lookup-asm/lookup-asm-x86_64-win64.S Index: src/runtime/lookup-asm/lookup-asm-x86_64-win64.S ================================================================== --- src/runtime/lookup-asm/lookup-asm-x86_64-win64.S +++ src/runtime/lookup-asm/lookup-asm-x86_64-win64.S @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -.globl objc_msg_lookup -.globl objc_msg_lookup_stret -.globl objc_msg_lookup_super -.globl objc_msg_lookup_super_stret - -.section .text -.macro GENERATE_LOOKUP name notFound -\name: - testq %rcx, %rcx - jz returnNilMethod - - testb $1, %cl - jnz .LtaggedPointer_\name - - movq (%rcx), %r8 - movq 56(%r8), %r8 - -.Lmain_\name: - movq %rcx, %r10 - movq %rdx, %r11 - - movq (%rdx), %rax - movzbl %ah, %ecx - movzbl %al, %edx -#ifdef OF_SELUID24 - shrl $16, %eax - - movq (%r8,%rax,8), %r8 -#endif - movq (%r8,%rcx,8), %r8 - movq (%r8,%rdx,8), %rax - - testq %rax, %rax - jz 0f - - ret - -0: - movq %r10, %rcx - movq %r11, %rdx - jmp \notFound - -.LtaggedPointer_\name: - xorq objc_taggedPointerSecret(%rip), %rcx - andb $0xE, %cl - movzbl %cl, %r8d - - leaq objc_taggedPointerClasses(%rip), %rax - movq (%rax,%r8,4), %r8 - movq 56(%r8), %r8 - - jmp .Lmain_\name -.def \name -.scl 2 -.type 32 -.endef -.endm - -.macro GENERATE_LOOKUP_SUPER name lookup -\name: - movq %rcx, %r8 - movq (%rcx), %rcx - testq %rcx, %rcx - jz returnNilMethod - - movq 8(%r8), %r8 - movq 56(%r8), %r8 - jmp .Lmain_\lookup -.def \name -.scl 2 -.type 32 -.endef -.endm - -GENERATE_LOOKUP objc_msg_lookup objc_methodNotFound -GENERATE_LOOKUP objc_msg_lookup_stret objc_methodNotFound_stret -GENERATE_LOOKUP_SUPER objc_msg_lookup_super objc_msg_lookup -GENERATE_LOOKUP_SUPER objc_msg_lookup_super_stret objc_msg_lookup_stret - -returnNilMethod: - leaq nilMethod(%rip), %rax - ret - -nilMethod: - xorq %rax, %rax - ret Index: src/runtime/lookup-asm/lookup-asm.S ================================================================== --- src/runtime/lookup-asm/lookup-asm.S +++ src/runtime/lookup-asm/lookup-asm.S @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,12 +16,12 @@ #include "config.h" #include "platform.h" #if defined(OF_ELF) -# if defined(OF_X86_64) -# include "lookup-asm-x86_64-elf.S" +# if defined(OF_AMD64) +# include "lookup-asm-amd64-elf.S" # elif defined(OF_X86) # include "lookup-asm-x86-elf.S" # elif defined(OF_ARM64) # include "lookup-asm-arm64-elf.S" # elif defined(OF_ARM) @@ -38,15 +38,15 @@ # include "lookup-asm-sparc64-elf.S" # elif defined(OF_SPARC) # include "lookup-asm-sparc-elf.S" # endif #elif defined(OF_MACH_O) -# if defined(OF_X86_64) -# include "lookup-asm-x86_64-macho.S" +# if defined(OF_AMD64) +# include "lookup-asm-amd64-macho.S" # endif #elif defined(OF_WINDOWS) -# if defined(OF_X86_64) -# include "lookup-asm-x86_64-win64.S" +# if defined(OF_AMD64) +# include "lookup-asm-amd64-win64.S" # elif defined(OF_X86) # include "lookup-asm-x86-win32.S" # endif #endif Index: src/runtime/lookup.m ================================================================== --- src/runtime/lookup.m +++ src/runtime/lookup.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/method.m ================================================================== --- src/runtime/method.m +++ src/runtime/method.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/misc.m ================================================================== --- src/runtime/misc.m +++ src/runtime/misc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -25,18 +25,18 @@ #ifdef OF_WINDOWS # include #endif #ifdef OF_AMIGAOS +# define Class IntuitionClass # define USE_INLINE_STDARG # include # include # define __NOLIBBASE__ -# define Class IntuitionClass # include -# undef Class # undef __NOLIBBASE__ +# undef Class #endif static objc_enumeration_mutation_handler enumerationMutationHandler = NULL; void Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -355,23 +355,23 @@ #define OBJC_ERROR(...) \ objc_error("ObjFWRT @ " __FILE__ ":" OF_STRINGIFY(__LINE__), \ __VA_ARGS__) #if defined(OF_ELF) -# if defined(OF_X86_64) || defined(OF_X86) || \ +# if defined(OF_AMD64) || defined(OF_X86) || \ defined(OF_POWERPC64) || defined(OF_POWERPC) || \ defined(OF_ARM64) || defined(OF_ARM) || \ defined(OF_MIPS64_N64) || defined(OF_MIPS) || \ defined(OF_SPARC64) || defined(OF_SPARC) # define OF_ASM_LOOKUP # endif #elif defined(OF_MACH_O) -# if defined(OF_X86_64) +# if defined(OF_AMD64) # define OF_ASM_LOOKUP # endif #elif defined(OF_WINDOWS) -# if defined(OF_X86_64) || defined(OF_X86) +# if defined(OF_AMD64) || defined(OF_X86) # define OF_ASM_LOOKUP # endif #endif @interface DummyObject Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/protocol.m ================================================================== --- src/runtime/protocol.m +++ src/runtime/protocol.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/selector.m ================================================================== --- src/runtime/selector.m +++ src/runtime/selector.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/sparsearray.m ================================================================== --- src/runtime/sparsearray.m +++ src/runtime/sparsearray.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/static-instances.m ================================================================== --- src/runtime/static-instances.m +++ src/runtime/static-instances.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/synchronized.m ================================================================== --- src/runtime/synchronized.m +++ src/runtime/synchronized.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/tagged-pointer.m ================================================================== --- src/runtime/tagged-pointer.m +++ src/runtime/tagged-pointer.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/threading.m ================================================================== --- src/runtime/threading.m +++ src/runtime/threading.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/runtime/versioninfo.rc ================================================================== --- src/runtime/versioninfo.rc +++ src/runtime/versioninfo.rc @@ -12,11 +12,11 @@ VALUE "ProductName", "ObjFW Runtime" VALUE "ProductVersion", PACKAGE_VERSION VALUE "FileVersion", OBJFWRT_LIB_VERSION VALUE "FileDescription", "Objective-C runtime" VALUE "LegalCopyright", - "(c) 2008-2022 Jonathan Schleifer" + "(c) 2008-2023 Jonathan Schleifer" VALUE "InternalName", "ObjFWRT" VALUE "OriginalFilename", OBJFWRT_SHARED_LIB } } Index: src/tls/OFGnuTLSTLSStream.h ================================================================== --- src/tls/OFGnuTLSTLSStream.h +++ src/tls/OFGnuTLSTLSStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/tls/OFGnuTLSTLSStream.m ================================================================== --- src/tls/OFGnuTLSTLSStream.m +++ src/tls/OFGnuTLSTLSStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,11 +18,11 @@ #include #import "OFGnuTLSTLSStream.h" #import "OFData.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFReadFailedException.h" #import "OFTLSHandshakeFailedException.h" #import "OFWriteFailedException.h" @@ -200,11 +200,11 @@ OFTLSStreamErrorCodeInitializationFailed; id exception = nil; int status; if (_initialized) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if (gnutls_init(&_session, GNUTLS_CLIENT | GNUTLS_NONBLOCK | GNUTLS_SAFE_PADDING_CHECK) != GNUTLS_E_SUCCESS) @throw [OFTLSHandshakeFailedException exceptionWithStream: self Index: src/tls/OFOpenSSLTLSStream.h ================================================================== --- src/tls/OFOpenSSLTLSStream.h +++ src/tls/OFOpenSSLTLSStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- src/tls/OFOpenSSLTLSStream.m +++ src/tls/OFOpenSSLTLSStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -18,11 +18,11 @@ #include #import "OFOpenSSLTLSStream.h" #import "OFData.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFReadFailedException.h" #import "OFTLSHandshakeFailedException.h" #import "OFWriteFailedException.h" @@ -205,11 +205,11 @@ OFTLSStreamErrorCodeInitializationFailed; id exception = nil; int status; if (_SSL != NULL) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; if ((_readBIO = BIO_new(BIO_s_mem())) == NULL) @throw [OFTLSHandshakeFailedException exceptionWithStream: self host: host Index: src/tls/OFSecureTransportTLSStream.h ================================================================== --- src/tls/OFSecureTransportTLSStream.h +++ src/tls/OFSecureTransportTLSStream.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/tls/OFSecureTransportTLSStream.m ================================================================== --- src/tls/OFSecureTransportTLSStream.m +++ src/tls/OFSecureTransportTLSStream.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -17,11 +17,11 @@ #include #import "OFSecureTransportTLSStream.h" -#import "OFAlreadyConnectedException.h" +#import "OFAlreadyOpenException.h" #import "OFNotOpenException.h" #import "OFReadFailedException.h" #import "OFTLSHandshakeFailedException.h" #import "OFWriteFailedException.h" @@ -186,11 +186,11 @@ OFTLSStreamErrorCodeInitializationFailed; id exception = nil; OSStatus status; if (_context != NULL) - @throw [OFAlreadyConnectedException exceptionWithSocket: self]; + @throw [OFAlreadyOpenException exceptionWithObject: self]; #ifdef HAVE_SSLCREATECONTEXT if ((_context = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType)) == NULL) #else Index: src/tls/ObjFWTLS.h ================================================================== --- src/tls/ObjFWTLS.h +++ src/tls/ObjFWTLS.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/unicode.h ================================================================== --- src/unicode.h +++ src/unicode.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/unicode.m ================================================================== --- src/unicode.m +++ src/unicode.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/unistd_wrapper.h ================================================================== --- src/unistd_wrapper.h +++ src/unistd_wrapper.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: src/versioninfo.rc ================================================================== --- src/versioninfo.rc +++ src/versioninfo.rc @@ -12,11 +12,11 @@ VALUE "ProductName", "ObjFW" VALUE "ProductVersion", PACKAGE_VERSION VALUE "FileVersion", OBJFW_LIB_VERSION VALUE "FileDescription", "Objective-C framework" VALUE "LegalCopyright", - "(c) 2008-2022 Jonathan Schleifer" + "(c) 2008-2023 Jonathan Schleifer" VALUE "InternalName", "ObjFW" VALUE "OriginalFilename", OBJFW_SHARED_LIB } } Index: tests/ForwardingTests.m ================================================================== --- tests/ForwardingTests.m +++ tests/ForwardingTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/ImportTest.m ================================================================== --- tests/ImportTest.m +++ tests/ImportTest.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -11,6 +11,6 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#import +@import ObjFW; Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -8,11 +8,10 @@ boot.dol \ ${PROG_NOINST}.arm9 \ ${PROG_NOINST}.nds \ ${PROG_NOINST}.nro \ ${PROG_NOINST}.rpx \ - serialization_xml.m \ testfile_bin.m \ testfile_ini.m DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} @@ -19,20 +18,23 @@ STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ OFCharacterSetTests.m \ + OFColorTests.m \ OFDataTests.m \ OFDateTests.m \ OFDictionaryTests.m \ OFHMACTests.m \ OFINIFileTests.m \ + OFIRITests.m \ OFInvocationTests.m \ OFJSONTests.m \ OFListTests.m \ OFLocaleTests.m \ OFMD5HashTests.m \ + OFMatrix4x4Tests.m \ OFMemoryStreamTests.m \ OFMethodSignatureTests.m \ OFNotificationCenterTests.m \ OFNumberTests.m \ OFObjectTests.m \ @@ -43,16 +45,14 @@ OFSHA224HashTests.m \ OFSHA256HashTests.m \ OFSHA384HashTests.m \ OFSHA512HashTests.m \ OFScryptTests.m \ - OFSerializationTests.m \ OFSetTests.m \ OFStreamTests.m \ OFStringTests.m \ OFSystemInfoTests.m \ - OFURITests.m \ OFValueTests.m \ OFXMLElementBuilderTests.m \ OFXMLNodeTests.m \ OFXMLParserTests.m \ RuntimeTests.m \ @@ -61,11 +61,10 @@ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ ${USE_SRCS_THREADS} \ ${USE_SRCS_WINDOWS} \ - serialization_xml.m \ testfile_bin.m \ testfile_ini.m SRCS_PLUGINS = OFPluginTests.m SRCS_SOCKETS = OFDNSResolverTests.m \ ${OF_HTTP_CLIENT_TESTS_M} \ @@ -90,12 +89,10 @@ IOS_USER ?= mobile IOS_TMP ?= /tmp/objfw-test include ../buildsys.mk -serialization_xml.m: serialization.xml - ${SHELL} ../utils/objfw-embed serialization.xml serialization.xml $@ testfile_bin.m: testfile.bin ${SHELL} ../utils/objfw-embed testfile.bin testfile.bin $@ testfile_ini.m: testfile.ini ${SHELL} ../utils/objfw-embed testfile.ini testfile.ini $@ Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -429,20 +429,20 @@ [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && [[[arrayClass arrayWithObjects: @"1", @"2", nil] valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) mutableArray1 = [mutableArrayClass arrayWithObjects: - [OFMutableURI URIWithString: @"http://foo.bar/"], - [OFMutableURI URIWithString: @"http://bar.qux/"], - [OFMutableURI URIWithString: @"http://qux.quxqux/"], nil]; + [OFMutableIRI IRIWithString: @"http://foo.bar/"], + [OFMutableIRI IRIWithString: @"http://bar.qux/"], + [OFMutableIRI IRIWithString: @"http://qux.quxqux/"], nil]; TEST(@"-[setValue:forKey:]", R([mutableArray1 setValue: [OFNumber numberWithShort: 1234] forKey: @"port"]) && [mutableArray1 isEqual: [arrayClass arrayWithObjects: - [OFURI URIWithString: @"http://foo.bar:1234/"], - [OFURI URIWithString: @"http://bar.qux:1234/"], - [OFURI URIWithString: @"http://qux.quxqux:1234/"], nil]]) + [OFIRI IRIWithString: @"http://foo.bar:1234/"], + [OFIRI IRIWithString: @"http://bar.qux:1234/"], + [OFIRI IRIWithString: @"http://qux.quxqux:1234/"], nil]]) objc_autoreleasePoolPop(pool); } - (void)arrayTests Index: tests/OFBlockTests.m ================================================================== --- tests/OFBlockTests.m +++ tests/OFBlockTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -27,11 +27,14 @@ extern void *_NSConcreteStackBlock; extern void *_NSConcreteGlobalBlock; extern void *_NSConcreteMallocBlock; #endif +/* Clang on Win32 generates broken code that crashes for global blocks. */ +#if !defined(OF_WINDOWS) || !defined(OF_X86) || !defined(__clang__) static void (^globalBlock)(void) = ^ {}; +#endif static int (^returnStackBlock(void))(void) { __block int i = 42; @@ -67,15 +70,11 @@ TEST(@"Class of stack block", (Class)&_NSConcreteStackBlock == objc_getClass("OFStackBlock") && [stackBlock isKindOfClass: [OFBlock class]]) -#if !defined(OF_WINDOWS) || !defined(__clang__) || !defined(OF_NO_SHARED) - /* - * Causes a linker error on Windows with Clang when compiling as a - * static library. This is a bug in Clang. - */ +#if !defined(OF_WINDOWS) || !defined(OF_X86) || !defined(__clang__) TEST(@"Class of global block", (Class)&_NSConcreteGlobalBlock == objc_getClass("OFGlobalBlock") && [globalBlock isKindOfClass: [OFBlock class]]) #endif @@ -92,25 +91,29 @@ TEST(@"Copying a stack block and using its copied variable", (voidBlock = returnStackBlock()) && voidBlock() == 43 && voidBlock() == 44 && voidBlock() == 45) +#if !defined(OF_WINDOWS) || !defined(OF_X86) || !defined(__clang__) TEST(@"Copying a global block", (id)globalBlock == [[globalBlock copy] autorelease]) +#endif #ifndef __clang_analyzer__ TEST(@"Copying a malloc block", (id)mallocBlock == [mallocBlock copy] && [mallocBlock retainCount] == 2) #endif TEST(@"Autorelease a stack block", R([stackBlock autorelease])) +#if !defined(OF_WINDOWS) || !defined(OF_X86) || !defined(__clang__) TEST(@"Autorelease a global block", R([globalBlock autorelease])) +#endif #ifndef __clang_analyzer__ TEST(@"Autorelease a malloc block", R([mallocBlock autorelease])) #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFCharacterSetTests.m ================================================================== --- tests/OFCharacterSetTests.m +++ tests/OFCharacterSetTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in ADDED tests/OFColorTests.m Index: tests/OFColorTests.m ================================================================== --- tests/OFColorTests.m +++ tests/OFColorTests.m @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFColor"; + +@implementation TestsAppDelegate (OFColorTests) +- (void)colorTests +{ + void *pool = objc_autoreleasePoolPush(); + OFColor *color; + float red, green, blue, alpha; + + TEST(@"+[colorWithRed:green:blue:alpha:]", + (color = [OFColor colorWithRed: 63.f / 255 + green: 127.f / 255 + blue: 1 + alpha: 1])) + +#ifdef OF_OBJFW_RUNTIME + TEST(@"+[colorWithRed:green:blue:alpha:] returns tagged pointer", + object_isTaggedPointer(color)) +#endif + + TEST(@"-[getRed:green:blue:alpha:]", + R([color getRed: &red green: &green blue: &blue alpha: &alpha]) && + red == 63.f / 255 && green == 127.f / 255 && blue == 1 && + alpha == 1) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFDDPSocketTests.m ================================================================== --- tests/OFDDPSocketTests.m +++ tests/OFDDPSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -38,10 +38,11 @@ port: 0 protocolType: 11])) } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: + case EPROTONOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @"\r[OFDDPSocket] -[bindToNetwork:node:port:" @"protocolType:] AppleTalk unsupported, skipping " @"tests"]; Index: tests/OFDNSResolverTests.m ================================================================== --- tests/OFDNSResolverTests.m +++ tests/OFDNSResolverTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -57,15 +57,15 @@ [OFStdOut writeFormat: @"[OFDNSResolver] Min number of dots in absolute name: %u\n", resolver.minNumberOfDotsInAbsoluteName]; - [OFStdOut writeFormat: @"[OFDNSResolver] Uses TCP: %u\n", - resolver.usesTCP]; + [OFStdOut writeFormat: @"[OFDNSResolver] Forces TCP: %u\n", + resolver.forcesTCP]; [OFStdOut writeFormat: @"[OFDNSResolver] Config reload interval: %lf\n", resolver.configReloadInterval]; objc_autoreleasePoolPop(pool); } @end Index: tests/OFDataTests.m ================================================================== --- tests/OFDataTests.m +++ tests/OFDataTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFHMACTests.m ================================================================== --- tests/OFHMACTests.m +++ tests/OFHMACTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -49,12 +49,12 @@ @implementation TestsAppDelegate (OFHMACTests) - (void)HMACTests { void *pool = objc_autoreleasePoolPush(); - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; OFHMAC *HMACMD5, *HMACSHA1, *HMACRMD160; OFHMAC *HMACSHA256, *HMACSHA384, *HMACSHA512; TEST(@"+[HMACWithHashClass:] with MD5", (HMACMD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] Index: tests/OFHTTPClientTests.m ================================================================== --- tests/OFHTTPClientTests.m +++ tests/OFHTTPClientTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -36,16 +36,18 @@ @implementation HTTPClientTestsServer - (id)main { OFTCPSocket *listener, *client; + OFSocketAddress address; char buffer[5]; [condition lock]; listener = [OFTCPSocket socket]; - _port = [listener bindToHost: @"127.0.0.1" port: 0]; + address = [listener bindToHost: @"127.0.0.1" port: 0]; + _port = OFSocketAddressIPPort(&address); [listener listen]; [condition signal]; [condition unlock]; @@ -99,11 +101,11 @@ - (void)HTTPClientTests { void *pool = objc_autoreleasePoolPush(); HTTPClientTestsServer *server; - OFURI *URI; + OFIRI *IRI; OFHTTPClient *client; OFHTTPRequest *request; OFData *data; condition = [OFCondition condition]; @@ -114,17 +116,17 @@ [server start]; [condition wait]; [condition unlock]; - URI = [OFURI URIWithString: + IRI = [OFIRI IRIWithString: [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo", server->_port]]; TEST(@"-[asyncPerformRequest:]", (client = [OFHTTPClient client]) && (client.delegate = self) && - (request = [OFHTTPRequest requestWithURI: URI]) && + (request = [OFHTTPRequest requestWithIRI: IRI]) && (request.headers = [OFDictionary dictionaryWithObject: @"5" forKey: @"Content-Length"]) && R([client asyncPerformRequest: request])) Index: tests/OFHTTPCookieManagerTests.m ================================================================== --- tests/OFHTTPCookieManagerTests.m +++ tests/OFHTTPCookieManagerTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -22,75 +22,75 @@ @implementation TestsAppDelegate (OFHTTPCookieManagerTests) - (void)HTTPCookieManagerTests { void *pool = objc_autoreleasePoolPush(); OFHTTPCookieManager *manager = [OFHTTPCookieManager manager]; - OFURI *URI1, *URI2, *URI3, *URI4; + OFIRI *IRI1, *IRI2, *IRI3, *IRI4; OFHTTPCookie *cookie1, *cookie2, *cookie3, *cookie4, *cookie5; - URI1 = [OFURI URIWithString: @"http://nil.im/foo"]; - URI2 = [OFURI URIWithString: @"https://nil.im/foo/bar"]; - URI3 = [OFURI URIWithString: @"https://test.nil.im/foo/bar"]; - URI4 = [OFURI URIWithString: @"http://webkeks.org/foo/bar"]; + IRI1 = [OFIRI IRIWithString: @"http://nil.im/foo"]; + IRI2 = [OFIRI IRIWithString: @"https://nil.im/foo/bar"]; + IRI3 = [OFIRI IRIWithString: @"https://test.nil.im/foo/bar"]; + IRI4 = [OFIRI IRIWithString: @"http://webkeks.org/foo/bar"]; cookie1 = [OFHTTPCookie cookieWithName: @"test" value: @"1" domain: @"nil.im"]; - TEST(@"-[addCookie:forURI:] #1", - R([manager addCookie: cookie1 forURI: URI1])) + TEST(@"-[addCookie:forIRI:] #1", + R([manager addCookie: cookie1 forIRI: IRI1])) - TEST(@"-[cookiesForURI:] #1", - [[manager cookiesForURI: URI1] isEqual: + TEST(@"-[cookiesForIRI:] #1", + [[manager cookiesForIRI: IRI1] isEqual: [OFArray arrayWithObject: cookie1]]) cookie2 = [OFHTTPCookie cookieWithName: @"test" value: @"2" domain: @"webkeks.org"]; - TEST(@"-[addCookie:forURI:] #2", - R([manager addCookie: cookie2 forURI: URI1])) + TEST(@"-[addCookie:forIRI:] #2", + R([manager addCookie: cookie2 forIRI: IRI1])) - TEST(@"-[cookiesForURI:] #2", - [[manager cookiesForURI: URI1] isEqual: + TEST(@"-[cookiesForIRI:] #2", + [[manager cookiesForIRI: IRI1] isEqual: [OFArray arrayWithObject: cookie1]] && - [[manager cookiesForURI: URI4] isEqual: [OFArray array]]) + [[manager cookiesForIRI: IRI4] isEqual: [OFArray array]]) cookie3 = [OFHTTPCookie cookieWithName: @"test" value: @"3" domain: @"nil.im"]; cookie3.secure = true; - TEST(@"-[addCookie:forURI:] #3", - R([manager addCookie: cookie3 forURI: URI2])) + TEST(@"-[addCookie:forIRI:] #3", + R([manager addCookie: cookie3 forIRI: IRI2])) - TEST(@"-[cookiesForURI:] #3", - [[manager cookiesForURI: URI2] isEqual: + TEST(@"-[cookiesForIRI:] #3", + [[manager cookiesForIRI: IRI2] isEqual: [OFArray arrayWithObject: cookie3]] && - [[manager cookiesForURI: URI1] isEqual: [OFArray array]]) + [[manager cookiesForIRI: IRI1] isEqual: [OFArray array]]) cookie3.expires = [OFDate dateWithTimeIntervalSinceNow: -1]; cookie4 = [OFHTTPCookie cookieWithName: @"test" value: @"4" domain: @"nil.im"]; cookie4.domain = @".nil.im"; - TEST(@"-[addCookie:forURI:] #4", - R([manager addCookie: cookie4 forURI: URI2])) + TEST(@"-[addCookie:forIRI:] #4", + R([manager addCookie: cookie4 forIRI: IRI2])) - TEST(@"-[cookiesForURI:] #4", - [[manager cookiesForURI: URI2] isEqual: + TEST(@"-[cookiesForIRI:] #4", + [[manager cookiesForIRI: IRI2] isEqual: [OFArray arrayWithObject: cookie4]] && - [[manager cookiesForURI: URI3] isEqual: + [[manager cookiesForIRI: IRI3] isEqual: [OFArray arrayWithObject: cookie4]]) cookie5 = [OFHTTPCookie cookieWithName: @"bar" value: @"5" domain: @"test.nil.im"]; - TEST(@"-[addCookie:forURI:] #5", - R([manager addCookie: cookie5 forURI: URI1])) + TEST(@"-[addCookie:forIRI:] #5", + R([manager addCookie: cookie5 forIRI: IRI1])) - TEST(@"-[cookiesForURI:] #5", - [[manager cookiesForURI: URI1] isEqual: + TEST(@"-[cookiesForIRI:] #5", + [[manager cookiesForIRI: IRI1] isEqual: [OFArray arrayWithObject: cookie4]] && - [[manager cookiesForURI: URI3] isEqual: + [[manager cookiesForIRI: IRI3] isEqual: [OFArray arrayWithObjects: cookie4, cookie5, nil]]) TEST(@"-[purgeExpiredCookies]", [manager.cookies isEqual: [OFArray arrayWithObjects: cookie3, cookie4, cookie5, nil]] && Index: tests/OFHTTPCookieTests.m ================================================================== --- tests/OFHTTPCookieTests.m +++ tests/OFHTTPCookieTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -21,30 +21,30 @@ @implementation TestsAppDelegate (OFHTTPCookieTests) - (void)HTTPCookieTests { void *pool = objc_autoreleasePoolPush(); - OFURI *URI = [OFURI URIWithString: @"http://nil.im"]; + OFIRI *IRI = [OFIRI IRIWithString: @"http://nil.im"]; OFHTTPCookie *cookie1, *cookie2; OFArray OF_GENERIC(OFHTTPCookie *) *cookies; cookie1 = [OFHTTPCookie cookieWithName: @"foo" value: @"bar" domain: @"nil.im"]; - TEST(@"+[cookiesWithResponseHeaderFields:forURI:] #1", + TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #1", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar" - forKey: @"Set-Cookie"] forURI: URI] + forKey: @"Set-Cookie"] forIRI: IRI] isEqual: [OFArray arrayWithObject: cookie1]]) cookie2 = [OFHTTPCookie cookieWithName: @"qux" value: @"cookie" domain: @"nil.im"]; - TEST(@"+[cookiesWithResponseHeaderFields:forURI:] #2", + TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #2", [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar,qux=cookie" - forKey: @"Set-Cookie"] forURI: URI] + forKey: @"Set-Cookie"] forIRI: IRI] isEqual: [OFArray arrayWithObjects: cookie1, cookie2, nil]]) cookie1.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; cookie2.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890]; cookie1.path = @"/x"; @@ -52,17 +52,17 @@ cookie2.path = @"/objfw"; cookie2.secure = true; cookie2.HTTPOnly = true; [cookie2.extensions addObject: @"foo"]; [cookie2.extensions addObject: @"bar"]; - TEST(@"+[cookiesWithResponseHeaderFields:forURI:] #3", + TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #3", [(cookies = [OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary dictionaryWithObject: @"foo=bar; Expires=Fri, 13 Feb 2009 23:31:30 GMT; Path=/x," @"qux=cookie; Expires=Fri, 13 Feb 2009 23:31:30 GMT; " @"Domain=webkeks.org; Path=/objfw; Secure; HTTPOnly; foo; bar" - forKey: @"Set-Cookie"] forURI: URI]) isEqual: + forKey: @"Set-Cookie"] forIRI: IRI]) isEqual: [OFArray arrayWithObjects: cookie1, cookie2, nil]]) TEST(@"+[requestHeaderFieldsWithCookies:]", [[OFHTTPCookie requestHeaderFieldsWithCookies: cookies] isEqual: [OFDictionary dictionaryWithObject: @"foo=bar; qux=cookie" Index: tests/OFINIFileTests.m ================================================================== --- tests/OFINIFileTests.m +++ tests/OFINIFileTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -41,23 +41,23 @@ @"bool=false\r\n" @"float=0.25\r\n" @"array1=foo\r\n" @"array1=bar\r\n" @"double=0.75\r\n"; - OFURI *URI; + OFIRI *IRI; OFINIFile *file; OFINICategory *tests, *foobar, *types; OFArray *array; #if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) - OFURI *writeURI; + OFIRI *writeIRI; #endif module = @"OFINIFile"; - URI = [OFURI URIWithString: @"embedded:testfile.ini"]; - TEST(@"+[fileWithURI:encoding:]", - (file = [OFINIFile fileWithURI: URI + IRI = [OFIRI IRIWithString: @"embedded:testfile.ini"]; + TEST(@"+[fileWithIRI:encoding:]", + (file = [OFINIFile fileWithIRI: IRI encoding: OFStringEncodingCodepage437])) tests = [file categoryForName: @"tests"]; foobar = [file categoryForName: @"foobar"]; types = [file categoryForName: @"types"]; @@ -114,22 +114,24 @@ module = @"OFINIFile"; /* FIXME: Find a way to write files on Nintendo DS */ #if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) - writeURI = [[OFSystemInfo temporaryDirectoryURI] - URIByAppendingPathComponent: @"objfw-tests.ini" - isDirectory: false]; + writeIRI = [OFSystemInfo temporaryDirectoryIRI]; + if (writeIRI == nil) + writeIRI = [[OFFileManager defaultManager] currentDirectoryIRI]; + writeIRI = [writeIRI IRIByAppendingPathComponent: @"objfw-tests.ini" + isDirectory: false]; TEST(@"-[writeToFile:encoding:]", - R([file writeToURI: writeURI + R([file writeToIRI: writeIRI encoding: OFStringEncodingCodepage437]) && - [[OFString stringWithContentsOfURI: writeURI + [[OFString stringWithContentsOfIRI: writeIRI encoding: OFStringEncodingCodepage437] isEqual: output]) - [[OFFileManager defaultManager] removeItemAtURI: writeURI]; + [[OFFileManager defaultManager] removeItemAtIRI: writeIRI]; #else (void)output; #endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFIPXSocketTests.m ================================================================== --- tests/OFIPXSocketTests.m +++ tests/OFIPXSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -26,12 +26,14 @@ { const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; void *pool = objc_autoreleasePoolPush(); OFIPXSocket *sock; OFSocketAddress address1, address2; + OFDictionary *networkInterfaces; char buffer[5]; unsigned char node1[IPX_NODE_LEN], node2[IPX_NODE_LEN]; + unsigned char node[IPX_NODE_LEN]; TEST(@"+[socket]", (sock = [OFIPXSocket socket])) @try { TEST(@"-[bindToNetwork:node:port:packetType:]", @@ -59,10 +61,41 @@ } objc_autoreleasePoolPop(pool); return; } + + /* + * Find any network interface with IPX and send to it. Any should be + * fine since we bound to 0.0. + */ + networkInterfaces = [OFSystemInfo networkInterfaces]; + for (OFString *name in networkInterfaces) { + OFNetworkInterface interface = [networkInterfaces + objectForKey: name]; + OFData *addresses = [interface + objectForKey: OFNetworkInterfaceIPXAddresses]; + + if (addresses.count == 0) + continue; + + OFSocketAddressSetIPXNetwork(&address1, + OFSocketAddressIPXNetwork([addresses itemAtIndex: 0])); + OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node); + OFSocketAddressSetIPXNode(&address1, node); + } + + OFSocketAddressGetIPXNode(&address1, node); + if (OFSocketAddressIPXNetwork(&address1) == 0 && + memcmp(node, zeroNode, 6) == 0) { + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"[OFIPXSocket] -[sendBuffer:length:receiver:]: " + @"Could not determine own address, skipping tests"]; + objc_autoreleasePoolPop(pool); + return; + } TEST(@"-[sendBuffer:length:receiver:]", R([sock sendBuffer: "Hello" length: 5 receiver: &address1])) TEST(@"-[receiveIntoBuffer:length:sender:]", ADDED tests/OFIRITests.m Index: tests/OFIRITests.m ================================================================== --- tests/OFIRITests.m +++ tests/OFIRITests.m @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFIRI"; +static OFString *IRIString = @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/" + @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; + +@implementation TestsAppDelegate (OFIRITests) +- (void)IRITests +{ + void *pool = objc_autoreleasePoolPush(); + OFIRI *IRI1, *IRI2, *IRI3, *IRI4, *IRI5, *IRI6, *IRI7, *IRI8, *IRI9; + OFIRI *IRI10, *IRI11; + OFMutableIRI *mutableIRI; + + TEST(@"+[IRIWithString:]", + R(IRI1 = [OFIRI IRIWithString: IRIString]) && + R(IRI2 = [OFIRI IRIWithString: @"http://foo:80"]) && + R(IRI3 = [OFIRI IRIWithString: @"http://bar/"]) && + R(IRI4 = [OFIRI IRIWithString: @"file:///etc/passwd"]) && + R(IRI5 = [OFIRI IRIWithString: @"http://foo/bar/qux/foo%2fbar"]) && + R(IRI6 = [OFIRI IRIWithString: @"https://[12:34::56:abcd]/"]) && + R(IRI7 = [OFIRI IRIWithString: @"https://[12:34::56:abcd]:234/"]) && + R(IRI8 = [OFIRI IRIWithString: @"urn:qux:foo"]) && + R(IRI9 = [OFIRI IRIWithString: @"file:/foo?query#frag"]) && + R(IRI10 = [OFIRI IRIWithString: @"file:foo@bar/qux?query#frag"]) && + R(IRI11 = [OFIRI IRIWithString: @"http://ä/ö?ü"])) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #1", + OFInvalidFormatException, + [OFIRI IRIWithString: @"ht,tp://foo"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #2", + OFInvalidFormatException, + [OFIRI IRIWithString: @"http://f`oo"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #3", + OFInvalidFormatException, + [OFIRI IRIWithString: @"http://foo/`"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #4", + OFInvalidFormatException, + [OFIRI IRIWithString: @"http://foo/foo?`"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #5", + OFInvalidFormatException, + [OFIRI IRIWithString: @"http://foo/foo?foo#`"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #6", + OFInvalidFormatException, + [OFIRI IRIWithString: @"https://[g]/"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #7", + OFInvalidFormatException, + [OFIRI IRIWithString: @"https://[f]:/"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #8", + OFInvalidFormatException, + [OFIRI IRIWithString: @"https://[f]:f/"]) + + EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #9", + OFInvalidFormatException, + [OFIRI IRIWithString: @"foo:"]) + + TEST(@"+[IRIWithString:relativeToIRI:]", + [[[OFIRI IRIWithString: @"/foo" relativeToIRI: IRI1] string] + isEqual: @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && + [[[OFIRI IRIWithString: @"foo/bar?q" + relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/quux"]] + string] isEqual: @"http://h/qux/foo/bar?q"] && + [[[OFIRI IRIWithString: @"foo/bar" + relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/?x"]] + string] isEqual: @"http://h/qux/foo/bar"] && + [[[OFIRI IRIWithString: @"http://foo/?q" + relativeToIRI: IRI1] string] isEqual: @"http://foo/?q"] && + [[[OFIRI IRIWithString: @"foo" + relativeToIRI: [OFIRI IRIWithString: @"http://foo/bar"]] + string] isEqual: @"http://foo/foo"] && + [[[OFIRI IRIWithString: @"foo" + relativeToIRI: [OFIRI IRIWithString: @"http://foo"]] + string] isEqual: @"http://foo/foo"]) + + EXPECT_EXCEPTION( + @"+[IRIWithString:relativeToIRI:] fails with invalid characters #1", + OFInvalidFormatException, + [OFIRI IRIWithString: @"`" relativeToIRI: IRI1]) + + EXPECT_EXCEPTION( + @"+[IRIWithString:relativeToIRI:] fails with invalid characters #2", + OFInvalidFormatException, + [OFIRI IRIWithString: @"/`" relativeToIRI: IRI1]) + + EXPECT_EXCEPTION( + @"+[IRIWithString:relativeToIRI:] fails with invalid characters #3", + OFInvalidFormatException, + [OFIRI IRIWithString: @"?`" relativeToIRI: IRI1]) + + EXPECT_EXCEPTION( + @"+[IRIWithString:relativeToIRI:] fails with invalid characters #4", + OFInvalidFormatException, + [OFIRI IRIWithString: @"#`" relativeToIRI: IRI1]) + +#ifdef OF_HAVE_FILES + TEST(@"+[fileIRIWithPath:]", + [[[OFIRI fileIRIWithPath: @"testfile.txt"] fileSystemRepresentation] + isEqual: [[OFFileManager defaultManager].currentDirectoryPath + stringByAppendingPathComponent: @"testfile.txt"]]) + +# if defined(OF_WINDOWS) || defined(OF_MSDOS) + OFIRI *tmp; + TEST(@"+[fileIRIWithPath:] for c:\\", + (tmp = [OFIRI fileIRIWithPath: @"c:\\"]) && + [tmp.string isEqual: @"file:/c:/"] && + [tmp.fileSystemRepresentation isEqual: @"c:\\"]) +# endif + +# ifdef OF_WINDOWS + TEST(@"+[fileIRIWithPath:] with UNC", + (tmp = [OFIRI fileIRIWithPath: @"\\\\foo\\bar" + isDirectory: false]) && + [tmp.host isEqual: @"foo"] && [tmp.path isEqual: @"/bar"] && + [tmp.string isEqual: @"file://foo/bar"] && + [tmp.fileSystemRepresentation isEqual: @"\\\\foo\\bar"] && + (tmp = [OFIRI fileIRIWithPath: @"\\\\test" isDirectory: true]) && + [tmp.host isEqual: @"test"] && [tmp.path isEqual: @"/"] && + [tmp.string isEqual: @"file://test/"] && + [tmp.fileSystemRepresentation isEqual: @"\\\\test"]) +# endif +#endif + + TEST(@"-[string]", + [IRI1.string isEqual: IRIString] && + [IRI2.string isEqual: @"http://foo:80"] && + [IRI3.string isEqual: @"http://bar/"] && + [IRI4.string isEqual: @"file:///etc/passwd"] && + [IRI5.string isEqual: @"http://foo/bar/qux/foo%2fbar"] && + [IRI6.string isEqual: @"https://[12:34::56:abcd]/"] && + [IRI7.string isEqual: @"https://[12:34::56:abcd]:234/"] && + [IRI8.string isEqual: @"urn:qux:foo"] && + [IRI9.string isEqual: @"file:/foo?query#frag"] && + [IRI10.string isEqual: @"file:foo@bar/qux?query#frag"] && + [IRI11.string isEqual: @"http://ä/ö?ü"]) + + TEST(@"-[scheme]", + [IRI1.scheme isEqual: @"ht+tp"] && [IRI4.scheme isEqual: @"file"] && + [IRI9.scheme isEqual: @"file"] && [IRI10.scheme isEqual: @"file"] && + [IRI11.scheme isEqual: @"http"]) + + TEST(@"-[user]", [IRI1.user isEqual: @"us:er"] && IRI4.user == nil && + IRI10.user == nil && IRI11.user == nil) + TEST(@"-[password]", + [IRI1.password isEqual: @"p@w"] && IRI4.password == nil && + IRI10.password == nil && IRI11.password == nil) + TEST(@"-[host]", [IRI1.host isEqual: @"ho:st"] && + [IRI6.host isEqual: @"12:34::56:abcd"] && + [IRI7.host isEqual: @"12:34::56:abcd"] && + IRI8.host == nil && IRI9.host == nil && IRI10.host == nil && + [IRI11.host isEqual: @"ä"]) + TEST(@"-[port]", IRI1.port.unsignedShortValue == 1234 && + [IRI4 port] == nil && IRI7.port.unsignedShortValue == 234 && + IRI8.port == nil && IRI9.port == nil && IRI10.port == nil && + IRI11.port == nil) + TEST(@"-[path]", + [IRI1.path isEqual: @"/pa?th"] && + [IRI4.path isEqual: @"/etc/passwd"] && + [IRI8.path isEqual: @"qux:foo"] && + [IRI9.path isEqual: @"/foo"] && + [IRI10.path isEqual: @"foo@bar/qux"] && + [IRI11.path isEqual: @"/ö"]) + TEST(@"-[pathComponents]", + [IRI1.pathComponents isEqual: + [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && + [IRI4.pathComponents isEqual: + [OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil]] && + [IRI5.pathComponents isEqual: + [OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", nil]]) + TEST(@"-[lastPathComponent]", + [[[OFIRI IRIWithString: @"http://host/foo//bar/baz"] + lastPathComponent] isEqual: @"baz"] && + [[[OFIRI IRIWithString: @"http://host/foo//bar/baz/"] + lastPathComponent] isEqual: @"baz"] && + [[[OFIRI IRIWithString: @"http://host/foo/"] + lastPathComponent] isEqual: @"foo"] && + [[[OFIRI IRIWithString: @"http://host/"] + lastPathComponent] isEqual: @"/"] && + [IRI5.lastPathComponent isEqual: @"foo/bar"]) + TEST(@"-[query]", + [IRI1.query isEqual: @"que#ry=1&f&oo=b=ar"] && IRI4.query == nil && + [IRI9.query isEqual: @"query"] && [IRI10.query isEqual: @"query"] && + [IRI11.query isEqual: @"ü"]) + TEST(@"-[queryItems]", + [IRI1.queryItems isEqual: [OFArray arrayWithObjects: + [OFPair pairWithFirstObject: @"que#ry" secondObject: @"1"], + [OFPair pairWithFirstObject: @"f&oo" secondObject: @"b=ar"], nil]]); + TEST(@"-[fragment]", + [IRI1.fragment isEqual: @"frag#ment"] && IRI4.fragment == nil && + [IRI9.fragment isEqual: @"frag"] && + [IRI10.fragment isEqual: @"frag"]) + + TEST(@"-[copy]", R(IRI4 = [[IRI1 copy] autorelease])) + + TEST(@"-[isEqual:]", [IRI1 isEqual: IRI4] && ![IRI2 isEqual: IRI3] && + [[OFIRI IRIWithString: @"HTTP://bar/"] isEqual: IRI3]) + + TEST(@"-[hash:]", IRI1.hash == IRI4.hash && IRI2.hash != IRI3.hash) + + EXPECT_EXCEPTION(@"Detection of invalid format", + OFInvalidFormatException, [OFIRI IRIWithString: @"http"]) + + TEST(@"-[IRIByAddingPercentEncodingForUnicodeCharacters]", + [IRI11.IRIByAddingPercentEncodingForUnicodeCharacters + isEqual: [OFIRI IRIWithString: @"http://%C3%A4/%C3%B6?%C3%BC"]]) + + mutableIRI = [OFMutableIRI IRIWithScheme: @"dummy"]; + + EXPECT_EXCEPTION( + @"-[setPercentEncodedScheme:] with invalid characters fails", + OFInvalidFormatException, mutableIRI.scheme = @"%20") + + TEST(@"-[setHost:]", + (mutableIRI.host = @"ho:st") && + [mutableIRI.percentEncodedHost isEqual: @"ho%3Ast"] && + (mutableIRI.host = @"12:34:ab") && + [mutableIRI.percentEncodedHost isEqual: @"[12:34:ab]"] && + (mutableIRI.host = @"12:34:aB") && + [mutableIRI.percentEncodedHost isEqual: @"[12:34:aB]"] && + (mutableIRI.host = @"12:34:g") && + [mutableIRI.percentEncodedHost isEqual: @"12%3A34%3Ag"]) + + TEST(@"-[setPercentEncodedHost:]", + (mutableIRI.percentEncodedHost = @"ho%3Ast") && + [mutableIRI.host isEqual: @"ho:st"] && + (mutableIRI.percentEncodedHost = @"[12:34]") && + [mutableIRI.host isEqual: @"12:34"] && + (mutableIRI.percentEncodedHost = @"[12::ab]") && + [mutableIRI.host isEqual: @"12::ab"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedHost:] with invalid characters fails #1", + OFInvalidFormatException, + mutableIRI.percentEncodedHost = @"/") + + EXPECT_EXCEPTION( + @"-[setPercentEncodedHost:] with invalid characters fails #2", + OFInvalidFormatException, + mutableIRI.percentEncodedHost = @"[12:34") + + EXPECT_EXCEPTION( + @"-[setPercentEncodedHost:] with invalid characters fails #3", + OFInvalidFormatException, + mutableIRI.percentEncodedHost = @"[a::g]") + + TEST(@"-[setUser:]", + (mutableIRI.user = @"us:er") && + [mutableIRI.percentEncodedUser isEqual: @"us%3Aer"]) + + TEST(@"-[setPercentEncodedUser:]", + (mutableIRI.percentEncodedUser = @"us%3Aer") && + [mutableIRI.user isEqual: @"us:er"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedUser:] with invalid characters fails", + OFInvalidFormatException, + mutableIRI.percentEncodedHost = @"/") + + TEST(@"-[setPassword:]", + (mutableIRI.password = @"pass:word") && + [mutableIRI.percentEncodedPassword isEqual: @"pass%3Aword"]) + + TEST(@"-[setPercentEncodedPassword:]", + (mutableIRI.percentEncodedPassword = @"pass%3Aword") && + [mutableIRI.password isEqual: @"pass:word"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedPassword:] with invalid characters fails", + OFInvalidFormatException, + mutableIRI.percentEncodedPassword = @"/") + + TEST(@"-[setPath:]", + (mutableIRI.path = @"pa/th@?") && + [mutableIRI.percentEncodedPath isEqual: @"pa/th@%3F"]) + + TEST(@"-[setPercentEncodedPath:]", + (mutableIRI.percentEncodedPath = @"pa/th@%3F") && + [mutableIRI.path isEqual: @"pa/th@?"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedPath:] with invalid characters fails", + OFInvalidFormatException, + mutableIRI.percentEncodedPath = @"?") + + TEST(@"-[setQuery:]", + (mutableIRI.query = @"que/ry?#") && + [mutableIRI.percentEncodedQuery isEqual: @"que/ry?%23"]) + + TEST(@"-[setPercentEncodedQuery:]", + (mutableIRI.percentEncodedQuery = @"que/ry?%23") && + [mutableIRI.query isEqual: @"que/ry?#"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedQuery:] with invalid characters fails", + OFInvalidFormatException, + mutableIRI.percentEncodedQuery = @"`") + + TEST(@"-[setQueryItems:]", + (mutableIRI.queryItems = [OFArray arrayWithObjects: + [OFPair pairWithFirstObject: @"foo&bar" secondObject: @"baz=qux"], + [OFPair pairWithFirstObject: @"f=oobar" secondObject: @"b&azqux"], + nil]) && [mutableIRI.percentEncodedQuery isEqual: + @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"]) + + TEST(@"-[setFragment:]", + (mutableIRI.fragment = @"frag/ment?#") && + [mutableIRI.percentEncodedFragment isEqual: @"frag/ment?%23"]) + + TEST(@"-[setPercentEncodedFragment:]", + (mutableIRI.percentEncodedFragment = @"frag/ment?%23") && + [mutableIRI.fragment isEqual: @"frag/ment?#"]) + + EXPECT_EXCEPTION( + @"-[setPercentEncodedFragment:] with invalid characters fails", + OFInvalidFormatException, + mutableIRI.percentEncodedFragment = @"`") + + TEST(@"-[IRIByAppendingPathComponent:isDirectory:]", + [[[OFIRI IRIWithString: @"file:///foo/bar"] + IRIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: + [OFIRI IRIWithString: @"file:///foo/bar/qux"]] && + [[[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: + [OFIRI IRIWithString: @"file:///foo/bar/qux"]] && + [[[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qu?x" isDirectory: false] isEqual: + [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx"]] && + [[[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qu?x" isDirectory: true] isEqual: + [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx/"]]) + + TEST(@"-[IRIByStandardizingPath]", + [[[OFIRI IRIWithString: @"http://foo/bar/.."] + IRIByStandardizingPath] isEqual: + [OFIRI IRIWithString: @"http://foo/"]] && + [[[OFIRI IRIWithString: @"http://foo/bar/%2E%2E/../qux/"] + IRIByStandardizingPath] isEqual: + [OFIRI IRIWithString: @"http://foo/bar/qux/"]] && + [[[OFIRI IRIWithString: @"http://foo/bar/./././qux/./"] + IRIByStandardizingPath] isEqual: + [OFIRI IRIWithString: @"http://foo/bar/qux/"]] && + [[[OFIRI IRIWithString: @"http://foo/bar/../../qux"] + IRIByStandardizingPath] isEqual: + [OFIRI IRIWithString: @"http://foo/../qux"]]) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFKernelEventObserverTests.m ================================================================== --- tests/OFKernelEventObserverTests.m +++ tests/OFKernelEventObserverTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -51,20 +51,21 @@ - (instancetype)initWithTestsAppDelegate: (TestsAppDelegate *)testsAppDelegate { self = [super init]; @try { - uint16_t port; + OFSocketAddress address; _testsAppDelegate = testsAppDelegate; _server = [[OFTCPSocket alloc] init]; - port = [_server bindToHost: @"127.0.0.1" port: 0]; + address = [_server bindToHost: @"127.0.0.1" port: 0]; [_server listen]; _client = [[OFTCPSocket alloc] init]; - [_client connectToHost: @"127.0.0.1" port: port]; + [_client connectToHost: @"127.0.0.1" + port: OFSocketAddressIPPort(&address)]; [_client writeBuffer: "0" length: 1]; } @catch (id e) { [self release]; @throw e; } Index: tests/OFListTests.m ================================================================== --- tests/OFListTests.m +++ tests/OFListTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFLocaleTests.m ================================================================== --- tests/OFLocaleTests.m +++ tests/OFLocaleTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -27,12 +27,12 @@ @implementation TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests { void *pool = objc_autoreleasePoolPush(); OFMD5Hash *MD5, *MD5Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (MD5 = [OFMD5Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { ADDED tests/OFMatrix4x4Tests.m Index: tests/OFMatrix4x4Tests.m ================================================================== --- tests/OFMatrix4x4Tests.m +++ tests/OFMatrix4x4Tests.m @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "TestsAppDelegate.h" + +static OFString *const module = @"OFMatrix4x4Tests"; + +@implementation TestsAppDelegate (OFMatrix4x4Tests) +- (void)matrix4x4Tests +{ + void *pool = objc_autoreleasePoolPush(); + OFMatrix4x4 *matrix, *matrix2; + OFVector4D point; + + TEST(@"+[identityMatrix]", + memcmp([[OFMatrix4x4 identityMatrix] values], (const float [4][4]){ + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }, 16 * sizeof(float)) == 0) + + TEST(@"+[matrixWithValues:]", + (matrix = [OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 1, 2, 3, 4 }, + { 5, 6, 7, 8 }, + { 9, 10, 11, 12 }, + { 13, 14, 15, 16 } + }])) + + TEST(@"-[description]", + [matrix.description isEqual: @""]) + + TEST(@"-[isEqual:]", [[OFMatrix4x4 identityMatrix] isEqual: + [OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }]]) + + TEST(@"-[copy]", (matrix2 = [matrix copy]) && [matrix2 isEqual: matrix]) + + TEST(@"-[multiplyWithMatrix:] #1", + R([matrix2 multiplyWithMatrix: [OFMatrix4x4 identityMatrix]]) && + [matrix2 isEqual: matrix]) + + matrix2 = [OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 100, 200, 300, 400 }, + { 500, 600, 700, 800 }, + { 900, 1000, 1100, 1200 }, + { 1300, 1400, 1500, 1600 } + }]; + TEST(@"-[multiplyWithMatrix:] #2", + R([matrix2 multiplyWithMatrix: matrix]) && + [matrix2 isEqual: + [OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 9000, 10000, 11000, 12000 }, + { 20200, 22800, 25400, 28000 }, + { 31400, 35600, 39800, 44000 }, + { 42600, 48400, 54200, 60000 } + }]]) + + TEST(@"[-translateWithVector:]", + (matrix2 = [OFMatrix4x4 identityMatrix]) && + R([matrix2 translateWithVector: OFMakeVector3D(1, 2, 3)]) && + R(point = + [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && + point.x == 3 && point.y == 5 && point.z == 7 && point.w == 1) + + TEST(@"-[scaleWithVector:]", + R([matrix2 scaleWithVector: OFMakeVector3D(-1, 0.5f, 2)]) && + R(point = + [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && + point.x == -3 && point.y == 2.5 && point.z == 14 && point.w == 1) + + TEST(@"-[transformedVector:]", + R((point = + [matrix transformedVector: OFMakeVector4D(1, 2, 3, 1)])) && + point.x == 18 && point.y == 46 && point.z == 74 && point.w == 102) + + objc_autoreleasePoolPop(pool); +} +@end Index: tests/OFMemoryStreamTests.m ================================================================== --- tests/OFMemoryStreamTests.m +++ tests/OFMemoryStreamTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFMethodSignatureTests.m ================================================================== --- tests/OFMethodSignatureTests.m +++ tests/OFMethodSignatureTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFNotificationCenterTests.m ================================================================== --- tests/OFNotificationCenterTests.m +++ tests/OFNotificationCenterTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -107,11 +107,11 @@ test1->_received == 1 && test2->_received == 3 && test3->_received == 0 && test4->_received == 0) #ifdef OF_HAVE_BLOCKS __block bool received = false; - OFNotificationCenterHandle *handle; + id handle; notification = [OFNotification notificationWithName: notificationName object: self]; TEST(@"-[addObserverForName:object:usingBlock:]", (handle = [center addObserverForName: notificationName Index: tests/OFNumberTests.m ================================================================== --- tests/OFNumberTests.m +++ tests/OFNumberTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFObjectTests.m ================================================================== --- tests/OFObjectTests.m +++ tests/OFObjectTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFPBKDF2Tests.m ================================================================== --- tests/OFPBKDF2Tests.m +++ tests/OFPBKDF2Tests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFPluginTests.m ================================================================== --- tests/OFPluginTests.m +++ tests/OFPluginTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFPropertyListTests.m ================================================================== --- tests/OFPropertyListTests.m +++ tests/OFPropertyListTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -28,12 +28,12 @@ @implementation TestsAppDelegate (OFRIPEMD160HashTests) - (void)RIPEMD160HashTests { void *pool = objc_autoreleasePoolPush(); OFRIPEMD160Hash *RIPEMD160, *RIPEMD160Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (RIPEMD160 = [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -28,12 +28,12 @@ @implementation TestsAppDelegate (SHA1HashTests) - (void)SHA1HashTests { void *pool = objc_autoreleasePoolPush(); OFSHA1Hash *SHA1, *SHA1Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (SHA1 = [OFSHA1Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -28,12 +28,12 @@ @implementation TestsAppDelegate (SHA224HashTests) - (void)SHA224HashTests { void *pool = objc_autoreleasePoolPush(); OFSHA224Hash *SHA224, *SHA224Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (SHA224 = [OFSHA224Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -28,12 +28,12 @@ @implementation TestsAppDelegate (SHA256HashTests) - (void)SHA256HashTests { void *pool = objc_autoreleasePoolPush(); OFSHA256Hash *SHA256, *SHA256Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (SHA256 = [OFSHA256Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -29,12 +29,12 @@ @implementation TestsAppDelegate (SHA384HashTests) - (void)SHA384HashTests { void *pool = objc_autoreleasePoolPush(); OFSHA384Hash *SHA384, *SHA384Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (SHA384 = [OFSHA384Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -30,12 +30,12 @@ @implementation TestsAppDelegate (SHA512HashTests) - (void)SHA512HashTests { void *pool = objc_autoreleasePoolPush(); OFSHA512Hash *SHA512, *SHA512Copy; - OFURI *URI = [OFURI URIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFURIHandler openItemAtURI: URI mode: @"r"]; + OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; TEST(@"+[hashWithAllowsSwappableMemory:]", (SHA512 = [OFSHA512Hash hashWithAllowsSwappableMemory: true])) while (!file.atEndOfStream) { Index: tests/OFSPXSocketTests.m ================================================================== --- tests/OFSPXSocketTests.m +++ tests/OFSPXSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -77,10 +77,11 @@ OFSocketAddress address1; const OFSocketAddress *address2; uint32_t network; unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint16_t port; + OFDictionary *networkInterfaces; char buffer[5]; SPXSocketDelegate *delegate; TEST(@"+[socket]", (sockClient = [OFSPXSocket socket]) && (sockServer = [OFSPXSocket socket])) @@ -121,10 +122,28 @@ network = OFSocketAddressIPXNetwork(&address1); OFSocketAddressGetIPXNode(&address1, node); port = OFSocketAddressIPXPort(&address1); TEST(@"-[listen]", R([sockServer listen])) + + /* + * Find any network interface with IPX and send to it. Any should be + * fine since we bound to 0.0. + */ + networkInterfaces = [OFSystemInfo networkInterfaces]; + for (OFString *name in networkInterfaces) { + OFNetworkInterface interface = [networkInterfaces + objectForKey: name]; + OFData *addresses = [interface + objectForKey: OFNetworkInterfaceIPXAddresses]; + + if (addresses.count == 0) + continue; + + network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]); + OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node); + } TEST(@"-[connectToNetwork:node:port:]", R([sockClient connectToNetwork: network node: node port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) @@ -136,11 +155,10 @@ [sockClient receiveIntoBuffer: buffer length: 5] == 5 && memcmp(buffer, "Hello", 5) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - OFSocketAddressIPXNetwork(address2) == network && R(OFSocketAddressGetIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXSocketDelegate alloc] init] autorelease]; @@ -171,10 +189,17 @@ [OFDate dateWithTimeIntervalSinceNow: 2]]; TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveKernelEventsFailedException *e) { + /* + * Make sure it doesn't stay in the run loop and throws again + * next time we run the run loop. + */ + [sockClient cancelAsyncRequests]; + [sockServer cancelAsyncRequests]; + switch (e.errNo) { case ENOTSOCK: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @"\r[OFSPXSocket] -[asyncAccept] & " Index: tests/OFSPXStreamSocketTests.m ================================================================== --- tests/OFSPXStreamSocketTests.m +++ tests/OFSPXStreamSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -77,10 +77,11 @@ OFSocketAddress address1; const OFSocketAddress *address2; uint32_t network; unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN]; uint16_t port; + OFDictionary *networkInterfaces; char buffer[5]; SPXStreamSocketDelegate *delegate; TEST(@"+[socket]", (sockClient = [OFSPXStreamSocket socket]) && (sockServer = [OFSPXStreamSocket socket])) @@ -122,10 +123,28 @@ network = OFSocketAddressIPXNetwork(&address1); OFSocketAddressGetIPXNode(&address1, node); port = OFSocketAddressIPXPort(&address1); TEST(@"-[listen]", R([sockServer listen])) + + /* + * Find any network interface with IPX and send to it. Any should be + * fine since we bound to 0.0. + */ + networkInterfaces = [OFSystemInfo networkInterfaces]; + for (OFString *name in networkInterfaces) { + OFNetworkInterface interface = [networkInterfaces + objectForKey: name]; + OFData *addresses = [interface + objectForKey: OFNetworkInterfaceIPXAddresses]; + + if (addresses.count == 0) + continue; + + network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]); + OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node); + } TEST(@"-[connectToNetwork:node:port:]", R([sockClient connectToNetwork: network node: node port: port])) TEST(@"-[accept]", (sockAccepted = [sockServer accept])) @@ -140,11 +159,10 @@ [sockClient readIntoBuffer: buffer length: 3] == 3 && memcmp(buffer, "llo", 3) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - OFSocketAddressIPXNetwork(address2) == network && R(OFSocketAddressGetIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease]; @@ -175,10 +193,17 @@ [OFDate dateWithTimeIntervalSinceNow: 2]]; TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]", delegate->_accepted && delegate->_connected) } @catch (OFObserveKernelEventsFailedException *e) { + /* + * Make sure it doesn't stay in the run loop and throws again + * next time we run the run loop. + */ + [sockClient cancelAsyncRequests]; + [sockServer cancelAsyncRequests]; + switch (e.errNo) { case ENOTSOCK: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @"\r[OFSPXStreamSocket] -[asyncAccept] & " Index: tests/OFScryptTests.m ================================================================== --- tests/OFScryptTests.m +++ tests/OFScryptTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED tests/OFSerializationTests.m Index: tests/OFSerializationTests.m ================================================================== --- tests/OFSerializationTests.m +++ tests/OFSerializationTests.m @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSerialization"; - -@implementation TestsAppDelegate (OFSerializationTests) -- (void)serializationTests -{ - void *pool = objc_autoreleasePoolPush(); - OFMutableDictionary *dict = [OFMutableDictionary dictionary]; - OFMutableArray *array = [OFMutableArray array]; - OFList *list = [OFList list]; - OFData *data; - OFString *string; - OFUUID *UUID; - - [array addObject: @"Qu\"xbar\ntest"]; - [array addObject: [OFNumber numberWithInt: 1234]]; - [array addObject: [OFNumber numberWithDouble: 1234.5678]]; - [array addObject: [OFMutableString stringWithString: @"asd"]]; - [array addObject: [OFDate dateWithTimeIntervalSince1970: 1234.5678]]; - - [dict setObject: @"Hello" forKey: array]; - [dict setObject: @"B\"la" forKey: @"Blub"]; - - [list appendObject: @"Hello"]; - [list appendObject: @"Wo\rld!\nHow are you?"]; - [list appendObject: [OFURI URIWithString: @"https://objfw.nil.im/"]]; - [list appendObject: - [OFXMLElement elementWithXMLString: @""]]; - [list appendObject: - [OFSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - [list appendObject: - [OFCountedSet setWithObjects: @"foo", @"foo", @"bar", nil]]; - - [dict setObject: @"list" forKey: list]; - - data = [OFData dataWithItems: "0123456789:; + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFSocketTests.m ================================================================== --- tests/OFSocketTests.m +++ tests/OFSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -119,10 +119,20 @@ R(addr = OFSocketAddressParseIP(@"fd00::1%123", 1234)) && COMPARE_V6(addr, 0xFD00, 0, 0, 0, 0, 0, 0, 1) && OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234 && addr.sockaddr.in6.sin6_scope_id == 123) + TEST(@"Parsing an IPv6 #7", + R(addr = OFSocketAddressParseIP(@"::ffff:127.0.0.1", 1234)) && + COMPARE_V6(addr, 0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 1) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + + TEST(@"Parsing an IPv6 #8", + R(addr = OFSocketAddressParseIP(@"64:ff9b::127.0.0.1", 1234)) && + COMPARE_V6(addr, 0x64, 0xFF9B, 0, 0, 0, 0, 0x7F00, 1) && + OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, OFSocketAddressParseIP(@"1:::2", 1234)) EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, OFSocketAddressParseIP(@"1: ::2", 1234)) Index: tests/OFStreamTests.m ================================================================== --- tests/OFStreamTests.m +++ tests/OFStreamTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -355,12 +355,12 @@ TEST(@"+[stringWithContentsOfFile:encoding]", (string = [stringClass stringWithContentsOfFile: @"testfile.txt" encoding: OFStringEncodingISO8859_1]) && [string isEqual: @"testäöü"]) - TEST(@"+[stringWithContentsOfURI:encoding]", (string = [stringClass - stringWithContentsOfURI: [OFURI fileURIWithPath: @"testfile.txt"] + TEST(@"+[stringWithContentsOfIRI:encoding]", (string = [stringClass + stringWithContentsOfIRI: [OFIRI fileIRIWithPath: @"testfile.txt"] encoding: OFStringEncodingISO8859_1]) && [string isEqual: @"testäöü"]) #endif TEST(@"-[appendUTFString:length:]", @@ -1154,11 +1154,11 @@ # if (!defined(OF_SOLARIS) || !defined(OF_X86)) && !defined(OF_AMIGAOS_M68K) # define INPUT @"\t-0.123456789 " # define EXPECTED -0.123456789 # else /* - * Solaris' strtod() has weird rounding on x86, but not on x86_64. + * Solaris' strtod() has weird rounding on x86, but not on AMD64. * AmigaOS 3 with libnix has weird rounding as well. */ # define INPUT @"\t-0.125 " # define EXPECTED -0.125 # endif Index: tests/OFSystemInfoTests.m ================================================================== --- tests/OFSystemInfoTests.m +++ tests/OFSystemInfoTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -14,15 +14,38 @@ */ #include "config.h" #import "TestsAppDelegate.h" + +#ifdef OF_HAVE_SOCKETS +static void +printAddresses(OFData *addresses, bool *firstAddress) +{ + size_t count = addresses.count; + + for (size_t i = 0; i < count; i++) { + const OFSocketAddress *address = [addresses itemAtIndex: i]; + + if (!*firstAddress) + [OFStdOut writeString: @", "]; + + *firstAddress = false; + + [OFStdOut writeString: OFSocketAddressString(address)]; + } +} +#endif @implementation TestsAppDelegate (OFSystemInfoTests) - (void)systemInfoTests { void *pool = objc_autoreleasePoolPush(); +#ifdef OF_HAVE_SOCKETS + OFDictionary *networkInterfaces; + bool firstInterface = true; +#endif [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeFormat: @"[OFSystemInfo] Page size: %zd\n", [OFSystemInfo pageSize]]; @@ -44,18 +67,18 @@ [OFStdOut writeFormat: @"[OFSystemInfo] Operating system version: %@\n", [OFSystemInfo operatingSystemVersion]]; - [OFStdOut writeFormat: @"[OFSystemInfo] User config URI: %@\n", - [OFSystemInfo userConfigURI].string]; - - [OFStdOut writeFormat: @"[OFSystemInfo] User data URI: %@\n", - [OFSystemInfo userDataURI].string]; - - [OFStdOut writeFormat: @"[OFSystemInfo] Temporary directory URI: %@\n", - [OFSystemInfo temporaryDirectoryURI].string]; + [OFStdOut writeFormat: @"[OFSystemInfo] User config IRI: %@\n", + [OFSystemInfo userConfigIRI].string]; + + [OFStdOut writeFormat: @"[OFSystemInfo] User data IRI: %@\n", + [OFSystemInfo userDataIRI].string]; + + [OFStdOut writeFormat: @"[OFSystemInfo] Temporary directory IRI: %@\n", + [OFSystemInfo temporaryDirectoryIRI].string]; [OFStdOut writeFormat: @"[OFSystemInfo] CPU vendor: %@\n", [OFSystemInfo CPUVendor]]; [OFStdOut writeFormat: @"[OFSystemInfo] CPU model: %@\n", @@ -62,10 +85,16 @@ [OFSystemInfo CPUModel]]; #if defined(OF_X86_64) || defined(OF_X86) [OFStdOut writeFormat: @"[OFSystemInfo] Supports MMX: %d\n", [OFSystemInfo supportsMMX]]; + + [OFStdOut writeFormat: @"[OFSystemInfo] Supports 3DNow!: %d\n", + [OFSystemInfo supports3DNow]]; + + [OFStdOut writeFormat: @"[OFSystemInfo] Supports enhanced 3DNow!: %d\n", + [OFSystemInfo supportsEnhanced3DNow]]; [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE: %d\n", [OFSystemInfo supportsSSE]]; [OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE2: %d\n", @@ -98,9 +127,63 @@ #ifdef OF_POWERPC [OFStdOut writeFormat: @"[OFSystemInfo] Supports AltiVec: %d\n", [OFSystemInfo supportsAltiVec]]; #endif + +#ifdef OF_HAVE_SOCKETS + networkInterfaces = [OFSystemInfo networkInterfaces]; + [OFStdOut writeString: @"[OFSystemInfo] Network interfaces: "]; + for (OFString *name in networkInterfaces) { + bool firstAddress = true; + OFNetworkInterface interface; + OFData *hardwareAddress; + + if (!firstInterface) + [OFStdOut writeString: @"; "]; + + firstInterface = false; + + [OFStdOut writeFormat: @"%@(", name]; + + interface = [networkInterfaces objectForKey: name]; + + printAddresses([interface objectForKey: + OFNetworkInterfaceIPv4Addresses], &firstAddress); +# ifdef OF_HAVE_IPV6 + printAddresses([interface objectForKey: + OFNetworkInterfaceIPv6Addresses], &firstAddress); +# endif +# ifdef OF_HAVE_IPX + printAddresses([interface objectForKey: + OFNetworkInterfaceIPXAddresses], &firstAddress); +# endif +# ifdef OF_HAVE_APPLETALK + printAddresses([interface objectForKey: + OFNetworkInterfaceAppleTalkAddresses], &firstAddress); +# endif + + hardwareAddress = [interface + objectForKey: OFNetworkInterfaceHardwareAddress]; + if (hardwareAddress != nil) { + const unsigned char *bytes = hardwareAddress.items; + size_t length = hardwareAddress.count; + + if (!firstAddress) + [OFStdOut writeString: @", "]; + + for (size_t i = 0; i < length; i++) { + if (i > 0) + [OFStdOut writeString: @":"]; + + [OFStdOut writeFormat: @"%02X", bytes[i]]; + } + } + + [OFStdOut writeString: @")"]; + } + [OFStdOut writeString: @"\n"]; +#endif objc_autoreleasePoolPop(pool); } @end Index: tests/OFTCPSocketTests.m ================================================================== --- tests/OFTCPSocketTests.m +++ tests/OFTCPSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,23 +24,24 @@ @implementation TestsAppDelegate (OFTCPSocketTests) - (void)TCPSocketTests { void *pool = objc_autoreleasePoolPush(); OFTCPSocket *server, *client = nil, *accepted; - uint16_t port; + OFSocketAddress address; char buffer[6]; TEST(@"+[socket]", (server = [OFTCPSocket socket]) && (client = [OFTCPSocket socket])) TEST(@"-[bindToHost:port:]", - (port = [server bindToHost: @"127.0.0.1" port: 0])) + R(address = [server bindToHost: @"127.0.0.1" port: 0])) TEST(@"-[listen]", R([server listen])) TEST(@"-[connectToHost:port:]", - R([client connectToHost: @"127.0.0.1" port: port])) + R([client connectToHost: @"127.0.0.1" + port: OFSocketAddressIPPort(&address)])) TEST(@"-[accept]", (accepted = [server accept])) TEST(@"-[remoteAddress]", [OFSocketAddressString(accepted.remoteAddress) Index: tests/OFThreadTests.m ================================================================== --- tests/OFThreadTests.m +++ tests/OFThreadTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFUDPSocketTests.m ================================================================== --- tests/OFUDPSocketTests.m +++ tests/OFUDPSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -24,36 +24,30 @@ @implementation TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests { void *pool = objc_autoreleasePoolPush(); OFUDPSocket *sock; - uint16_t port1; OFSocketAddress addr1, addr2, addr3; char buf[6]; TEST(@"+[socket]", (sock = [OFUDPSocket socket])) TEST(@"-[bindToHost:port:]", - (port1 = [sock bindToHost: @"127.0.0.1" port: 0])) - - addr1 = OFSocketAddressParseIP(@"127.0.0.1", port1); + R(addr1 = [sock bindToHost: @"127.0.0.1" port: 0])) TEST(@"-[sendBuffer:length:receiver:]", R([sock sendBuffer: "Hello" length: 6 receiver: &addr1])) TEST(@"-[receiveIntoBuffer:length:sender:]", [sock receiveIntoBuffer: buf length: 6 sender: &addr2] == 6 && !memcmp(buf, "Hello", 6) && [OFSocketAddressString(&addr2) isEqual: @"127.0.0.1"] && - OFSocketAddressIPPort(&addr2) == port1) - - addr3 = OFSocketAddressParseIP(@"127.0.0.1", port1 + 1); - - /* - * TODO: Move those tests elsewhere as soon as the DNS resolving part - * is no longer in OFUDPSocket. - */ + OFSocketAddressIPPort(&addr2) == OFSocketAddressIPPort(&addr1)) + + addr3 = OFSocketAddressParseIP(@"127.0.0.1", + OFSocketAddressIPPort(&addr1) + 1); + TEST(@"OFSocketAddressEqual()", OFSocketAddressEqual(&addr1, &addr2) && !OFSocketAddressEqual(&addr1, &addr3)) TEST(@"OFSocketAddressHash()", Index: tests/OFUNIXDatagramSocketTests.m ================================================================== --- tests/OFUNIXDatagramSocketTests.m +++ tests/OFUNIXDatagramSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -29,19 +29,19 @@ OFUNIXDatagramSocket *sock; OFSocketAddress address1, address2; char buffer[5]; #if defined(OF_HAVE_FILES) && !defined(OF_IOS) - path = [[OFSystemInfo temporaryDirectoryURI] - URIByAppendingPathComponent: [[OFUUID UUID] UUIDString]] + path = [[OFSystemInfo temporaryDirectoryIRI] + IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]] .fileSystemRepresentation; #else /* * We can have sockets, including UNIX sockets, while file support is * disabled. * - * We also use this code path for iOS, as the temporaryDirectoryURI is + * We also use this code path for iOS, as the temporaryDirectoryIRI is * too long on the iOS simulator. */ path = [OFString stringWithFormat: @"/tmp/%@", [[OFUUID UUID] UUIDString]]; #endif Index: tests/OFUNIXStreamSocketTests.m ================================================================== --- tests/OFUNIXStreamSocketTests.m +++ tests/OFUNIXStreamSocketTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -28,19 +28,19 @@ OFString *path; OFUNIXStreamSocket *sockClient, *sockServer, *sockAccepted; char buffer[5]; #if defined(OF_HAVE_FILES) && !defined(OF_IOS) - path = [[OFSystemInfo temporaryDirectoryURI] - URIByAppendingPathComponent: [[OFUUID UUID] UUIDString]] + path = [[OFSystemInfo temporaryDirectoryIRI] + IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]] .fileSystemRepresentation; #else /* * We can have sockets, including UNIX sockets, while file support is * disabled. * - * We also use this code path for iOS, as the temporaryDirectoryURI is + * We also use this code path for iOS, as the temporaryDirectory:RI is * too long on the iOS simulator. */ path = [OFString stringWithFormat: @"/tmp/%@", [[OFUUID UUID] UUIDString]]; #endif DELETED tests/OFURITests.m Index: tests/OFURITests.m ================================================================== --- tests/OFURITests.m +++ tests/OFURITests.m @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2008-2022 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFURI"; -static OFString *URIString = @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/" - @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; - -@implementation TestsAppDelegate (OFURITests) -- (void)URITests -{ - void *pool = objc_autoreleasePoolPush(); - OFURI *URI1, *URI2, *URI3, *URI4, *URI5, *URI6, *URI7, *URI8, *URI9; - OFURI *URI10; - OFMutableURI *mutableURI; - - TEST(@"+[URIWithString:]", - R(URI1 = [OFURI URIWithString: URIString]) && - R(URI2 = [OFURI URIWithString: @"http://foo:80"]) && - R(URI3 = [OFURI URIWithString: @"http://bar/"]) && - R(URI4 = [OFURI URIWithString: @"file:///etc/passwd"]) && - R(URI5 = [OFURI URIWithString: @"http://foo/bar/qux/foo%2fbar"]) && - R(URI6 = [OFURI URIWithString: @"https://[12:34::56:abcd]/"]) && - R(URI7 = [OFURI URIWithString: @"https://[12:34::56:abcd]:234/"]) && - R(URI8 = [OFURI URIWithString: @"urn:qux:foo"]) && - R(URI9 = [OFURI URIWithString: @"file:/foo?query#frag"]) && - R(URI10 = [OFURI URIWithString: @"file:foo@bar/qux?query#frag"])) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #1", - OFInvalidFormatException, - [OFURI URIWithString: @"ht,tp://foo"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #2", - OFInvalidFormatException, - [OFURI URIWithString: @"http://f`oo"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #3", - OFInvalidFormatException, - [OFURI URIWithString: @"http://foo/`"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #4", - OFInvalidFormatException, - [OFURI URIWithString: @"http://foo/foo?`"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #5", - OFInvalidFormatException, - [OFURI URIWithString: @"http://foo/foo?foo#`"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #6", - OFInvalidFormatException, - [OFURI URIWithString: @"https://[g]/"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #7", - OFInvalidFormatException, - [OFURI URIWithString: @"https://[f]:/"]) - - EXPECT_EXCEPTION(@"+[URIWithString:] fails with invalid characters #8", - OFInvalidFormatException, - [OFURI URIWithString: @"https://[f]:f/"]) - - TEST(@"+[URIWithString:relativeToURI:]", - [[[OFURI URIWithString: @"/foo" relativeToURI: URI1] string] - isEqual: @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && - [[[OFURI URIWithString: @"foo/bar?q" - relativeToURI: [OFURI URIWithString: @"http://h/qux/quux"]] - string] isEqual: @"http://h/qux/foo/bar?q"] && - [[[OFURI URIWithString: @"foo/bar" - relativeToURI: [OFURI URIWithString: @"http://h/qux/?x"]] - string] isEqual: @"http://h/qux/foo/bar"] && - [[[OFURI URIWithString: @"http://foo/?q" - relativeToURI: URI1] string] isEqual: @"http://foo/?q"] && - [[[OFURI URIWithString: @"foo" - relativeToURI: [OFURI URIWithString: @"http://foo/bar"]] - string] isEqual: @"http://foo/foo"] && - [[[OFURI URIWithString: @"foo" - relativeToURI: [OFURI URIWithString: @"http://foo"]] - string] isEqual: @"http://foo/foo"]) - - EXPECT_EXCEPTION( - @"+[URIWithString:relativeToURI:] fails with invalid characters #1", - OFInvalidFormatException, - [OFURI URIWithString: @"`" relativeToURI: URI1]) - - EXPECT_EXCEPTION( - @"+[URIWithString:relativeToURI:] fails with invalid characters #2", - OFInvalidFormatException, - [OFURI URIWithString: @"/`" relativeToURI: URI1]) - - EXPECT_EXCEPTION( - @"+[URIWithString:relativeToURI:] fails with invalid characters #3", - OFInvalidFormatException, - [OFURI URIWithString: @"?`" relativeToURI: URI1]) - - EXPECT_EXCEPTION( - @"+[URIWithString:relativeToURI:] fails with invalid characters #4", - OFInvalidFormatException, - [OFURI URIWithString: @"#`" relativeToURI: URI1]) - -#ifdef OF_HAVE_FILES - TEST(@"+[fileURIWithPath:]", - [[[OFURI fileURIWithPath: @"testfile.txt"] fileSystemRepresentation] - isEqual: [[OFFileManager defaultManager].currentDirectoryPath - stringByAppendingPathComponent: @"testfile.txt"]]) - -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - OFURI *tmp; - TEST(@"+[fileURIWithPath:] for c:\\", - (tmp = [OFURI fileURIWithPath: @"c:\\"]) && - [tmp.string isEqual: @"file:/c:/"] && - [tmp.fileSystemRepresentation isEqual: @"c:\\"]) -# endif - -# ifdef OF_WINDOWS - TEST(@"+[fileURIWithPath:] with UNC", - (tmp = [OFURI fileURIWithPath: @"\\\\foo\\bar" - isDirectory: false]) && - [tmp.host isEqual: @"foo"] && [tmp.path isEqual: @"/bar"] && - [tmp.string isEqual: @"file://foo/bar"] && - [tmp.fileSystemRepresentation isEqual: @"\\\\foo\\bar"] && - (tmp = [OFURI fileURIWithPath: @"\\\\test" isDirectory: true]) && - [tmp.host isEqual: @"test"] && [tmp.path isEqual: @"/"] && - [tmp.string isEqual: @"file://test/"] && - [tmp.fileSystemRepresentation isEqual: @"\\\\test"]) -# endif -#endif - - TEST(@"-[string]", - [URI1.string isEqual: URIString] && - [URI2.string isEqual: @"http://foo:80"] && - [URI3.string isEqual: @"http://bar/"] && - [URI4.string isEqual: @"file:///etc/passwd"] && - [URI5.string isEqual: @"http://foo/bar/qux/foo%2fbar"] && - [URI6.string isEqual: @"https://[12:34::56:abcd]/"] && - [URI7.string isEqual: @"https://[12:34::56:abcd]:234/"] && - [URI8.string isEqual: @"urn:qux:foo"] && - [URI9.string isEqual: @"file:/foo?query#frag"] && - [URI10.string isEqual: @"file:foo@bar/qux?query#frag"]) - - TEST(@"-[scheme]", - [URI1.scheme isEqual: @"ht+tp"] && [URI4.scheme isEqual: @"file"] && - [URI9.scheme isEqual: @"file"] && [URI10.scheme isEqual: @"file"]) - - TEST(@"-[user]", [URI1.user isEqual: @"us:er"] && URI4.user == nil && - URI10.user == nil) - TEST(@"-[password]", - [URI1.password isEqual: @"p@w"] && URI4.password == nil && - URI10.password == nil) - TEST(@"-[host]", [URI1.host isEqual: @"ho:st"] && - [URI6.host isEqual: @"12:34::56:abcd"] && - [URI7.host isEqual: @"12:34::56:abcd"] && - URI8.host == nil && URI9.host == nil && URI10.host == nil) - TEST(@"-[port]", URI1.port.unsignedShortValue == 1234 && - [URI4 port] == nil && URI7.port.unsignedShortValue == 234 && - URI8.port == nil && URI9.port == nil && URI10.port == nil) - TEST(@"-[path]", - [URI1.path isEqual: @"/pa?th"] && - [URI4.path isEqual: @"/etc/passwd"] && - [URI8.path isEqual: @"qux:foo"] && - [URI9.path isEqual: @"/foo"] && - [URI10.path isEqual: @"foo@bar/qux"]) - TEST(@"-[pathComponents]", - [URI1.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && - [URI4.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil]] && - [URI5.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", nil]]) - TEST(@"-[lastPathComponent]", - [[[OFURI URIWithString: @"http://host/foo//bar/baz"] - lastPathComponent] isEqual: @"baz"] && - [[[OFURI URIWithString: @"http://host/foo//bar/baz/"] - lastPathComponent] isEqual: @"baz"] && - [[[OFURI URIWithString: @"http://host/foo/"] - lastPathComponent] isEqual: @"foo"] && - [[[OFURI URIWithString: @"http://host/"] - lastPathComponent] isEqual: @"/"] && - [URI5.lastPathComponent isEqual: @"foo/bar"]) - TEST(@"-[query]", - [URI1.query isEqual: @"que#ry=1&f&oo=b=ar"] && URI4.query == nil && - [URI9.query isEqual: @"query"] && [URI10.query isEqual: @"query"]) - TEST(@"-[queryItems]", - [URI1.queryItems isEqual: [OFArray arrayWithObjects: - [OFPair pairWithFirstObject: @"que#ry" secondObject: @"1"], - [OFPair pairWithFirstObject: @"f&oo" secondObject: @"b=ar"], nil]]); - TEST(@"-[fragment]", - [URI1.fragment isEqual: @"frag#ment"] && URI4.fragment == nil && - [URI9.fragment isEqual: @"frag"] && - [URI10.fragment isEqual: @"frag"]) - - TEST(@"-[copy]", R(URI4 = [[URI1 copy] autorelease])) - - TEST(@"-[isEqual:]", [URI1 isEqual: URI4] && ![URI2 isEqual: URI3] && - [[OFURI URIWithString: @"HTTP://bar/"] isEqual: URI3]) - - TEST(@"-[hash:]", URI1.hash == URI4.hash && URI2.hash != URI3.hash) - - EXPECT_EXCEPTION(@"Detection of invalid format", - OFInvalidFormatException, [OFURI URIWithString: @"http"]) - - mutableURI = [OFMutableURI URIWithScheme: @"dummy"]; - - EXPECT_EXCEPTION( - @"-[setPercentEncodedScheme:] with invalid characters fails", - OFInvalidFormatException, mutableURI.scheme = @"%20") - - TEST(@"-[setHost:]", - (mutableURI.host = @"ho:st") && - [mutableURI.percentEncodedHost isEqual: @"ho%3Ast"] && - (mutableURI.host = @"12:34:ab") && - [mutableURI.percentEncodedHost isEqual: @"[12:34:ab]"] && - (mutableURI.host = @"12:34:aB") && - [mutableURI.percentEncodedHost isEqual: @"[12:34:aB]"] && - (mutableURI.host = @"12:34:g") && - [mutableURI.percentEncodedHost isEqual: @"12%3A34%3Ag"]) - - TEST(@"-[setPercentEncodedHost:]", - (mutableURI.percentEncodedHost = @"ho%3Ast") && - [mutableURI.host isEqual: @"ho:st"] && - (mutableURI.percentEncodedHost = @"[12:34]") && - [mutableURI.host isEqual: @"12:34"] && - (mutableURI.percentEncodedHost = @"[12::ab]") && - [mutableURI.host isEqual: @"12::ab"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #1", - OFInvalidFormatException, - mutableURI.percentEncodedHost = @"/") - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #2", - OFInvalidFormatException, - mutableURI.percentEncodedHost = @"[12:34") - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #3", - OFInvalidFormatException, - mutableURI.percentEncodedHost = @"[a::g]") - - TEST(@"-[setUser:]", - (mutableURI.user = @"us:er") && - [mutableURI.percentEncodedUser isEqual: @"us%3Aer"]) - - TEST(@"-[setPercentEncodedUser:]", - (mutableURI.percentEncodedUser = @"us%3Aer") && - [mutableURI.user isEqual: @"us:er"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedUser:] with invalid characters fails", - OFInvalidFormatException, - mutableURI.percentEncodedHost = @"/") - - TEST(@"-[setPassword:]", - (mutableURI.password = @"pass:word") && - [mutableURI.percentEncodedPassword isEqual: @"pass%3Aword"]) - - TEST(@"-[setPercentEncodedPassword:]", - (mutableURI.percentEncodedPassword = @"pass%3Aword") && - [mutableURI.password isEqual: @"pass:word"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedPassword:] with invalid characters fails", - OFInvalidFormatException, - mutableURI.percentEncodedPassword = @"/") - - TEST(@"-[setPath:]", - (mutableURI.path = @"pa/th@?") && - [mutableURI.percentEncodedPath isEqual: @"pa/th@%3F"]) - - TEST(@"-[setPercentEncodedPath:]", - (mutableURI.percentEncodedPath = @"pa/th@%3F") && - [mutableURI.path isEqual: @"pa/th@?"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedPath:] with invalid characters fails", - OFInvalidFormatException, - mutableURI.percentEncodedPath = @"?") - - TEST(@"-[setQuery:]", - (mutableURI.query = @"que/ry?#") && - [mutableURI.percentEncodedQuery isEqual: @"que/ry?%23"]) - - TEST(@"-[setPercentEncodedQuery:]", - (mutableURI.percentEncodedQuery = @"que/ry?%23") && - [mutableURI.query isEqual: @"que/ry?#"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedQuery:] with invalid characters fails", - OFInvalidFormatException, - mutableURI.percentEncodedQuery = @"`") - - TEST(@"-[setQueryItems:]", - (mutableURI.queryItems = [OFArray arrayWithObjects: - [OFPair pairWithFirstObject: @"foo&bar" secondObject: @"baz=qux"], - [OFPair pairWithFirstObject: @"f=oobar" secondObject: @"b&azqux"], - nil]) && [mutableURI.percentEncodedQuery isEqual: - @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"]) - - TEST(@"-[setFragment:]", - (mutableURI.fragment = @"frag/ment?#") && - [mutableURI.percentEncodedFragment isEqual: @"frag/ment?%23"]) - - TEST(@"-[setPercentEncodedFragment:]", - (mutableURI.percentEncodedFragment = @"frag/ment?%23") && - [mutableURI.fragment isEqual: @"frag/ment?#"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedFragment:] with invalid characters fails", - OFInvalidFormatException, - mutableURI.percentEncodedFragment = @"`") - - TEST(@"-[URIByAppendingPathComponent:isDirectory:]", - [[[OFURI URIWithString: @"file:///foo/bar"] - URIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: - [OFURI URIWithString: @"file:///foo/bar/qux"]] && - [[[OFURI URIWithString: @"file:///foo/bar/"] - URIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: - [OFURI URIWithString: @"file:///foo/bar/qux"]] && - [[[OFURI URIWithString: @"file:///foo/bar/"] - URIByAppendingPathComponent: @"qu?x" isDirectory: false] isEqual: - [OFURI URIWithString: @"file:///foo/bar/qu%3Fx"]] && - [[[OFURI URIWithString: @"file:///foo/bar/"] - URIByAppendingPathComponent: @"qu?x" isDirectory: true] isEqual: - [OFURI URIWithString: @"file:///foo/bar/qu%3Fx/"]]) - - TEST(@"-[URIByStandardizingPath]", - [[[OFURI URIWithString: @"http://foo/bar/.."] - URIByStandardizingPath] isEqual: - [OFURI URIWithString: @"http://foo/"]] && - [[[OFURI URIWithString: @"http://foo/bar/%2E%2E/../qux/"] - URIByStandardizingPath] isEqual: - [OFURI URIWithString: @"http://foo/bar/qux/"]] && - [[[OFURI URIWithString: @"http://foo/bar/./././qux/./"] - URIByStandardizingPath] isEqual: - [OFURI URIWithString: @"http://foo/bar/qux/"]] && - [[[OFURI URIWithString: @"http://foo/bar/../../qux"] - URIByStandardizingPath] isEqual: - [OFURI URIWithString: @"http://foo/../qux"]]) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/OFValueTests.m ================================================================== --- tests/OFValueTests.m +++ tests/OFValueTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFWindowsRegistryKeyTests.m ================================================================== --- tests/OFWindowsRegistryKeyTests.m +++ tests/OFWindowsRegistryKeyTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFXMLElementBuilderTests.m ================================================================== --- tests/OFXMLElementBuilderTests.m +++ tests/OFXMLElementBuilderTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFXMLNodeTests.m ================================================================== --- tests/OFXMLNodeTests.m +++ tests/OFXMLNodeTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/RuntimeARCTests.m ================================================================== --- tests/RuntimeARCTests.m +++ tests/RuntimeARCTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/RuntimeTests.m ================================================================== --- tests/RuntimeTests.m +++ tests/RuntimeTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -68,10 +68,14 @@ @end @interface TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests; @end + +@interface TestsAppDelegate (OFColorTests) +- (void)colorTests; +@end @interface TestsAppDelegate (OFDDPSocketTests) - (void)DDPSocketTests; @end @@ -108,10 +112,14 @@ @end @interface TestsAppDelegate (OFINIFileTests) - (void)INIFileTests; @end + +@interface TestsAppDelegate (OFIRITests) +- (void)IRITests; +@end @interface TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests; @end @@ -140,10 +148,14 @@ @end @interface TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests; @end + +@interface TestsAppDelegate (OFMatrix4x4Tests) +- (void)matrix4x4Tests; +@end @interface TestsAppDelegate (OFMemoryStreamTests) - (void)memoryStreamTests; @end @@ -217,14 +229,10 @@ @interface TestsAppDelegate (OFSPXStreamSocketTests) - (void)SPXStreamSocketTests; @end -@interface TestsAppDelegate (OFSerializationTests) -- (void)serializationTests; -@end - @interface TestsAppDelegate (OFSetTests) - (void)setTests; @end @interface TestsAppDelegate (OFSystemInfoTests) @@ -261,14 +269,10 @@ @interface TestsAppDelegate (OFUNIXStreamSocketTests) - (void)UNIXStreamSocketTests; @end -@interface TestsAppDelegate (OFURITests) -- (void)URITests; -@end - @interface TestsAppDelegate (OFValueTests) - (void)valueTests; @end @interface TestsAppDelegate (OFWindowsRegistryKeyTests) Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -397,10 +397,11 @@ [self listTests]; [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; + [self colorTests]; [self streamTests]; [self memoryStreamTests]; [self notificationCenterTests]; [self MD5HashTests]; [self RIPEMD160HashTests]; @@ -434,11 +435,11 @@ [self kernelEventObserverTests]; #endif #ifdef OF_HAVE_THREADS [self threadTests]; #endif - [self URITests]; + [self IRITests]; #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) [self HTTPClientTests]; #endif #ifdef OF_HAVE_SOCKETS [self HTTPCookieTests]; @@ -445,13 +446,14 @@ [self HTTPCookieManagerTests]; #endif [self XMLParserTests]; [self XMLNodeTests]; [self XMLElementBuilderTests]; - [self serializationTests]; [self JSONTests]; [self propertyListTests]; + [self matrix4x4Tests]; + #if defined(OF_HAVE_PLUGINS) [self pluginTests]; #endif #ifdef OF_WINDOWS [self windowsRegistryKeyTests]; Index: tests/iOS.xcodeproj/project.pbxproj ================================================================== --- tests/iOS.xcodeproj/project.pbxproj +++ tests/iOS.xcodeproj/project.pbxproj @@ -11,11 +11,10 @@ 4BC7FD07201394F300280496 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; }; 4BC7FD092013954B00280496 /* tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD082013954B00280496 /* tests.a */; }; 4BC7FD0B2013956D00280496 /* ObjFW.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4BC7FD102013960600280496 /* testfile.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0C2013960600280496 /* testfile.txt */; }; 4BC7FD112013960600280496 /* testfile.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0D2013960600280496 /* testfile.bin */; }; - 4BC7FD122013960600280496 /* serialization.xml in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0E2013960600280496 /* serialization.xml */; }; 4BC7FD132013960600280496 /* testfile.ini in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0F2013960600280496 /* testfile.ini */; }; 4BEBFB6E2013934E002E8710 /* ImportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBFB6D2013934E002E8710 /* ImportTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -45,11 +44,10 @@ 4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = TestPlugin.bundle; path = plugin/TestPlugin.bundle; sourceTree = ""; }; 4BC7FD06201394F300280496 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = ../src/ObjFW.framework; sourceTree = ""; }; 4BC7FD082013954B00280496 /* tests.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = tests.a; sourceTree = ""; }; 4BC7FD0C2013960600280496 /* testfile.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.txt; sourceTree = ""; }; 4BC7FD0D2013960600280496 /* testfile.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = testfile.bin; sourceTree = ""; }; - 4BC7FD0E2013960600280496 /* serialization.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = serialization.xml; sourceTree = ""; }; 4BC7FD0F2013960600280496 /* testfile.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.ini; sourceTree = ""; }; 4BEBFB5B2013934E002E8710 /* tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4BEBFB6C2013934E002E8710 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 4BEBFB6D2013934E002E8710 /* ImportTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImportTest.m; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -97,11 +95,10 @@ 4BEBFB5D2013934E002E8710 /* tests */ = { isa = PBXGroup; children = ( 4BEBFB6C2013934E002E8710 /* Info.plist */, 4BEBFB6D2013934E002E8710 /* ImportTest.m */, - 4BC7FD0E2013960600280496 /* serialization.xml */, 4BC7FD0D2013960600280496 /* testfile.bin */, 4BC7FD0F2013960600280496 /* testfile.ini */, 4BC7FD0C2013960600280496 /* testfile.txt */, ); name = tests; @@ -166,11 +163,10 @@ 4BEBFB592013934E002E8710 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 4BC7FD102013960600280496 /* testfile.txt in Resources */, - 4BC7FD122013960600280496 /* serialization.xml in Resources */, 4BC7FD132013960600280496 /* testfile.ini in Resources */, 4BC7FD112013960600280496 /* testfile.bin in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -307,11 +303,11 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -327,11 +323,11 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", ); - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; Index: tests/objc_sync/test.m ================================================================== --- tests/objc_sync/test.m +++ tests/objc_sync/test.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/plugin/TestPlugin.h ================================================================== --- tests/plugin/TestPlugin.h +++ tests/plugin/TestPlugin.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: tests/plugin/TestPlugin.m ================================================================== --- tests/plugin/TestPlugin.m +++ tests/plugin/TestPlugin.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in DELETED tests/serialization.xml Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -1,67 +0,0 @@ - - - - - 01234567-89ab-cdef-fedc-ba9876543210 - - - uuid - - - Blub - - - B"la - - - - Hello - Wo ld! -How are you? - https://objfw.nil.im/ - - - - - - - - - - bar - foo - - - - bar - - - foo - - - - - - list - - - MDEyMzQ1Njc4OTo7PEFCQ0RFRkdISklLTE1OT1BRUlNUVVZXWFla - - - data - - - - Qu"xbar -test - 1234 - 40934a456d5cfaad - asd - 40934a456d5cfaad - - - - Hello - - - Index: tests/terminal/TerminalTests.m ================================================================== --- tests/terminal/TerminalTests.m +++ tests/terminal/TerminalTests.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/Makefile ================================================================== --- utils/Makefile +++ utils/Makefile @@ -1,13 +1,12 @@ include ../extra.mk -SUBDIRS += ${OBJFW_NEW} \ - ${OFARC} \ - ${OFDNS} \ - ${OFHASH} \ - ${OFHTTP} \ - completions +SUBDIRS += ${OBJFW_NEW} \ + ${OFARC} \ + ${OFDNS} \ + ${OFHASH} \ + ${OFHTTP} include ../buildsys.mk DISTCLEAN = objfw-config DELETED utils/completions/Makefile Index: utils/completions/Makefile ================================================================== --- utils/completions/Makefile +++ utils/completions/Makefile @@ -1,5 +0,0 @@ -include ../../extra.mk - -SUBDIRS = ${FISH_COMPLETIONS} - -include ../../buildsys.mk DELETED utils/completions/fish/Makefile Index: utils/completions/fish/Makefile ================================================================== --- utils/completions/fish/Makefile +++ utils/completions/fish/Makefile @@ -1,10 +0,0 @@ -DATA = objfw-compile.fish \ - objfw-config.fish \ - ofarc.fish \ - ofdns.fish \ - ofhash.fish \ - ofhttp.fish - -include ../../../buildsys.mk - -PACKAGE_NAME = fish/vendor_completions.d DELETED utils/completions/fish/objfw-compile.fish Index: utils/completions/fish/objfw-compile.fish ================================================================== --- utils/completions/fish/objfw-compile.fish +++ utils/completions/fish/objfw-compile.fish @@ -1,28 +0,0 @@ -complete -c objfw-compile -s o -x -d 'Specify the output name (not file name!)' -complete -c objfw-compile -l arc -d 'Use automatic reference counting' -complete -c objfw-compile -l lib -x -d \ - 'Compile a library (with the specified version) instead of an application' -complete -c objfw-compile -l plugin \ - -d 'Compile a plugin instead of an application' -complete -c objfw-compile -l package -x -d 'Use the specified package' -complete -c objfw-compile -l builddir -r \ - -d 'Place built objects into the specified directory' -complete -c objfw-compile -s D -x -d 'Pass the specified define to the compiler' -complete -c objfw-compile -o framework -x \ - -d 'Pass the specified -framework argument to the linker (macOS / iOS only)' -# -f* cannot be represented. -complete -c objfw-compile -s F -x \ - -d 'Pass the specified -F flag to the linker (macOS / iOS only)' -# -g* cannot be represented. -complete -c objfw-compile -s I -x \ - -d 'Pass the specified -I flag to the compiler' -complete -c objfw-compile -s l -x -d 'Pass the specified -l flag to the linker' -complete -c objfw-compile -s L -x -d 'Pass the specified -L flag to the linker' -# -m* cannot be represented. -# -O* cannot be represented. -complete -c objfw-compile -o pthread \ - -d 'Pass -pthread to the compiler and linker' -# -std=* cannot be represented. -# -Wl,* cannot be represented. -# -W* cannot be represented. -complete -c objfw-compile -l help -d 'Show this help' DELETED utils/completions/fish/objfw-config.fish Index: utils/completions/fish/objfw-config.fish ================================================================== --- utils/completions/fish/objfw-config.fish +++ utils/completions/fish/objfw-config.fish @@ -1,33 +0,0 @@ -complete -c objfw-config -l all -d 'Outputs all flags + libs' -complete -c objfw-config -l arc -d 'Outputs the required OBJCFLAGS to use ARC' -complete -c objfw-config -l cflags -d 'Outputs the required CFLAGS' -complete -c objfw-config -l cppflags -d 'Outputs the required CPPFLAGS' -complete -c objfw-config -l cxxflags -d 'Outputs the required CXXFLAGS' -complete -c objfw-config -l framework-libs \ - -d 'Outputs the required LIBS, preferring frameworks' -complete -c objfw-config -l help -d 'Print help' -complete -c objfw-config -l ldflags -d 'Outputs the required LDFLAGS' -complete -c objfw-config -l libs -d 'Outputs the required LIBS' -complete -c objfw-config -l lib-cflags \ - -d 'Outputs CFLAGS for building a library' -complete -c objfw-config -l lib-ldflags \ - -d 'Outputs LDFLAGS for building a library' -complete -c objfw-config -l lib-prefix -d 'Outputs the prefix for libraries' -complete -c objfw-config -l lib-suffix -d 'Outputs the suffix for libraries' -complete -c objfw-config -l objc -d 'Outputs the OBJC used to compile ObjFW' -complete -c objfw-config -l objcflags -d 'Outputs the required OBJCFLAGS' -complete -c objfw-config -l package -x \ - -d 'Additionally outputs the flags for the specified package' -complete -c objfw-config -l packages-dir \ - -d 'Outputs the directory where flags for packages are stored' -complete -c objfw-config -l plugin-cflags \ - -d 'Outputs CFLAGS for building a plugin' -complete -c objfw-config -l plugin-ldflags \ - -d 'Outputs LDFLAGS for building a plugin' -complete -c objfw-config -l plugin-suffix -d 'Outputs the suffix for plugins' -complete -c objfw-config -l prog-suffix -d 'Outputs the suffix for binaries' -complete -c objfw-config -l reexport -d 'Outputs LDFLAGS to reexport ObjFW' -complete -c objfw-config -l rpath -d 'Outputs LDFLAGS for using rpath' -complete -c objfw-config -l static-libs \ - -d 'Outputs the required LIBS to link ObjFW statically' -complete -c objfw-config -l version -d 'Outputs the installed version' DELETED utils/completions/fish/ofarc.fish Index: utils/completions/fish/ofarc.fish ================================================================== --- utils/completions/fish/ofarc.fish +++ utils/completions/fish/ofarc.fish @@ -1,14 +0,0 @@ -complete -c ofarc -s a -l append -d 'Append to archive' -complete -c ofarc -s c -l create -d 'Create archive' -complete -c ofarc -s C -l directory -r -d 'Extract into the specified directory' -complete -c ofarc -s E -l encoding -x \ - -d 'The encoding used by the archive (only tar files)' -complete -c ofarc -s f -l force -d 'Force / overwrite files' -complete -c ofarc -s h -l help -d 'Show help' -complete -c ofarc -s l -l list -d 'List all files in the archive' -complete -c ofarc -s n -l no-clobber -d 'Never overwrite files' -complete -c ofarc -s p -l print -d 'Print one or more files from the archive' -complete -c ofarc -s q -l quiet -d 'Quiet mode (no output, except errors)' -complete -c ofarc -s t -l type -x -a 'gz lha tar tgz zip' -d 'Archive type' -complete -c ofarc -s v -l verbose -d 'Verbose output for file list' -complete -c ofarc -s x -l extract -d 'Extract files' DELETED utils/completions/fish/ofdns.fish Index: utils/completions/fish/ofdns.fish ================================================================== --- utils/completions/fish/ofdns.fish +++ utils/completions/fish/ofdns.fish @@ -1,5 +0,0 @@ -complete -c ofdns -s c -l class -x -d 'The DNS class to query (defaults to IN)' -complete -c ofdns -s h -l help -d 'Show help' -complete -c ofdns -s s -l server -x -d 'The server to query' -complete -c ofdns -s t -l type -x \ - -d 'The record type to query (defaults to ALL, can be repeated)' DELETED utils/completions/fish/ofhash.fish Index: utils/completions/fish/ofhash.fish ================================================================== --- utils/completions/fish/ofhash.fish +++ utils/completions/fish/ofhash.fish @@ -1,7 +0,0 @@ -complete -c ofhash --long-option md5 -complete -c ofhash --long-option ripemd160 -complete -c ofhash --long-option sha1 -complete -c ofhash --long-option sha224 -complete -c ofhash --long-option sha256 -complete -c ofhash --long-option sha384 -complete -c ofhash --long-option sha256 DELETED utils/completions/fish/ofhttp.fish Index: utils/completions/fish/ofhttp.fish ================================================================== --- utils/completions/fish/ofhttp.fish +++ utils/completions/fish/ofhttp.fish @@ -1,15 +0,0 @@ -complete -c ofhttp -x -complete -c ofhttp -s b -l body -r -d 'Specify the file to send as body' -complete -c ofhttp -s c -l continue -d 'Continue download of existing file' -complete -c ofhttp -s f -l force -d 'Force / overwrite existing file' -complete -c ofhttp -s h -l help -d 'Show help' -complete -c ofhttp -s H -l header -x -d 'Add a header (e.g. X-Foo:Bar)' -complete -c ofhttp -s m -l method -x -d 'Set the method of the HTTP request' -complete -c ofhttp -s o -l output -r -d 'Specify output file name' -complete -c ofhttp -s O -l detect-filename \ - -d 'Do a HEAD request to detect the file name' -complete -c ofhttp -s P -l proxy -x -d 'Specify SOCKS5 proxy' -complete -c ofhttp -s q -l quiet -d 'Quiet mode (no output, except errors)' -complete -c ofhttp -s v -l verbose -d 'Verbose mode (print headers)' -complete -c ofhttp -l insecure \ - -d 'Ignore TLS errors and allow insecure redirects' Index: utils/objfw-compile ================================================================== --- utils/objfw-compile +++ utils/objfw-compile @@ -1,8 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008-2022 Jonathan Schleifer +# Copyright (c) 2008-2023 Jonathan Schleifer # # All rights reserved. # # This file is part of ObjFW. It may be distributed under the terms of the # Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-config.in ================================================================== --- utils/objfw-config.in +++ utils/objfw-config.in @@ -1,8 +1,8 @@ #!/bin/sh # -# Copyright (c) 2008-2022 Jonathan Schleifer +# Copyright (c) 2008-2023 Jonathan Schleifer # # All rights reserved. # # This file is part of ObjFW. It may be distributed under the terms of the # Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-embed ================================================================== --- utils/objfw-embed +++ utils/objfw-embed @@ -9,13 +9,13 @@ cat < #include #ifdef OF_COMPILING_OBJFW -# import "OFEmbeddedURIHandler.h" +# import "OFEmbeddedIRIHandler.h" #else -# import +# import #endif static const uint8_t bytes[] = { EOF od -vtx1 $1 | sed -e '/^[^ ][^ ]*$/d;s/ */ /g' -e 's/ $//g;s/^[^ ][^ ]* //' -e 's/ /, 0x/g' -e 's/^/ 0x/' -e 's/$/,/' Index: utils/objfw-new/NewApp.m ================================================================== --- utils/objfw-new/NewApp.m +++ utils/objfw-new/NewApp.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-new/NewClass.m ================================================================== --- utils/objfw-new/NewClass.m +++ utils/objfw-new/NewClass.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-new/ObjFWNew.m ================================================================== --- utils/objfw-new/ObjFWNew.m +++ utils/objfw-new/ObjFWNew.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-new/Property.h ================================================================== --- utils/objfw-new/Property.h +++ utils/objfw-new/Property.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/objfw-new/Property.m ================================================================== --- utils/objfw-new/Property.m +++ utils/objfw-new/Property.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/Archive.h ================================================================== --- utils/ofarc/Archive.h +++ utils/ofarc/Archive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/GZIPArchive.h ================================================================== --- utils/ofarc/GZIPArchive.h +++ utils/ofarc/GZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/GZIPArchive.m ================================================================== --- utils/ofarc/GZIPArchive.m +++ utils/ofarc/GZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/LHAArchive.h ================================================================== --- utils/ofarc/LHAArchive.h +++ utils/ofarc/LHAArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFApplication.h" #import "OFDate.h" #import "OFFileManager.h" #import "OFLocale.h" @@ -24,10 +26,12 @@ #import "OFStdIOStream.h" #import "OFString.h" #import "LHAArchive.h" #import "OFArc.h" + +#import "OFSetItemAttributesFailedException.h" static OFArc *app; static OFString * indent(OFString *string) @@ -61,12 +65,17 @@ setModificationDate(OFString *path, OFLHAArchiveEntry *entry) { OFFileAttributes attributes = [OFDictionary dictionaryWithObject: entry.modificationDate forKey: OFFileModificationDate]; - [[OFFileManager defaultManager] setAttributes: attributes - ofItemAtPath: path]; + @try { + [[OFFileManager defaultManager] setAttributes: attributes + ofItemAtPath: path]; + } @catch (OFSetItemAttributesFailedException *e) { + if (e.errNo != EISDIR) + @throw e; + } } @implementation LHAArchive + (void)initialize { Index: utils/ofarc/OFArc.h ================================================================== --- utils/ofarc/OFArc.h +++ utils/ofarc/OFArc.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -19,15 +19,15 @@ #import "OFApplication.h" #import "OFArray.h" #import "OFFile.h" #import "OFFileManager.h" +#import "OFIRI.h" #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFSandbox.h" #import "OFStdIOStream.h" -#import "OFURI.h" #import "OFArc.h" #import "GZIPArchive.h" #import "LHAArchive.h" #import "TarArchive.h" @@ -205,14 +205,15 @@ [OFApplication of_activateSandbox: sandbox]; #endif #ifndef OF_AMIGAOS - [OFLocale addLocalizationDirectory: @LOCALIZATION_DIR]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @LOCALIZATION_DIR]]; #else - [OFLocale addLocalizationDirectory: - @"PROGDIR:/share/ofarc/localization"]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @"PROGDIR:/share/ofarc/localization"]]; #endif optionsParser = [OFOptionsParser parserWithOptions: options]; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { @@ -460,11 +461,11 @@ encoding: [OFLocale encoding]]; [OFStdErr writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_create_directory", @"Failed to create directory %[dir]: %[error]", - @"dir", e.URI.fileSystemRepresentation, + @"dir", e.IRI.fileSystemRepresentation, @"error", error)]; _exitStatus = 1; } @catch (OFOpenItemFailedException *e) { OFString *error = [OFString stringWithCString: strerror(e.errNo) Index: utils/ofarc/TarArchive.h ================================================================== --- utils/ofarc/TarArchive.h +++ utils/ofarc/TarArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -12,10 +12,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFApplication.h" #import "OFDate.h" #import "OFFileManager.h" #import "OFLocale.h" @@ -24,10 +26,12 @@ #import "OFStdIOStream.h" #import "OFString.h" #import "TarArchive.h" #import "OFArc.h" + +#import "OFSetItemAttributesFailedException.h" static OFArc *app; static void setPermissions(OFString *path, OFTarArchiveEntry *entry) @@ -54,12 +58,17 @@ return; attributes = [OFDictionary dictionaryWithObject: modificationDate forKey: OFFileModificationDate]; - [[OFFileManager defaultManager] setAttributes: attributes - ofItemAtPath: path]; + @try { + [[OFFileManager defaultManager] setAttributes: attributes + ofItemAtPath: path]; + } @catch (OFSetItemAttributesFailedException *e) { + if (e.errNo != EISDIR) + @throw e; + } } @implementation TarArchive + (void)initialize { Index: utils/ofarc/ZIPArchive.h ================================================================== --- utils/ofarc/ZIPArchive.h +++ utils/ofarc/ZIPArchive.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofarc/ZIPArchive.m ================================================================== --- utils/ofarc/ZIPArchive.m +++ utils/ofarc/ZIPArchive.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -31,10 +31,11 @@ #import "OFArc.h" #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" +#import "OFSetItemAttributesFailedException.h" static OFArc *app; static void setPermissions(OFString *path, OFZIPArchiveEntry *entry) @@ -64,12 +65,17 @@ return; attributes = [OFDictionary dictionaryWithObject: modificationDate forKey: OFFileModificationDate]; - [[OFFileManager defaultManager] setAttributes: attributes - ofItemAtPath: path]; + @try { + [[OFFileManager defaultManager] setAttributes: attributes + ofItemAtPath: path]; + } @catch (OFSetItemAttributesFailedException *e) { + if (e.errNo != EISDIR) + @throw e; + } } @implementation ZIPArchive + (void)initialize { Index: utils/ofdns/OFDNS.m ================================================================== --- utils/ofdns/OFDNS.m +++ utils/ofdns/OFDNS.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,10 +16,11 @@ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFDNSResolver.h" +#import "OFIRI.h" #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFSandbox.h" #import "OFStdIOStream.h" @@ -50,11 +51,13 @@ @" Show this help\n " @"-s --server" @" The server to query\n " @"-t --type " @" The record type to query (defaults to ALL, can be " - @"repeated)")]; + @"repeated)\n " + @" --tcp " + @" Force using TCP for the query")]; } [OFApplication terminateWithStatus: status]; } @@ -81,15 +84,17 @@ } - (void)applicationDidFinishLaunching: (OFNotification *)notification { OFString *DNSClassString, *server; + bool forceTCP; const OFOptionsParserOption options[] = { { 'c', @"class", 1, NULL, &DNSClassString }, { 'h', @"help", 0, NULL, NULL }, { 's', @"server", 1, NULL, &server }, { 't', @"type", 1, NULL, NULL }, + { '\0', @"tcp", 0, &forceTCP, NULL }, { '\0', nil, 0, NULL, NULL } }; OFMutableArray OF_GENERIC(OFString *) *recordTypes; OFOptionsParser *optionsParser; OFUnichar option; @@ -97,14 +102,15 @@ OFDNSResolver *resolver; OFDNSClass DNSClass; #ifdef OF_HAVE_FILES # ifndef OF_AMIGAOS - [OFLocale addLocalizationDirectory: @LOCALIZATION_DIR]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @LOCALIZATION_DIR]]; # else - [OFLocale addLocalizationDirectory: - @"PROGDIR:/share/ofdns/localization"]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @"PROGDIR:/share/ofdns/localization"]]; # endif #endif #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [[OFSandbox alloc] init]; @@ -178,20 +184,21 @@ if (remainingArguments.count < 1) help(OFStdErr, false, 1); resolver = [OFDNSResolver resolver]; + resolver.configReloadInterval = 0; + resolver.forcesTCP = forceTCP; + DNSClass = (DNSClassString != nil ? OFDNSClassParseName(DNSClassString) : OFDNSClassIN); if (recordTypes.count == 0) [recordTypes addObject: @"ALL"]; - if (server != nil) { - resolver.configReloadInterval = 0; + if (server != nil) resolver.nameServers = [OFArray arrayWithObject: server]; - } for (OFString *domainName in remainingArguments) { for (OFString *recordTypeString in recordTypes) { OFDNSRecordType recordType = OFDNSRecordTypeParseName(recordTypeString); Index: utils/ofdns/localization/de.json ================================================================== --- utils/ofdns/localization/de.json +++ utils/ofdns/localization/de.json @@ -4,15 +4,16 @@ "Optionen:\n", " -c --class Die anzufragende DNS-Klasse (standardmäßig IN)\n", " -h --help Diese Hilfe anzeigen\n", " -s --server Der abzufragende Server\n", " -t --type Der anzufragende Record-Typ (standardmäßig ALL,\n", - " kann wiederholt werden)" + " kann wiederholt werden)\n", + " --tcp Benutzung von TCP erzwingen" ], "long_option_requires_argument": [ "%[prog]: Option --%[opt] benötigt ein Argument" ], "option_requires_argument": "%[prog]: Option -%[opt] benötigt ein Argument", "unknown_long_option": "%[prog]: Unbekannte Option: --%[opt]", "unknown_option": "%[prog]: Unbekannte Option: -%[opt]", "failed_to_resolve": "Auflösen fehlgeschlagen: %[exception]" } Index: utils/ofhash/OFHash.m ================================================================== --- utils/ofhash/OFHash.m +++ utils/ofhash/OFHash.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,10 +16,11 @@ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFFile.h" +#import "OFIRI.h" #import "OFLocale.h" #import "OFMD5Hash.h" #import "OFOptionsParser.h" #import "OFRIPEMD160Hash.h" #import "OFSHA1Hash.h" @@ -93,14 +94,15 @@ OFSHA256Hash *SHA256Hash = nil; OFSHA384Hash *SHA384Hash = nil; OFSHA512Hash *SHA512Hash = nil; #ifndef OF_AMIGAOS - [OFLocale addLocalizationDirectory: @LOCALIZATION_DIR]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @LOCALIZATION_DIR]]; #else - [OFLocale addLocalizationDirectory: - @"PROGDIR:/share/ofhash/localization"]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @"PROGDIR:/share/ofhash/localization"]]; #endif while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case '?': @@ -110,11 +112,11 @@ @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString stringWithFormat: - @"%c", optionsParser.lastOption]; + @"%C", optionsParser.lastOption]; [OFStdErr writeLine: OF_LOCALIZED(@"unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @"opt", optStr)]; Index: utils/ofhttp/OFHTTP.m ================================================================== --- utils/ofhttp/OFHTTP.m +++ utils/ofhttp/OFHTTP.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in @@ -16,16 +16,18 @@ #include "config.h" #import "OFApplication.h" #import "OFArray.h" #import "OFData.h" +#import "OFDate.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFFileManager.h" #import "OFHTTPClient.h" #import "OFHTTPRequest.h" #import "OFHTTPResponse.h" +#import "OFIRI.h" #import "OFLocale.h" #import "OFOptionsParser.h" #ifdef OF_HAVE_PLUGINS # import "OFPlugin.h" #endif @@ -32,11 +34,10 @@ #import "OFSandbox.h" #import "OFStdIOStream.h" #import "OFSystemInfo.h" #import "OFTCPSocket.h" #import "OFTLSStream.h" -#import "OFURI.h" #ifdef HAVE_TLS_SUPPORT # import "ObjFWTLS.h" #endif @@ -48,10 +49,11 @@ #import "OFInvalidServerResponseException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFResolveHostFailedException.h" +#import "OFSetItemAttributesFailedException.h" #import "OFUnsupportedProtocolException.h" #import "OFWriteFailedException.h" #import "ProgressBar.h" @@ -60,12 +62,12 @@ #define KIBIBYTE (1024) @interface OFHTTP: OFObject { - OFArray OF_GENERIC(OFString *) *_URIs; - size_t _URIIndex; + OFArray OF_GENERIC(OFString *) *_IRIs; + size_t _IRIIndex; int _errorCode; OFString *_outputPath, *_currentFileName; bool _continue, _force, _detectFileName, _detectFileNameRequest; bool _detectedFileName, _quiet, _verbose, _insecure, _ignoreStatus; bool _useUnicode; @@ -77,11 +79,11 @@ OFStream *_output; unsigned long long _received, _length, _resumedFrom; ProgressBar *_progressBar; } -- (void)downloadNextURI; +- (void)downloadNextIRI; @end #ifdef HAVE_TLS_SUPPORT void _reference_to_ObjFWTLS(void) @@ -95,11 +97,11 @@ static void help(OFStream *stream, bool full, int status) { [OFStdErr writeLine: OF_LOCALIZED(@"usage", - @"Usage: %[prog] -[cehHmoOPqv] uri1 [uri2 ...]", + @"Usage: %[prog] -[cehHmoOPqv] iri1 [iri2 ...]", @"prog", [OFApplication programName])]; if (full) { [stream writeString: @"\n"]; [stream writeLine: OF_LOCALIZED(@"full_usage", @@ -449,14 +451,15 @@ [OFApplication of_activateSandbox: sandbox]; #endif #ifndef OF_AMIGAOS - [OFLocale addLocalizationDirectory: @LOCALIZATION_DIR]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @LOCALIZATION_DIR]]; #else - [OFLocale addLocalizationDirectory: - @"PROGDIR:/share/ofhttp/localization"]; + [OFLocale addLocalizationDirectoryIRI: + [OFIRI fileIRIWithPath: @"PROGDIR:/share/ofhttp/localization"]]; #endif optionsParser = [OFOptionsParser parserWithOptions: options]; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { @@ -483,11 +486,11 @@ @"missing" @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString - stringWithFormat: @"%c", + stringWithFormat: @"%C", optionsParser.lastOption]; [OFStdErr writeLine: OF_LOCALIZED(@"argument_missing", @"%[prog]: Argument for option -%[opt] " @"missing", @@ -513,11 +516,11 @@ @"%[prog]: Unknown option: --%[opt]", @"prog", [OFApplication programName], @"opt", optionsParser.lastLongOption)]; else { OFString *optStr = [OFString - stringWithFormat: @"%c", + stringWithFormat: @"%C", optionsParser.lastOption]; [OFStdErr writeLine: OF_LOCALIZED(@"unknown_option", @"%[prog]: Unknown option: -%[opt]", @"prog", [OFApplication programName], @@ -544,13 +547,13 @@ sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif _outputPath = [outputPath copy]; - _URIs = [optionsParser.remainingArguments copy]; + _IRIs = [optionsParser.remainingArguments copy]; - if (_URIs.count < 1) + if (_IRIs.count < 1) help(OFStdErr, false, 1); if (_quiet && _verbose) { [OFStdErr writeLine: OF_LOCALIZED(@"quiet_xor_verbose", @"%[prog]: -q / --quiet and -v / --verbose are mutually " @@ -566,14 +569,14 @@ @"mutually exclusive!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } - if (_outputPath != nil && _URIs.count > 1) { + if (_outputPath != nil && _IRIs.count > 1) { [OFStdErr writeLine: - OF_LOCALIZED(@"output_only_with_one_uri", - @"%[prog]: Cannot use -o / --output when more than one URI " + OF_LOCALIZED(@"output_only_with_one_iri", + @"%[prog]: Cannot use -o / --output when more than one IRI " @"has been specified!", @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } @@ -584,11 +587,11 @@ _useUnicode = [OFSystemInfo isWindowsNT]; #else _useUnicode = ([OFLocale encoding] == OFStringEncodingUTF8); #endif - [self performSelector: @selector(downloadNextURI) afterDelay: 0]; + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; } - (void)client: (OFHTTPClient *)client didCreateTLSStream: (OFTLSStream *)stream request: (OFHTTPRequest *)request @@ -608,11 +611,11 @@ [body writeBuffer: buffer length: length]; } } - (bool)client: (OFHTTPClient *)client - shouldFollowRedirectToURI: (OFURI *)URI + shouldFollowRedirectToIRI: (OFIRI *)IRI statusCode: (short)statusCode request: (OFHTTPRequest *)request response: (OFHTTPResponse *)response { if (_verbose) { @@ -630,13 +633,13 @@ objc_autoreleasePoolPop(pool); } if (!_quiet) { if (_useUnicode) - [OFStdOut writeFormat: @"☇ %@", URI.string]; + [OFStdOut writeFormat: @"☇ %@", IRI.string]; else - [OFStdOut writeFormat: @"< %@", URI.string]; + [OFStdOut writeFormat: @"< %@", IRI.string]; } _length = 0; return true; @@ -646,11 +649,11 @@ didReadIntoBuffer: (void *)buffer length: (size_t)length exception: (id)exception { if (exception != nil) { - OFString *URI; + OFString *IRI; [_progressBar stop]; [_progressBar draw]; [_progressBar release]; _progressBar = nil; @@ -659,21 +662,21 @@ [OFStdOut writeString: @"\n "]; [OFStdOut writeLine: OF_LOCALIZED(@"download_error", @"Error!")]; } - URI = [_URIs objectAtIndex: _URIIndex - 1]; + IRI = [_IRIs objectAtIndex: _IRIIndex - 1]; [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_exception", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" %[exception]", @"prog", [OFApplication programName], - @"uri", URI, + @"iri", IRI, @"exception", exception)]; _errorCode = 1; - [self performSelector: @selector(downloadNextURI) + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; return false; } [_output writeBuffer: buffer length: length]; @@ -691,11 +694,11 @@ [OFStdOut writeString: @"\n "]; [OFStdOut writeLine: OF_LOCALIZED(@"download_done", @"Done!")]; } - [self performSelector: @selector(downloadNextURI) + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; return false; } return true; @@ -815,38 +818,38 @@ if (!_quiet) [OFStdOut writeString: @"\n"]; [OFStdErr writeLine: OF_LOCALIZED(@"download_resolve_host_failed", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" Failed to resolve host: %[exception]", @"prog", [OFApplication programName], - @"uri", request.URI.string, + @"iri", request.IRI.string, @"exception", exception)]; } else if ([exception isKindOfClass: [OFConnectSocketFailedException class]]) { if (!_quiet) [OFStdOut writeString: @"\n"]; [OFStdErr writeLine: OF_LOCALIZED(@"download_failed_connection_failed", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" Connection failed: %[exception]", @"prog", [OFApplication programName], - @"uri", request.URI.string, + @"iri", request.IRI.string, @"exception", exception)]; } else if ([exception isKindOfClass: [OFInvalidServerResponseException class]]) { if (!_quiet) [OFStdOut writeString: @"\n"]; [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_invalid_server_response", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" Invalid server response!", @"prog", [OFApplication programName], - @"uri", request.URI.string)]; + @"iri", request.IRI.string)]; } else if ([exception isKindOfClass: [OFUnsupportedProtocolException class]]) { if (!_quiet) [OFStdOut writeString: @"\n"]; @@ -879,14 +882,14 @@ @"write", @"Write failed"); [OFStdErr writeLine: OF_LOCALIZED( @"download_failed_read_or_write_failed", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" %[error]: %[exception]", @"prog", [OFApplication programName], - @"uri", request.URI.string, + @"iri", request.IRI.string, @"error", error, @"exception", exception)]; } else if ([exception isKindOfClass: [OFHTTPRequestFailedException class]]) { short statusCode; @@ -899,20 +902,20 @@ statusCode = response.statusCode; codeString = [OFString stringWithFormat: @"%hd %@", statusCode, OFHTTPStatusCodeString(statusCode)]; [OFStdErr writeLine: OF_LOCALIZED(@"download_failed", - @"%[prog]: Failed to download <%[uri]>!\n" + @"%[prog]: Failed to download <%[iri]>!\n" @" HTTP status code: %[code]", @"prog", [OFApplication programName], - @"uri", request.URI.string, + @"iri", request.IRI.string, @"code", codeString)]; } else @throw exception; _errorCode = 1; - [self performSelector: @selector(downloadNextURI) + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; return; } after_exception_handling: @@ -923,14 +926,14 @@ _currentFileName = [fileNameFromContentDisposition( [response.headers objectForKey: @"Content-Disposition"]) copy]; _detectedFileName = true; - /* Handle this URI on the next -[downloadNextURI] call */ - _URIIndex--; + /* Handle this IRI on the next -[downloadNextIRI] call */ + _IRIIndex--; - [self performSelector: @selector(downloadNextURI) + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; return; } if ([_outputPath isEqual: @"-"]) @@ -963,10 +966,43 @@ @"exception", e)]; _errorCode = 1; goto next; } + +#ifdef OF_LINUX + @try { + OFString *IRIString = request.IRI.string; + OFData *downloadedFromData = [OFData + dataWithItems: IRIString.UTF8String + count: IRIString.UTF8StringLength + 1]; + [[OFFileManager defaultManager] + setExtendedAttributeData: downloadedFromData + forName: @"user.ofhttp." + @"downloaded_from" + ofItemAtPath: _currentFileName]; + } @catch (OFSetItemAttributesFailedException *) { + /* Ignore */ + } +#endif + +#ifdef OF_MACOS + @try { + OFString *quarantine = [OFString stringWithFormat: + @"0000;%08" @PRIx64 @";ofhttp;", + (uint64_t)[[OFDate date] timeIntervalSince1970]]; + OFData *quarantineData = [OFData + dataWithItems: quarantine.UTF8String + count: quarantine.UTF8StringLength]; + [[OFFileManager defaultManager] + setExtendedAttributeData: quarantineData + forName: @"com.apple.quarantine" + ofItemAtPath: _currentFileName]; + } @catch (OFSetItemAttributesFailedException *e) { + /* Ignore */ + } +#endif } if (!_quiet) { _progressBar = [[ProgressBar alloc] initWithLength: _length @@ -985,47 +1021,47 @@ next: [_currentFileName release]; _currentFileName = nil; - [self performSelector: @selector(downloadNextURI) afterDelay: 0]; + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; } -- (void)downloadNextURI +- (void)downloadNextIRI { - OFString *URIString = nil; - OFURI *URI; + OFString *IRIString = nil; + OFIRI *IRI; OFMutableDictionary *clientHeaders; OFHTTPRequest *request; _received = _length = _resumedFrom = 0; if (_output != OFStdOut) [_output release]; _output = nil; - if (_URIIndex >= _URIs.count) + if (_IRIIndex >= _IRIs.count) [OFApplication terminateWithStatus: _errorCode]; @try { - URIString = [_URIs objectAtIndex: _URIIndex++]; - URI = [OFURI URIWithString: URIString]; + IRIString = [_IRIs objectAtIndex: _IRIIndex++]; + IRI = [OFIRI IRIWithString: IRIString]; } @catch (OFInvalidFormatException *e) { - [OFStdErr writeLine: OF_LOCALIZED(@"invalid_uri", - @"%[prog]: Invalid URI: <%[uri]>!", + [OFStdErr writeLine: OF_LOCALIZED(@"invalid_iri", + @"%[prog]: Invalid IRI: <%[iri]>!", @"prog", [OFApplication programName], - @"uri", URIString)]; + @"iri", IRIString)]; _errorCode = 1; goto next; } - if (![URI.scheme isEqual: @"http"] && ![URI.scheme isEqual: @"https"]) { + if (![IRI.scheme isEqual: @"http"] && ![IRI.scheme isEqual: @"https"]) { [OFStdErr writeLine: OF_LOCALIZED(@"invalid_scheme", - @"%[prog]: Invalid scheme: <%[uri]>!", + @"%[prog]: Invalid scheme: <%[iri]>!", @"prog", [OFApplication programName], - @"uri", URIString)]; + @"iri", IRIString)]; _errorCode = 1; goto next; } @@ -1032,16 +1068,16 @@ clientHeaders = [[_clientHeaders mutableCopy] autorelease]; if (_detectFileName && !_detectedFileName) { if (!_quiet) { if (_useUnicode) - [OFStdOut writeFormat: @"⠒ %@", URI.string]; + [OFStdOut writeFormat: @"⠒ %@", IRI.string]; else - [OFStdOut writeFormat: @"? %@", URI.string]; + [OFStdOut writeFormat: @"? %@", IRI.string]; } - request = [OFHTTPRequest requestWithURI: URI]; + request = [OFHTTPRequest requestWithIRI: IRI]; request.headers = clientHeaders; request.method = OFHTTPRequestMethodHead; _detectFileNameRequest = true; [_HTTPClient asyncPerformRequest: request]; @@ -1056,11 +1092,11 @@ if (_currentFileName == nil) _currentFileName = [_outputPath copy]; if (_currentFileName == nil) - _currentFileName = [URI.path.lastPathComponent copy]; + _currentFileName = [IRI.path.lastPathComponent copy]; if ([_currentFileName isEqual: @"/"]) { [_currentFileName release]; _currentFileName = nil; } @@ -1087,22 +1123,22 @@ } } if (!_quiet) { if (_useUnicode) - [OFStdOut writeFormat: @"⇣ %@", URI.string]; + [OFStdOut writeFormat: @"⇣ %@", IRI.string]; else - [OFStdOut writeFormat: @"< %@", URI.string]; + [OFStdOut writeFormat: @"< %@", IRI.string]; } - request = [OFHTTPRequest requestWithURI: URI]; + request = [OFHTTPRequest requestWithIRI: IRI]; request.headers = clientHeaders; request.method = _method; _detectFileNameRequest = false; [_HTTPClient asyncPerformRequest: request]; return; next: - [self performSelector: @selector(downloadNextURI) afterDelay: 0]; + [self performSelector: @selector(downloadNextIRI) afterDelay: 0]; } @end Index: utils/ofhttp/ProgressBar.h ================================================================== --- utils/ofhttp/ProgressBar.h +++ utils/ofhttp/ProgressBar.h @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofhttp/ProgressBar.m ================================================================== --- utils/ofhttp/ProgressBar.m +++ utils/ofhttp/ProgressBar.m @@ -1,7 +1,7 @@ /* - * Copyright (c) 2008-2022 Jonathan Schleifer + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in Index: utils/ofhttp/localization/de.json ================================================================== --- utils/ofhttp/localization/de.json +++ utils/ofhttp/localization/de.json @@ -1,7 +1,7 @@ { - "usage": "Benutzung: %[prog] -[cehHmoOPqv] uri1 [uri2 ...]", + "usage": "Benutzung: %[prog] -[cehHmoOPqv] iri1 [iri2 ...]", "full_usage": [ "Optionen:\n", " -b --body Angegebene Datei als Body übergeben\n", " (- für Standard-Eingabe)\n", " -c --continue Download von existierender Datei ", @@ -34,24 +34,24 @@ ], "output_xor_detect_filename": [ "%[prog]: -o / --output und -O / --detect-filename schließen sich ", "gegenseitig aus!" ], - "output_only_with_one_uri": [ - "%[prog]: -o / --output kann nicht mit mehr als einer URI benutzt ", + "output_only_with_one_iri": [ + "%[prog]: -o / --output kann nicht mit mehr als einer IRI benutzt ", "werden!" ], "download_resolve_host_failed": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " Host auflösen fehlgeschlagen: %[exception]" ], "download_failed_connection_failed": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " Verbindung fehlgeschlagen: %[exception]" ], "download_failed_invalid_server_response": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " Ungültige Antwort vom Server!" ], "no_tls_support": [ "%[prog]: Keine TLS-Unterstützung in ObjFW!\n", " Um via HTTPS runterzuladen müssen Sie entweder ObjFW mit TLS-", @@ -62,25 +62,25 @@ ], "download_failed_read_or_write_failed_any": "Lesen oder Schreiben", "download_failed_read_or_write_failed_read": "Lesen", "download_failed_read_or_write_failed_write": "Schreiben", "download_failed_read_or_write_failed": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " %[error]: %[exception]" ], "download_failed": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " HTTP Status-Code: %[code]" ], "download_error": "Fehler!", "download_failed_exception": [ - "%[prog]: Fehler beim Download von <%[uri]>!\n", + "%[prog]: Fehler beim Download von <%[iri]>!\n", " %[exception]" ], "download_done": "Fertig!", - "invalid_uri": "%[prog]: Ungültige URI: <%[uri]>!", - "invalid_scheme": "%[prog]: Ungültiges Schema: <%[uri]>!", + "invalid_iri": "%[prog]: Ungültige IRI: <%[iri]>!", + "invalid_scheme": "%[prog]: Ungültiges Schema: <%[iri]>!", "type_unknown": "unbekannt", "size_gib": "%[num] GiB", "size_mib": "%[num] MiB", "size_kib": "%[num] KiB", "size_bytes": [