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 Index: .github/workflows/amiga-gcc.yml ================================================================== --- .github/workflows/amiga-gcc.yml +++ .github/workflows/amiga-gcc.yml @@ -1,37 +1,16 @@ name: amiga-gcc on: [push, pull_request] jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - configure_flags: - - - - --disable-amiga-lib + container: amigadev/crosstools:m68k-amigaos steps: - - name: Install dependencies - run: docker pull amigadev/crosstools:m68k-amigaos - uses: actions/checkout@v2 - name: autogen.sh run: ./autogen.sh - name: configure - run: | - docker run \ - -e PATH="/opt/m68k-amigaos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:m68k-amigaos \ - sh -c 'cd /objfw && ./configure --host=m68k-amigaos ${{ matrix.configure_flags }}' + run: ./configure --host=m68k-amigaos - name: make - run: | - docker run \ - -e PATH="/opt/m68k-amigaos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:m68k-amigaos \ - sh -c "cd /objfw && make -j$(nproc)" + run: make -j$(nproc) - name: make install - run: | - docker run \ - -e PATH="/opt/m68k-amigaos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:m68k-amigaos \ - sh -c "cd /objfw && make -j$(nproc)" + run: make install 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 Index: .github/workflows/morphos.yml ================================================================== --- .github/workflows/morphos.yml +++ .github/workflows/morphos.yml @@ -1,37 +1,16 @@ name: morphos on: [push, pull_request] jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - configure_flags: - - - - --disable-amiga-lib + container: amigadev/crosstools:ppc-morphos steps: - - name: Install dependencies - run: docker pull amigadev/crosstools:ppc-morphos - uses: actions/checkout@v2 - name: autogen.sh run: ./autogen.sh - name: configure - run: | - docker run \ - -e PATH="/opt/ppc-morphos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:ppc-morphos \ - sh -c 'cd /objfw && ./configure --host=ppc-morphos ${{ matrix.configure_flags }}' + run: ./configure --host=ppc-morphos - name: make - run: | - docker run \ - -e PATH="/opt/ppc-morphos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:ppc-morphos \ - sh -c "cd /objfw && make -j$(nproc)" + run: make -j$(nproc) - name: make install - run: | - docker run \ - -e PATH="/opt/ppc-morphos/bin:$PATH" \ - -v "$PWD:/objfw" \ - amigadev/crosstools:ppc-morphos \ - sh -c "cd /objfw && make -j$(nproc)" + run: 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 Index: .github/workflows/nintendo-3ds.yml ================================================================== --- .github/workflows/nintendo-3ds.yml +++ .github/workflows/nintendo-3ds.yml @@ -30,6 +30,6 @@ docker run \ -e DEVKITPRO=/opt/devkitpro \ -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ -v "$PWD:/objfw" \ devkitpro/devkitarm \ - sh -c "cd /objfw && make -j$(nproc)" + sh -c "cd /objfw && make install" Index: .github/workflows/nintendo-ds.yml ================================================================== --- .github/workflows/nintendo-ds.yml +++ .github/workflows/nintendo-ds.yml @@ -30,6 +30,6 @@ docker run \ -e DEVKITPRO=/opt/devkitpro \ -e PATH="/opt/devkitpro/devkitARM/bin:$PATH" \ -v "$PWD:/objfw" \ devkitpro/devkitarm \ - sh -c "cd /objfw && make -j$(nproc)" + sh -c "cd /objfw && make install" Index: .github/workflows/nintendo-switch.yml ================================================================== --- .github/workflows/nintendo-switch.yml +++ .github/workflows/nintendo-switch.yml @@ -30,6 +30,6 @@ docker run \ -e DEVKITPRO=/opt/devkitpro \ -e PATH="/opt/devkitpro/devkitA64/bin:$PATH" \ -v "$PWD:/objfw" \ devkitpro/devkita64 \ - sh -c "cd /objfw && make -j$(nproc)" + sh -c "cd /objfw && 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: .github/workflows/wii-u.yml ================================================================== --- .github/workflows/wii-u.yml +++ .github/workflows/wii-u.yml @@ -30,6 +30,6 @@ docker run \ -e DEVKITPRO=/opt/devkitpro \ -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ -v "$PWD:/objfw" \ devkitpro/devkitppc \ - sh -c "cd /objfw && make -j$(nproc)" + sh -c "cd /objfw && make install" Index: .github/workflows/wii.yml ================================================================== --- .github/workflows/wii.yml +++ .github/workflows/wii.yml @@ -30,6 +30,6 @@ docker run \ -e DEVKITPRO=/opt/devkitpro \ -e PATH="/opt/devkitpro/devkitPPC/bin:$PATH" \ -v "$PWD:/objfw" \ devkitpro/devkitppc \ - sh -c "cd /objfw && make -j$(nproc)" + sh -c "cd /objfw && 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`: @@ -321,11 +320,11 @@ To create your first, empty application, you can use `objfw-new`: $ objfw-new --app MyFirstApp - This creates a file `MyFirstApp.m`. The `-[applicationDidFinishLaunching]` + This creates a file `MyFirstApp.m`. The `-[applicationDidFinishLaunching:]` method is called as soon as ObjFW finished all initialization. Use this as the entry point to your own code. For example, you could add the following line there to create a "Hello World": [OFStdOut writeLine: @"Hello World!"]; 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 +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 @@ -1,8 +1,8 @@ # # Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, -# 2017, 2018, 2020, 2021 +# 2017, 2018, 2020, 2021, 2022, 2023 # Jonathan Schleifer # # https://fossil.nil.im/buildsys # # Permission to use, copy, modify, and/or distribute this software for any @@ -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.0dev, js@nil.im) +AC_INIT(ObjFW, 1.0dev, 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]) @@ -44,22 +44,10 @@ LIBS="$LIBS -ldebug" enable_files="yes" # Required for reading ENV: enable_shared="no" with_tls="no" - supports_amiga_lib="yes" - - AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFWRT_AMIGA_LIB, - ['objfwrt${OBJFWRT_LIB_MAJOR}.library']) - dnl For 68000, GCC emits calls to helper functions that - dnl do not work properly in a library. - t="-mcpu=68020 -fbaserel -noixemul -ffreestanding" - AC_SUBST(AMIGA_LIB_CFLAGS, $t) - t="$t -resident -nostartfiles -nodefaultlibs -ldebug -lc" - AC_SUBST(AMIGA_LIB_LDFLAGS, $t) - ]) AC_SUBST(LIBBASES_M, libbases.m) ;; powerpc-*-amigaos*) CPPFLAGS="$CPPFLAGS -D__USE_INLINE__" @@ -77,30 +65,20 @@ LDFLAGS="$LDFLAGS -noixemul" LIBS="$LIBS -ldebug" enable_files="yes" # Required for reading ENV: enable_shared="no" - supports_amiga_lib="yes" - - AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFWRT_AMIGA_LIB, - ['objfwrt${OBJFW_LIB_MAJOR}ppc.library']) - t="-mresident32 -ffreestanding -noixemul" - AC_SUBST(AMIGA_LIB_CFLAGS, $t) - t="-mresident32 -nostartfiles -nodefaultlibs -noixemul -ldebug" - AC_SUBST(AMIGA_LIB_LDFLAGS, "$t -lc") - ]) AC_SUBST(LIBBASES_M, libbases.m) ;; *-msdosdjgpp*) 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-*) @@ -141,10 +119,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} @@ -164,11 +150,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])) @@ -409,11 +394,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([ @@ -433,22 +420,12 @@ TESTS_LIBS="\${RUNTIME_LIBS} $TESTS_LIBS" TESTS_LIBS="-L../src/runtime -L../src/runtime/linklib $TESTS_LIBS" TESTS_LIBS="-L../src -lobjfw $TESTS_LIBS" ]) -AC_ARG_ENABLE(amiga-lib, - AS_HELP_STRING([--disable-amiga-lib], [do not build Amiga library])) -AS_IF([test x"$supports_amiga_lib" != x"yes"], [enable_amiga_lib="no"]) -AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(OBJFW_STATIC_LIB, "libobjfw.a") - AC_SUBST(EXCEPTIONS_A, "exceptions.a") - AC_SUBST(FORWARDING_A, "forwarding.a") - AC_SUBST(LOOKUP_ASM_AMIGALIB_A, "lookup-asm.amigalib.a") -]) - AC_ARG_ENABLE(static, AS_HELP_STRING([--enable-static], [build static library])) -AS_IF([test x"$enable_shared" = x"no" -a x"$enable_amiga_lib" = x"no"], [ +AS_IF([test x"$enable_shared" = x"no"], [ enable_static="yes" ]) AS_IF([test x"$enable_static" = x"yes"], [ AC_SUBST(OBJFW_STATIC_LIB, "libobjfw.a") AC_SUBST(EXCEPTIONS_A, "exceptions.a") @@ -570,11 +547,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") ]) @@ -582,22 +559,13 @@ AS_IF([test x"$build_framework" = x"yes"], [ AC_SUBST(OBJFWRT_FRAMEWORK, "ObjFWRT.framework") AC_SUBST(RUNTIME_FRAMEWORK_LIBS, "-framework ObjFWRT") ]) - AS_IF([test x"$enable_amiga_lib" != x"no"], [ - AC_SUBST(RUNTIME_LIBS, "-lobjfwrt.library") - AC_SUBST(LINKLIB, linklib) - tmp="../src/runtime/linklib/libobjfwrt.library.a" - AC_SUBST(LIBOBJFWRT_DEP, "$tmp") - AC_SUBST(LIBOBJFWRT_DEP_LVL2, "../$tmp") - ], [ - AC_SUBST(RUNTIME_LIBS, "-lobjfwrt") - ]) - - AS_IF([test x"$enable_shared" = x"no" \ - -a x"$enable_amiga_lib" = x"no"], [ + AC_SUBST(RUNTIME_LIBS, "-lobjfwrt") + + AS_IF([test x"$enable_shared" = x"no"], [ AC_SUBST(LIBOBJFWRT_DEP, "../src/runtime/libobjfwrt.a") AC_SUBST(LIBOBJFWRT_DEP_LVL2, "../../src/runtime/libobjfwrt.a") ]) AS_IF([test x"$enable_seluid24" = x"yes"], [ @@ -1027,11 +995,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 @@ -1303,11 +1289,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([ @@ -1389,27 +1375,47 @@ 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]) + 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_HEADER(netipx/ipx.h, [ - AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1, - [Whether we have netipx/ipx.h]) - ]) - AC_CHECK_MEMBER([struct sockaddr_in6.sin6_addr], [ AC_EGREP_CPP(egrep_cpp_yes, [ #ifdef _WIN32 typedef int BOOL; #endif @@ -1469,10 +1475,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 @@ -1490,17 +1511,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 @@ -1517,10 +1561,14 @@ ]) ], [ #ifdef _WIN32 typedef int BOOL; #endif + + #ifdef HAVE_SYS_TYPES_H + # include + #endif #ifdef OF_HAVE_NETIPX_IPX_H # include #endif @@ -1534,11 +1582,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 @@ -1563,10 +1612,101 @@ ], [ AC_DEFINE(OF_HAVE_IPX, 1, [Whether we have IPX/SPX]) AC_SUBST(USE_SRCS_IPX, '${SRCS_IPX}') ]) ]) + + AC_CHECK_HEADER(netat/appletalk.h, [ + AC_DEFINE(OF_HAVE_NETAT_APPLETALK_H, 1, + [Whether we have netat/appletalk.h]) + ]) + AC_CHECK_HEADER(netatalk/at.h, [ + AC_DEFINE(OF_HAVE_NETATALK_AT_H, 1, + [Whether we have netatalk/at.h]) + ]) + AC_CHECK_MEMBER(struct sockaddr_at.sat_addr, [], [ + AC_CHECK_MEMBER(struct sockaddr_at.sat_net, [], [], [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #if defined(OF_HAVE_NETAT_APPLETALK_H) + # include + #elif defined(OF_HAVE_NETATALK_AT_H) + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + ]) + ], [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_TYPES_H + # include + #endif + #if defined(OF_HAVE_NETAT_APPLETALK_H) + # include + #elif defined(OF_HAVE_NETATALK_AT_H) + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + ]) + AS_IF([test x"$ac_cv_member_struct_sockaddr_at_sat_addr" = x"yes" \ + -o x"$ac_cv_member_struct_sockaddr_at_sat_net" = x"yes"], [ + AC_EGREP_CPP(egrep_cpp_yes, [ + #ifdef _WIN32 + typedef int BOOL; + #endif + + #ifdef OF_HAVE_SYS_SOCKET_H + # include + #endif + + #ifdef _WIN32 + # ifdef __MINGW32__ + # include <_mingw.h> + # ifdef __MINGW64_VERSION_MAJOR + # include + # endif + # endif + # include + # include + #endif + + #ifdef AF_APPLETALK + egrep_cpp_yes + #endif + ], [ + AC_DEFINE(OF_HAVE_APPLETALK, 1, + [Whether we have AppleTalk]) + AC_SUBST(USE_SRCS_APPLETALK, '${SRCS_APPLETALK}') + ]) + ]) AC_CHECK_FUNCS(paccept accept4, break) AC_CHECK_FUNCS(kqueue1 kqueue, [ AC_DEFINE(HAVE_KQUEUE, 1, [Whether we have kqueue]) @@ -1609,27 +1749,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, @@ -1639,13 +1779,28 @@ ], []) LIBS="$old_LIBS" ]) ]) + + AS_IF([test x"$with_tls" = x"gnutls" \ + -o \( x"$with_tls" = x"yes" -a x"$tls_support" = x"no" \)], [ + PKG_CHECK_MODULES(gnutls, [gnutls >= 3.5.0], [ + tls_support="GnuTLS" + TLS_CPPFLAGS="$gnutls_CFLAGS $TLS_CPPFLAGS" + TLS_LIBS="$gnutls_LIBS $TLS_LIBS" + + AC_SUBST(OF_GNUTLS_TLS_STREAM_M, "OFGnuTLSTLSStream.m") + ], [ + dnl Disable default action-if-not-found, which exits + dnl configure with an error. + : + ]) + ]) 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" ;; @@ -1655,39 +1810,19 @@ ;; 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") ]) ], [], [-l$crypto]) ]) - AS_IF([test x"$with_tls" = x"gnutls" \ - -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") - ], [ - dnl Disable default action-if-not-found, which exits - dnl configure with an error. - : - ]) - ]) - AS_IF([test x"$tls_support" != x"no"], [ AC_SUBST(TLS, "tls") AC_SUBST(TLS_CPPFLAGS) AC_SUBST(TLS_LIBS) AC_DEFINE(HAVE_TLS_SUPPORT, 1, @@ -1696,11 +1831,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") ]) @@ -1760,14 +1895,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" ]) ;; @@ -1775,21 +1906,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" \ @@ -1799,19 +1931,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()]) ]) @@ -1820,11 +1951,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") ]) @@ -1854,11 +1985,17 @@ AC_MSG_RESULT(no) OBJCFLAGS="$old_OBJCFLAGS" ]) AS_IF([test x"$GOBJC" = x"yes"], [ - OBJCFLAGS="$OBJCFLAGS -Wwrite-strings -Wpointer-arith -Werror" + OBJCFLAGS="$OBJCFLAGS -Wwrite-strings -Wpointer-arith" + + AC_ARG_ENABLE(werror, + AS_HELP_STRING([--disable-werror], [do not build with -Werror])) + AS_IF([test x"$enable_werror" != x"no"], [ + OBJCFLAGS="$OBJCFLAGS -Werror" + ]) AC_MSG_CHECKING(whether we need -Wno-strict-aliasing due to GCC bugs) AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([ #ifdef __has_attribute @@ -1999,11 +2136,12 @@ # define OF_DEALLOC_UNSUPPORTED \ [self doesNotRecognizeSelector: _cmd]; \ \ abort(); \ \ - _Pragma("clang diagnostic push ignore \ + _Pragma("clang diagnostic push"); \ + _Pragma("clang diagnostic ignored \ \"-Wunreachable-code\""); \ [super dealloc]; \ _Pragma("clang diagnostic pop"); #else # define OF_DEALLOC_UNSUPPORTED \ @@ -2097,10 +2235,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([ @@ -2127,14 +2279,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. @@ -2144,21 +2293,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 @@ -6,11 +6,10 @@ OBJFW_LIB_MAJOR_MINOR = ${OBJFW_LIB_MAJOR}.${OBJFW_LIB_MINOR} OBJFWRT_SHARED_LIB = @OBJFWRT_SHARED_LIB@ OBJFWRT_STATIC_LIB = @OBJFWRT_STATIC_LIB@ OBJFWRT_FRAMEWORK = @OBJFWRT_FRAMEWORK@ -OBJFWRT_AMIGA_LIB = @OBJFWRT_AMIGA_LIB@ OBJFWRT_LIB_MAJOR = 0 OBJFWRT_LIB_MINOR = 0 OBJFWRT_LIB_MAJOR_MINOR = ${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR} OBJFWBRIDGE_SHARED_LIB = @OBJFWBRIDGE_SHARED_LIB@ @@ -27,21 +26,18 @@ ENCODINGS_A = @ENCODINGS_A@ ENCODINGS_LIB_A = @ENCODINGS_LIB_A@ ENCODINGS_SRCS = @ENCODINGS_SRCS@ EXCEPTIONS_A = @EXCEPTIONS_A@ EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@ -FISH_COMPLETIONS = @FISH_COMPLETIONS@ FORWARDING_A = @FORWARDING_A@ FORWARDING_LIB_A = @FORWARDING_LIB_A@ LIBBASES_M = @LIBBASES_M@ LIBOBJFWRT_DEP = @LIBOBJFWRT_DEP@ LIBOBJFWRT_DEP_LVL2 = @LIBOBJFWRT_DEP_LVL2@ LIBOBJFW_DEP = @LIBOBJFW_DEP@ LIBOBJFW_DEP_LVL2 = @LIBOBJFW_DEP_LVL2@ -LINKLIB = @LINKLIB@ LOOKUP_ASM_A = @LOOKUP_ASM_A@ -LOOKUP_ASM_AMIGALIB_A = @LOOKUP_ASM_AMIGALIB_A@ LOOKUP_ASM_LIB_A = @LOOKUP_ASM_LIB_A@ MAP_LDFLAGS = @MAP_LDFLAGS@ OBJC_SYNC = @OBJC_SYNC@ OBJFW_NEW = @OBJFW_NEW@ OFARC = @OFARC@ @@ -77,13 +73,14 @@ TLS = @TLS@ TLS_CPPFLAGS = @TLS_CPPFLAGS@ TLS_LIBS = @TLS_LIBS@ UNICODE_M = @UNICODE_M@ USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@ +USE_SRCS_APPLETALK = @USE_SRCS_APPLETALK@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_IPX = @USE_SRCS_IPX@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@ USE_SRCS_THREADS = @USE_SRCS_THREADS@ USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@ USE_SRCS_WINDOWS = @USE_SRCS_WINDOWS@ WRAPPER = @WRAPPER@ DELETED generators/library/FuncArrayGenerator.h Index: generators/library/FuncArrayGenerator.h ================================================================== --- generators/library/FuncArrayGenerator.h +++ generators/library/FuncArrayGenerator.h @@ -1,30 +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 "OFStream.h" -#import "OFXMLElement.h" - -@interface FuncArrayGenerator: OFObject -{ - OFXMLElement *_library; - OFStream *_include; -} - -- (instancetype)initWithLibrary: (OFXMLElement *)library - include: (OFStream *)include; -- (void)generate; -@end DELETED generators/library/FuncArrayGenerator.m Index: generators/library/FuncArrayGenerator.m ================================================================== --- generators/library/FuncArrayGenerator.m +++ generators/library/FuncArrayGenerator.m @@ -1,78 +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 "OFArray.h" -#import "OFXMLAttribute.h" - -#import "FuncArrayGenerator.h" - -#import "OFInvalidFormatException.h" -#import "OFUnsupportedVersionException.h" - -#import "copyright.h" - -@implementation FuncArrayGenerator -- (instancetype)initWithLibrary: (OFXMLElement *)library - include: (OFStream *)include -{ - self = [super init]; - - @try { - OFXMLAttribute *version; - - if (![library.name isEqual: @"amiga-library"] || - library.namespace != nil) - @throw [OFInvalidFormatException exception]; - - if ((version = [library attributeForName: @"version"]) == nil) - @throw [OFInvalidFormatException exception]; - - if (![version.stringValue isEqual: @"1.0"]) - @throw [OFUnsupportedVersionException - exceptionWithVersion: version.stringValue]; - - _library = [library retain]; - _include = [include retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_library release]; - [_include release]; - - [super dealloc]; -} - -- (void)generate -{ - [_include writeString: COPYRIGHT]; - [_include writeString: - @"/* This file is automatically generated from amiga-library.xml */" - @"\n\n"]; - - for (OFXMLElement *function in [_library elementsForName: @"function"]) - [_include writeFormat: - @"(CONST_APTR)glue_%@,\n", - [function attributeForName: @"name"].stringValue]; -} -@end DELETED generators/library/GlueGenerator.h Index: generators/library/GlueGenerator.h ================================================================== --- generators/library/GlueGenerator.h +++ generators/library/GlueGenerator.h @@ -1,31 +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 "OFStream.h" -#import "OFXMLElement.h" - -@interface GlueGenerator: OFObject -{ - OFXMLElement *_library; - OFStream *_header, *_impl; -} - -- (instancetype)initWithLibrary: (OFXMLElement *)library - header: (OFStream *)header - implementation: (OFStream *)implementation; -- (void)generate; -@end DELETED generators/library/GlueGenerator.m Index: generators/library/GlueGenerator.m ================================================================== --- generators/library/GlueGenerator.m +++ generators/library/GlueGenerator.m @@ -1,207 +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 "OFArray.h" -#import "OFXMLAttribute.h" - -#import "GlueGenerator.h" - -#import "OFInvalidFormatException.h" -#import "OFUnsupportedVersionException.h" - -#import "copyright.h" - -@implementation GlueGenerator -- (instancetype)initWithLibrary: (OFXMLElement *)library - header: (OFStream *)header - implementation: (OFStream *)impl -{ - self = [super init]; - - @try { - OFXMLAttribute *version; - - if (![library.name isEqual: @"amiga-library"] || - library.namespace != nil) - @throw [OFInvalidFormatException exception]; - - if ((version = [library attributeForName: @"version"]) == nil) - @throw [OFInvalidFormatException exception]; - - if (![version.stringValue isEqual: @"1.0"]) - @throw [OFUnsupportedVersionException - exceptionWithVersion: version.stringValue]; - - _library = [library retain]; - _header = [header retain]; - _impl = [impl retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_library release]; - [_header release]; - [_impl release]; - - [super dealloc]; -} - -- (void)generate -{ - [_header writeString: COPYRIGHT]; - [_impl writeString: COPYRIGHT]; - - [_header writeString: - @"/* This file is automatically generated from amiga-library.xml */" - @"\n\n"]; - - [_impl writeString: - @"/* This file is automatically generated from amiga-library.xml */" - @"\n\n" - @"#include \"config.h\"\n" - @"\n" - @"#import \"amiga-glue.h\"\n" - @"\n"]; - - for (OFXMLElement *include in [_library elementsForName: @"include"]) - [_header writeFormat: @"#import \"%@\"\n", include.stringValue]; - - [_header writeString: - @"\n" - @"#ifdef OF_AMIGAOS_M68K\n" - @"# define PPC_PARAMS(...) (void)\n" - @"# define M68K_ARG(type, name, reg)\t\t\\\n" - @"\tregister type reg##name __asm__(#reg);\t\\\n" - @"\ttype name = reg##name;\n" - @"#else\n" - @"# define PPC_PARAMS(...) (__VA_ARGS__)\n" - @"# define M68K_ARG(...)\n" - @"#endif\n" - @"\n"]; - [_impl writeString: - @"#ifdef OF_MORPHOS\n" - @"/* All __saveds functions in this file need to use the SysV " - @"ABI */\n" - @"__asm__ (\n" - @" \".section .text\\n\"\n" - @" \".align 2\\n\"\n" - @" \"__restore_r13:\\n\"\n" - @" \"\tlwz\t%r13, 44(%r12)\\n\"\n" - @" \"\tblr\\n\"\n" - @");\n" - @"#endif\n"]; - - for (OFXMLElement *function in - [_library elementsForName: @"function"]) { - OFString *name = - [function attributeForName: @"name"].stringValue; - OFString *returnType = - [function attributeForName: @"return-type"].stringValue; - OFArray OF_GENERIC(OFXMLElement *) *arguments = - [function elementsForName: @"argument"]; - size_t argumentIndex; - - if (returnType == nil) - returnType = @"void"; - - [_header writeFormat: - @"extern %@%@glue_%@", - returnType, - (![returnType hasSuffix: @"*"] ? @" " : @""), - name]; - - [_impl writeFormat: @"\n" - @"%@ __saveds\n" - @"glue_%@", - returnType, name]; - - if (arguments.count > 0) { - [_header writeString: @" PPC_PARAMS("]; - [_impl writeString: @" PPC_PARAMS("]; - } else { - [_header writeString: @"(void"]; - [_impl writeString: @"(void"]; - } - - argumentIndex = 0; - for (OFXMLElement *argument in arguments) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - OFString *argType = - [argument attributeForName: @"type"].stringValue; - - if (argumentIndex++ > 0) { - [_header writeString: @", "]; - [_impl writeString: @", "]; - } - - [_header writeString: argType]; - [_impl writeString: argType]; - if (![argType hasSuffix: @"*"]) { - [_header writeString: @" "]; - [_impl writeString: @" "]; - } - [_header writeString: argName]; - [_impl writeString: argName]; - } - - [_header writeString: @");\n"]; - - [_impl writeString: @")\n{\n"]; - for (OFXMLElement *argument in arguments) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - OFString *argType = - [argument attributeForName: @"type"].stringValue; - OFString *m68kReg = [argument - attributeForName: @"m68k-reg"].stringValue; - - [_impl writeFormat: @"\tM68K_ARG(%@, %@, %@)\n", - argType, argName, m68kReg]; - } - - if (arguments.count > 0) - [_impl writeString: @"\n"]; - - if (![returnType isEqual: @"void"]) - [_impl writeString: @"\treturn "]; - else - [_impl writeString: @"\t"]; - - [_impl writeFormat: @"%@(", name]; - - argumentIndex = 0; - for (OFXMLElement *argument in arguments) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argName]; - } - - [_impl writeString: @");\n}\n"]; - } -} -@end DELETED generators/library/LibraryGenerator.m Index: generators/library/LibraryGenerator.m ================================================================== --- generators/library/LibraryGenerator.m +++ generators/library/LibraryGenerator.m @@ -1,81 +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 "OFApplication.h" -#import "OFFile.h" -#import "OFFileManager.h" -#import "OFURI.h" -#import "OFXMLElement.h" - -#import "FuncArrayGenerator.h" -#import "GlueGenerator.h" -#import "LinkLibGenerator.h" - -@interface LibraryGenerator: OFObject -@end - -OF_APPLICATION_DELEGATE(LibraryGenerator) - -@implementation LibraryGenerator -- (void)applicationDidFinishLaunching -{ - OFURI *sourcesURI = [[OFFileManager defaultManager].currentDirectoryURI - URIByAppendingPathComponent: @"../../src"]; - OFURI *runtimeLibraryURI = [sourcesURI - URIByAppendingPathComponent: @"runtime/amiga-library.xml"]; - OFURI *runtimeLinkLibURI = [sourcesURI - URIByAppendingPathComponent: @"runtime/linklib/linklib.m"]; - OFURI *runtimeGlueHeaderURI = [sourcesURI - URIByAppendingPathComponent: @"runtime/amiga-glue.h"]; - OFURI *runtimeGlueURI = [sourcesURI - URIByAppendingPathComponent: @"runtime/amiga-glue.m"]; - OFURI *runtimeFuncArrayURI = [sourcesURI - URIByAppendingPathComponent: @"runtime/amiga-funcarray.inc"]; - OFXMLElement *runtimeLibrary = [OFXMLElement elementWithStream: - [OFFile fileWithPath: runtimeLibraryURI.fileSystemRepresentation - mode: @"r"]]; - OFFile *runtimeLinkLib = - [OFFile fileWithPath: runtimeLinkLibURI.fileSystemRepresentation - mode: @"w"]; - OFFile *runtimeGlueHeader = - [OFFile fileWithPath: runtimeGlueHeaderURI.fileSystemRepresentation - mode: @"w"]; - OFFile *runtimeGlue = - [OFFile fileWithPath: runtimeGlueURI.fileSystemRepresentation - mode: @"w"]; - OFFile *runtimeFuncArray = - [OFFile fileWithPath: runtimeFuncArrayURI.fileSystemRepresentation - mode: @"w"]; - LinkLibGenerator *runtimeLinkLibGenerator = [[[LinkLibGenerator alloc] - initWithLibrary: runtimeLibrary - implementation: runtimeLinkLib] autorelease]; - GlueGenerator *runtimeGlueGenerator = [[[GlueGenerator alloc] - initWithLibrary: runtimeLibrary - header: runtimeGlueHeader - implementation: runtimeGlue] autorelease]; - FuncArrayGenerator *runtimeFuncArrayGenerator; - runtimeFuncArrayGenerator = [[[FuncArrayGenerator alloc] - initWithLibrary: runtimeLibrary - include: runtimeFuncArray] autorelease]; - - [runtimeLinkLibGenerator generate]; - [runtimeGlueGenerator generate]; - [runtimeFuncArrayGenerator generate]; - - [OFApplication terminate]; -} -@end DELETED generators/library/LinkLibGenerator.h Index: generators/library/LinkLibGenerator.h ================================================================== --- generators/library/LinkLibGenerator.h +++ generators/library/LinkLibGenerator.h @@ -1,29 +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 "OFStream.h" -#import "OFXMLElement.h" - -@interface LinkLibGenerator: OFObject -{ - OFXMLElement *_library; - OFStream *_impl; -} - -- (instancetype)initWithLibrary: (OFXMLElement *)library - implementation: (OFStream *)impl; -- (void)generate; -@end DELETED generators/library/LinkLibGenerator.m Index: generators/library/LinkLibGenerator.m ================================================================== --- generators/library/LinkLibGenerator.m +++ generators/library/LinkLibGenerator.m @@ -1,226 +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 "OFArray.h" -#import "OFXMLAttribute.h" - -#import "LinkLibGenerator.h" - -#import "OFInvalidFormatException.h" -#import "OFUnsupportedVersionException.h" - -#import "copyright.h" - -@implementation LinkLibGenerator -- (instancetype)initWithLibrary: (OFXMLElement *)library - implementation: (OFStream *)impl -{ - self = [super init]; - - @try { - OFXMLAttribute *version; - - if (![library.name isEqual: @"amiga-library"] || - library.namespace != nil) - @throw [OFInvalidFormatException exception]; - - if ((version = [library attributeForName: @"version"]) == nil) - @throw [OFInvalidFormatException exception]; - - if (![version.stringValue isEqual: @"1.0"]) - @throw [OFUnsupportedVersionException - exceptionWithVersion: version.stringValue]; - - _library = [library retain]; - _impl = [impl retain]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_library release]; - [_impl release]; - - [super dealloc]; -} - -- (void)generate -{ - OFString *libBase = [_library attributeForName: @"base"].stringValue; - OFArray OF_GENERIC(OFXMLElement *) *functions; - size_t funcIndex = 0; - - [_impl writeString: COPYRIGHT]; - [_impl writeString: - @"/* This file is automatically generated from amiga-library.xml */" - @"\n\n" - @"#include \"config.h\"\n" - @"\n"]; - - for (OFXMLElement *include in [_library elementsForName: @"include"]) - [_impl writeFormat: @"#import \"%@\"\n", - include.stringValue]; - - [_impl writeFormat: @"\n" - @"extern struct Library *%@;\n" - @"\n", - libBase]; - - functions = [_library elementsForName: @"function"]; - for (OFXMLElement *function in functions) { - OFString *name = - [function attributeForName: @"name"].stringValue; - OFString *returnType = - [function attributeForName: @"return-type"].stringValue; - OFArray OF_GENERIC(OFXMLElement *) *arguments = - [function elementsForName: @"argument"]; - size_t argumentIndex; - - if (returnType == nil) - returnType = @"void"; - - [_impl writeFormat: @"%@\n%@(", returnType, name]; - - argumentIndex = 0; - for (OFXMLElement *argument in - [function elementsForName: @"argument"]) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - OFString *argType = - [argument attributeForName: @"type"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argType]; - if (![argType hasSuffix: @"*"]) - [_impl writeString: @" "]; - [_impl writeString: argName]; - } - - [_impl writeFormat: - @")\n" - @"{\n" - @"#if defined(OF_AMIGAOS_M68K)\n" - @"\tregister struct Library *a6 __asm__(\"a6\") = %@;\n" - @"\t(void)a6;\n" - @"\t", libBase]; - - if (![returnType isEqual: @"void"]) - [_impl writeString: @"return "]; - - [_impl writeString: @"(("]; - [_impl writeString: returnType]; - if (![returnType hasSuffix: @"*"]) - [_impl writeString: @" "]; - [_impl writeString: @"(*)("]; - - argumentIndex = 0; - for (OFXMLElement *argument in arguments) { - OFString *argType = - [argument attributeForName: @"type"].stringValue; - OFString *m68kReg = [argument - attributeForName: @"m68k-reg"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argType]; - if (![argType hasSuffix: @"*"]) - [_impl writeString: @" "]; - [_impl writeFormat: @"__asm__(\"%@\")", - m68kReg]; - } - - [_impl writeFormat: @"))(((uintptr_t)%@) - %zu))(", - libBase, 30 + funcIndex * 6]; - - argumentIndex = 0; - for (OFXMLElement *argument in - [function elementsForName: @"argument"]) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argName]; - } - - [_impl writeFormat: @");\n" - @"#elif defined(OF_MORPHOS)\n" - @"\t__asm__ __volatile__ (\n" - @"\t \"mr\t\t%%%%r12, %%0\"\n" - @"\t :: \"r\"(%@) : \"r12\"\n" - @"\t);\n" - @"\n" - @"\t", - libBase, libBase]; - - if (![returnType isEqual: @"void"]) - [_impl writeString: @"return "]; - - [_impl writeString: @"__extension__ (("]; - [_impl writeString: returnType]; - if (![returnType hasSuffix: @"*"]) - [_impl writeString: @" "]; - [_impl writeString: @"(*)("]; - - argumentIndex = 0; - for (OFXMLElement *argument in arguments) { - OFString *argType = - [argument attributeForName: @"type"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argType]; - } - - [_impl writeFormat: @"))*(void **)(((uintptr_t)%@) - %zu))(", - libBase, 28 + funcIndex * 6]; - - argumentIndex = 0; - for (OFXMLElement *argument in - [function elementsForName: @"argument"]) { - OFString *argName = - [argument attributeForName: @"name"].stringValue; - - if (argumentIndex++ > 0) - [_impl writeString: @", "]; - - [_impl writeString: argName]; - } - - [_impl writeString: @");\n" - @"#endif\n"]; - - if ([function attributeForName: @"noreturn"] != nil) - [_impl writeString: @"\n\tOF_UNREACHABLE\n"]; - - [_impl writeString: @"}\n"]; - - if (++funcIndex < functions.count) - [_impl writeString: @"\n"]; - } -} -@end DELETED generators/library/Makefile Index: generators/library/Makefile ================================================================== --- generators/library/Makefile +++ generators/library/Makefile @@ -1,75 +0,0 @@ -include ../../extra.mk - -PROG_NOINST = gen_libraries${PROG_SUFFIX} -SRCS = FuncArrayGenerator.m \ - GlueGenerator.m \ - LibraryGenerator.m \ - LinkLibGenerator.m - -include ../../buildsys.mk - -.PHONY: run -run: all - rm -f libobjfw.so.${OBJFW_LIB_MAJOR} - rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} - rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} - rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll - rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib - rm -f ${OBJFWRT_AMIGA_LIB} - if test -f ../../src/libobjfw.so; then \ - ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ - ${LN_S} ../../src/libobjfw.so \ - libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ - elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ - ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ - libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ - fi - if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ - ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ - objfw${OBJFW_LIB_MAJOR}.dll; \ - fi - if test -f ../../src/libobjfw.dylib; then \ - ${LN_S} ../../src/libobjfw.dylib \ - libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ - fi - if test -f ../../src/runtime/libobjfwrt.so; then \ - ${LN_S} ../../src/runtime/libobjfwrt.so \ - libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - ${LN_S} ../../src/runtime/libobjfwrt.so \ - libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ - elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ - ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ - fi - if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ - ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ - objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ - fi - if test -f ../../src/runtime/libobjfwrt.dylib; then \ - ${LN_S} ../../src/runtime/libobjfwrt.dylib \ - libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ - fi - if test -f ../../src/runtime/${OBJFWRT_AMIGA_LIB}; then \ - ${LN_S} ../../src/runtime/${OBJFWRT_AMIGA_LIB} \ - ${OBJFWRT_AMIGA_LIB}; \ - fi - LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ - DYLD_FRAMEWORK_PATH=../../src:../../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ - DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ - LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ - ASAN_OPTIONS=allocator_may_return_null=1 \ - ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ - rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ - rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ - rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ - rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ - rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ - rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ - rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ - exit $$EXIT - -CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. -LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} -LD = ${OBJC} DELETED generators/library/copyright.h Index: generators/library/copyright.h ================================================================== --- generators/library/copyright.h +++ generators/library/copyright.h @@ -1,38 +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" - -#define COPYRIGHT \ - @"/*\n" \ - @" * Copyright (c) 2008-2022 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" \ - @" * Q Public License 1.0, which can be found in the file LICENSE.QPL " \ - @"included in\n" \ - @" * the packaging of this file.\n" \ - @" *\n" \ - @" * Alternatively, it may be distributed under the terms of the GNU " \ - @"General\n" \ - @" * Public License, either version 2 or 3, which can be found in the " \ - @"file\n" \ - @" * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the " \ - @"packaging of this\n" \ - @" * file.\n" \ - @" */\n" \ - @"\n" Index: generators/unicode/Makefile ================================================================== --- generators/unicode/Makefile +++ generators/unicode/Makefile @@ -12,11 +12,10 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib - rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -45,14 +44,10 @@ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi - if test -f ../../src/runtime/${OBJFWRT_AMIGA_LIB}; then \ - ${LN_S} ../../src/runtime/${OBJFWRT_AMIGA_LIB} \ - ${OBJFWRT_AMIGA_LIB}; \ - fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_FRAMEWORK_PATH=../../src:../../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ 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 @@ -60,18 +60,18 @@ } return self; } -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { 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 @@ -30,11 +30,11 @@ BuildRequires: autoconf BuildRequires: automake BuildRequires: clang BuildRequires: make -BuildRequires: pkgconfig(openssl) +BuildRequires: pkgconfig(gnutls) Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} Requires: %{libobjfw_pkgname}-devel = %{version}-%{release} Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} Requires: %{libobjfwrt_pkgname}-devel = %{version}-%{release} Requires: ofarc%{_isa} = %{version}-%{release} @@ -87,11 +87,11 @@ The %{libobjfwrt_pkgname}-devel package contains header files and libraries for ObjFW's Objective-C runtime library. %package -n %{libobjfwtls_pkgname} Summary: TLS support for ObjFW -Requires: openssl%{_isa} >= 1.1.1 +Requires: gnutls%{_isa} >= 3.0.5 %description -n %{libobjfwtls_pkgname} The %{libobjfwtls_pkgname} package contains TLS support for ObjFW %package -n %{libobjfwtls_pkgname}-devel @@ -136,14 +136,14 @@ Requires: %{libobjfw_pkgname}%{_isa} = %{version}-%{release} Requires: %{libobjfwrt_pkgname}%{_isa} = %{version}-%{release} Requires: %{libobjfwtls_pkgname}%{_isa} = %{version}-%{release} %description -n ofhttp -ofhttp is a command line downloader for HTTP and HTTPS (via ObjOpenSSL) using -ObjFW's OFHTTPClient class. It supports all features one would expect from a -modern command line downloader such as resuming of downloads, using a SOCKS5 -proxy, a modern terminal-based UI, etc. +ofhttp is a command line downloader for HTTP and HTTPS using ObjFW's +OFHTTPClient class. It supports all features one would expect from a modern +command line downloader such as resuming of downloads, using a SOCKS5 proxy, a +modern terminal-based UI, etc. %prep %autosetup ./autogen.sh @@ -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 @@ -26,40 +26,42 @@ 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 \ @@ -72,41 +74,36 @@ OFSHA384Or512Hash.m \ OFSHA512Hash.m \ OFScrypt.m \ OFSecureData.m \ OFSeekableStream.m \ - OFSerialization.m \ OFSet.m \ + OFSettings.m \ OFSortedList.m \ OFStdIOStream.m \ OFStream.m \ 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} \ - OFSettings.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 \ @@ -131,15 +128,18 @@ 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} \ ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFDDPSocket.m SRCS_IPX = OFIPXSocket.m \ OFSPXSocket.m \ OFSPXStreamSocket.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ OFUNIXStreamSocket.m @@ -175,18 +175,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 \ - OFEmbeddedURIHandler.m \ + OFEmbeddedIRIHandler.m \ OFHuffmanTree.m \ OFINIFileSettings.m \ OFInvertedCharacterSet.m \ OFLHADecompressingStream.m \ OFMapTableDictionary.m \ @@ -208,16 +208,16 @@ OFUTF8String.m \ ${LIBBASES_M} \ ${RUNTIME_AUTORELEASE_M} \ ${RUNTIME_INSTANCE_M} \ ${UNICODE_M} -SRCS_FILES += OFFileURIHandler.m -SRCS_SOCKETS += OFDNSResolverSettings.m \ +SRCS_FILES += OFFileIRIHandler.m +SRCS_SOCKETS += OFAsyncIPSocketConnector.m \ + OFDNSResolverSettings.m \ ${OF_EPOLL_KERNEL_EVENT_OBSERVER_M} \ - OFHTTPURIHandler.m \ + OFHTTPIRIHandler.m \ OFHostAddressResolver.m \ - OFIPSocketAsyncConnector.m \ OFKernelEventObserver.m \ ${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M} \ ${OF_POLL_KERNEL_EVENT_OBSERVER_M} \ ${OF_SELECT_KERNEL_EVENT_OBSERVER_M} \ OFTCPSocketSOCKS5Connector.m @@ -243,5 +243,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 { @@ -318,10 +284,11 @@ - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count_ { + static unsigned long dummyMutations; size_t count = _array.count; if (count > INT_MAX) /* * Use the implementation from OFArray, which is slower, but can @@ -334,11 +301,11 @@ if (state->state >= count) return 0; state->state = (unsigned long)count; state->itemsPtr = (id *)_array.items; - state->mutationsPtr = (unsigned long *)self; + state->mutationsPtr = &dummyMutations; return (int)count; } #ifdef OF_HAVE_BLOCKS 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 @@ -27,10 +27,16 @@ @class OFMutableArray OF_GENERIC(ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFSandbox; @class OFString; +/** + * @brief A notification that will be sent when the application did finish + * launching. + */ +extern const OFNotificationName OFApplicationDidFinishLaunchingNotification; + /** * @brief A notification that will be sent when the application will terminate. */ extern const OFNotificationName OFApplicationWillTerminateNotification; @@ -49,11 +55,11 @@ * * // In MyAppDelegate.m: * OF_APPLICATION_DELEGATE(MyAppDelegate) * * @implementation MyAppDelegate - * - (void)applicationDidFinishLaunching + * - (void)applicationDidFinishLaunching: (OFNotification *)notification * { * [OFApplication terminate]; * } * @end * @endcode @@ -79,18 +85,24 @@ */ @protocol OFApplicationDelegate /** * @brief A method which is called when the application was initialized and is * running now. + * + * @param notification A notification with name + * OFApplicationDidFinishLaunchingNotification */ -- (void)applicationDidFinishLaunching; +- (void)applicationDidFinishLaunching: (OFNotification *)notification; @optional /** * @brief A method which is called when the application will terminate. + * + * @param notification A notification with name + * OFApplicationWillTerminateNotification */ -- (void)applicationWillTerminate; +- (void)applicationWillTerminate: (OFNotification *)notification; /** * @brief A method which is called when the application received a SIGINT. * * @warning You are not allowed to send any messages inside this method, as @@ -151,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 @@ -35,29 +35,32 @@ #import "OFNotificationCenter.h" #import "OFPair.h" #import "OFRunLoop+Private.h" #import "OFRunLoop.h" #import "OFSandbox.h" +#import "OFStdIOStream.h" #import "OFString.h" #import "OFSystemInfo.h" #import "OFThread+Private.h" #import "OFThread.h" +#import "OFActivateSandboxFailedException.h" #import "OFInvalidArgumentException.h" #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" -#import "OFSandboxActivationFailedException.h" #if defined(OF_MACOS) # include #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 @@ -82,27 +85,30 @@ andWideArgumentValues: (wchar_t *[])wargv; #endif - (void)of_run; @end +const OFNotificationName OFApplicationDidFinishLaunchingNotification = + @"OFApplicationDidFinishLaunchingNotification"; const OFNotificationName OFApplicationWillTerminateNotification = @"OFApplicationWillTerminateNotification"; static OFApplication *app = nil; static void atexitHandler(void) { id delegate = app.delegate; - - [[OFNotificationCenter defaultCenter] - postNotificationName: OFApplicationWillTerminateNotification + OFNotification *notification = [OFNotification + notificationWithName: OFApplicationWillTerminateNotification object: app]; - if ([delegate respondsToSelector: @selector(applicationWillTerminate)]) - [delegate applicationWillTerminate]; + if ([delegate respondsToSelector: @selector(applicationWillTerminate:)]) + [delegate applicationWillTerminate: notification]; [delegate release]; + + [[OFNotificationCenter defaultCenter] postNotification: notification]; #if defined(OF_HAVE_THREADS) && defined(OF_HAVE_SOCKETS) && \ defined(OF_AMIGAOS) && !defined(OF_MORPHOS) OFSocketDeinit(); #endif @@ -258,13 +264,12 @@ continue; } pos = [tmp rangeOfString: @"="].location; if (pos == OFNotFound) { - fprintf(stderr, - "Warning: Invalid environment " - "variable: %s\n", tmp.UTF8String); + OFLog(@"Warning: Invalid environment " + "variable: %@", tmp); continue; } key = [tmp substringToIndex: pos]; value = [tmp substringFromIndex: pos + 1]; @@ -300,13 +305,12 @@ continue; } pos = [tmp rangeOfString: @"="].location; if (pos == OFNotFound) { - fprintf(stderr, - "Warning: Invalid environment " - "variable: %s\n", tmp.UTF8String); + OFLog(@"Warning: Invalid environment " + "variable: %@", tmp); continue; } key = [tmp substringToIndex: pos]; value = [tmp substringFromIndex: pos + 1]; @@ -394,12 +398,12 @@ void *pool = objc_autoreleasePoolPush(); OFString *key, *value; char *sep; if ((sep = strchr(*env, '=')) == NULL) { - fprintf(stderr, "Warning: Invalid " - "environment variable: %s\n", *env); + OFLog(@"Warning: Invalid environment " + "variable: %s", *env); continue; } key = [OFString stringWithCString: *env @@ -578,10 +582,11 @@ - (void)of_run { void *pool = objc_autoreleasePoolPush(); OFRunLoop *runLoop; + OFNotification *notification; #ifdef OF_HAVE_THREADS [OFThread of_createMainThread]; runLoop = [OFRunLoop currentRunLoop]; #else @@ -597,11 +602,19 @@ * of_setMainRunLoop: retained it. However, we only have a weak * reference to it now, whereas we had a strong reference before. */ pool = objc_autoreleasePoolPush(); - [_delegate applicationDidFinishLaunching]; + + notification = [OFNotification + notificationWithName: OFApplicationDidFinishLaunchingNotification + object: app]; + + [[OFNotificationCenter defaultCenter] postNotification: notification]; + + [_delegate applicationDidFinishLaunching: notification]; + objc_autoreleasePoolPop(pool); [runLoop run]; } @@ -652,11 +665,11 @@ sandbox->_unveiledPathsIndex = unveiledPathsCount; promises = [sandbox.pledgeString cStringWithEncoding: encoding]; if (pledge(promises, NULL) != 0) - @throw [OFSandboxActivationFailedException + @throw [OFActivateSandboxFailedException exceptionWithSandbox: sandbox errNo: errno]; objc_autoreleasePoolPop(pool); @@ -680,11 +693,11 @@ promises = [sandbox.pledgeString cStringWithEncoding: [OFLocale encoding]]; if (pledge(NULL, promises) != 0) - @throw [OFSandboxActivationFailedException + @throw [OFActivateSandboxFailedException exceptionWithSandbox: sandbox errNo: errno]; objc_autoreleasePoolPop(pool); 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 @@ -16,20 +16,17 @@ #include "config.h" #include #include -#include - #import "OFArray.h" #import "OFArray+Private.h" #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" @@ -87,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; } @@ -214,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 { @@ -548,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]; } @@ -687,11 +647,11 @@ [data addItems: child.items count: child.count]; objc_autoreleasePoolPop(pool2); } - assert(i == count); + OFAssert(i == count); [data makeImmutable]; objc_autoreleasePoolPop(pool); @@ -725,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 { @@ -749,10 +719,11 @@ - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { + static unsigned long dummyMutations; OFRange range = OFMakeRange(state->state, count); if (range.length > SIZE_MAX - range.location) @throw [OFOutOfRangeException exception]; @@ -764,11 +735,11 @@ if (range.location + range.length > ULONG_MAX) @throw [OFOutOfRangeException exception]; state->state = (unsigned long)(range.location + range.length); state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *)self; + state->mutationsPtr = &dummyMutations; return (int)range.length; } - (OFEnumerator *)objectEnumerator ADDED src/OFAsyncIPSocketConnector.h Index: src/OFAsyncIPSocketConnector.h ================================================================== --- src/OFAsyncIPSocketConnector.h +++ src/OFAsyncIPSocketConnector.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFDNSResolver.h" +#import "OFRunLoop.h" +#import "OFRunLoop+Private.h" + +OF_ASSUME_NONNULL_BEGIN + +@protocol OFAsyncIPSocketConnecting +- (bool)of_createSocketForAddress: (const OFSocketAddress *)address + errNo: (int *)errNo; +- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address + errNo: (int *)errNo; +- (void)of_closeSocket; +@end + +@interface OFAsyncIPSocketConnector: OFObject +{ + id _socket; + OFString *_host; + uint16_t _port; + id _Nullable _delegate; + id _Nullable _block; + id _Nullable _exception; + OFData *_Nullable _socketAddresses; + size_t _socketAddressesIndex; +} + +- (instancetype)initWithSocket: (id)sock + host: (OFString *)host + port: (uint16_t)port + delegate: (nullable id)delegate + block: (nullable id)block; +- (void)didConnect; +- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode; +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFAsyncIPSocketConnector.m Index: src/OFAsyncIPSocketConnector.m ================================================================== --- src/OFAsyncIPSocketConnector.m +++ src/OFAsyncIPSocketConnector.m @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFAsyncIPSocketConnector.h" +#import "OFData.h" +#import "OFTCPSocket.h" +#import "OFThread.h" +#import "OFTimer.h" + +#import "OFConnectIPSocketFailedException.h" +#import "OFInvalidFormatException.h" + +@implementation OFAsyncIPSocketConnector +- (instancetype)initWithSocket: (id)sock + host: (OFString *)host + port: (uint16_t)port + delegate: (id)delegate + block: (id)block +{ + self = [super init]; + + @try { + _socket = [sock retain]; + _host = [host copy]; + _port = port; + _delegate = [delegate retain]; + _block = [block copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_socket release]; + [_host release]; + [_delegate release]; + [_block release]; + [_exception release]; + [_socketAddresses release]; + + [super dealloc]; +} + +- (void)didConnect +{ + if (_exception == nil) + [_socket setCanBlock: true]; + +#ifdef OF_HAVE_BLOCKS + if (_block != NULL) { + if ([_socket isKindOfClass: [OFTCPSocket class]]) + ((OFTCPSocketAsyncConnectBlock)_block)(_exception); + else + OFEnsure(0); + } else { +#endif + if ([_delegate respondsToSelector: + @selector(socket:didConnectToHost:port:exception:)]) + [_delegate socket: _socket + didConnectToHost: _host + port: _port + exception: _exception]; +#ifdef OF_HAVE_BLOCKS + } +#endif +} + +- (void)of_socketDidConnect: (id)sock exception: (id)exception +{ + if (exception != nil) { + /* + * self might be retained only by the pending async requests, + * which we're about to cancel. + */ + [[self retain] autorelease]; + + [sock cancelAsyncRequests]; + [sock of_closeSocket]; + + if (_socketAddressesIndex >= _socketAddresses.count) { + _exception = [exception retain]; + [self didConnect]; + } else { + /* + * We must not call it before returning, as otherwise + * the new socket would be removed from the queue upon + * return. + */ + OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; + SEL selector = + @selector(tryNextAddressWithRunLoopMode:); + OFTimer *timer = [OFTimer + timerWithTimeInterval: 0 + target: self + selector: selector + object: runLoop.currentMode + repeats: false]; + [runLoop addTimer: timer forMode: runLoop.currentMode]; + } + + return; + } + + [self didConnect]; +} + +- (id)of_connectionFailedExceptionForErrNo: (int)errNo +{ + return [OFConnectIPSocketFailedException exceptionWithHost: _host + port: _port + socket: _socket + errNo: errNo]; +} + +- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode +{ + OFSocketAddress address = *(const OFSocketAddress *) + [_socketAddresses itemAtIndex: _socketAddressesIndex++]; + int errNo; + + OFSocketAddressSetIPPort(&address, _port); + + if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { + if (_socketAddressesIndex >= _socketAddresses.count) { + _exception = [[OFConnectIPSocketFailedException alloc] + initWithHost: _host + port: _port + socket: _socket + errNo: errNo]; + [self didConnect]; + return; + } + + [self tryNextAddressWithRunLoopMode: runLoopMode]; + return; + } + +#if defined(OF_NINTENDO_3DS) || defined(OF_WII) + /* + * On Wii and 3DS, connect() fails if non-blocking is enabled. + * + * Additionally, on Wii, there is no getsockopt(), so it would not be + * possible to get the error (or success) after connecting anyway. + * + * So for now, connecting is blocking on Wii and 3DS. + * + * FIXME: Use a different thread as a work around. + */ + [_socket setCanBlock: true]; +#else + [_socket setCanBlock: false]; +#endif + + if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { +#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII) +# ifdef OF_WINDOWS + if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { +# else + if (errNo == EINPROGRESS) { +# endif + [OFRunLoop of_addAsyncConnectForSocket: _socket + mode: runLoopMode + delegate: self]; + return; + } else { +#endif + [_socket of_closeSocket]; + + if (_socketAddressesIndex >= _socketAddresses.count) { + _exception = [[OFConnectIPSocketFailedException + alloc] initWithHost: _host + port: _port + socket: _socket + errNo: errNo]; + [self didConnect]; + return; + } + + [self tryNextAddressWithRunLoopMode: runLoopMode]; + return; +#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII) + } +#endif + } + +#if defined(OF_NINTENDO_3DS) || defined(OF_WII) + [_socket setCanBlock: false]; +#endif + + [self didConnect]; +} + +- (void)resolver: (OFDNSResolver *)resolver + didResolveHost: (OFString *)host + addresses: (OFData *)addresses + exception: (id)exception +{ + if (exception != nil) { + _exception = [exception retain]; + [self didConnect]; + return; + } + + _socketAddresses = [addresses copy]; + + [self tryNextAddressWithRunLoopMode: + [OFRunLoop currentRunLoop].currentMode]; +} + +- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode +{ + @try { + OFSocketAddress address = OFSocketAddressParseIP(_host, _port); + + _socketAddresses = [[OFData alloc] + initWithItems: &address + count: 1 + itemSize: sizeof(address)]; + + [self tryNextAddressWithRunLoopMode: runLoopMode]; + return; + } @catch (OFInvalidFormatException *e) { + } + + [[OFThread DNSResolver] + asyncResolveAddressesForHost: _host + addressFamily: OFSocketAddressFamilyAny + runLoopMode: runLoopMode + delegate: self]; +} +@end 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 @@ -24,10 +24,11 @@ # import "OFAtomic.h" #endif #ifdef OF_HAVE_THREADS # import "OFPlainMutex.h" #endif +#import "OFString.h" #import "OFAllocFailedException.h" #import "OFInitializationFailedException.h" #if defined(OF_OBJFW_RUNTIME) 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 @@ -44,11 +44,11 @@ * @ref broadcast. * * @note Waiting might have been interrupted by a signal. It is thus recommended * to check the condition again after @ref wait returned! * - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (void)wait; #ifdef OF_AMIGAOS /** @@ -57,11 +57,11 @@ * * @note This is only available on AmigaOS! * * @param signalMask A pointer to a signal mask of Exec Signals to receive. * This is modified and set to the mask of signals received. - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (void)waitForConditionOrExecSignal: (ULONG *)signalMask; #endif /** @@ -71,11 +71,11 @@ * @note Waiting might have been interrupted by a signal. It is thus recommended * to check the condition again after @ref waitForTimeInterval: returned! * * @param timeInterval The time interval until the timeout is reached * @return Whether the condition has been signaled - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (bool)waitForTimeInterval: (OFTimeInterval)timeInterval; #ifdef OF_AMIGAOS /** @@ -86,11 +86,11 @@ * * @param timeInterval The time interval until the timeout is reached * @param signalMask A pointer to a signal mask of Exec Signals to receive. * This is modified and set to the mask of signals received. * @return Whether the condition has been signaled or a signal received - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (bool)waitForTimeInterval: (OFTimeInterval)timeInterval orExecSignal: (ULONG *)signalMask; #endif @@ -101,11 +101,11 @@ * @note Waiting might have been interrupted by a signal. It is thus recommended * to check the condition again after @ref waitUntilDate: returned! * * @param date The date at which the timeout is reached * @return Whether the condition has been signaled - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (bool)waitUntilDate: (OFDate *)date; #ifdef OF_AMIGAOS /** @@ -116,26 +116,26 @@ * * @param date The date at which the timeout is reached * @param signalMask A pointer to a signal mask of Exec Signals to receive. * This is modified and set to the mask of signals received. * @return Whether the condition has been signaled or a signal received - * @throw OFConditionWaitFailedException Waiting for the condition failed + * @throw OFWaitForConditionFailedException Waiting for the condition failed */ - (bool)waitUntilDate: (OFDate *)date orExecSignal: (ULONG *)signalMask; #endif /** * @brief Signals the next waiting thread to continue. * - * @throw OFConditionSignalFailedException Signaling the condition failed + * @throw OFSignalConditionFailedException Signaling the condition failed */ - (void)signal; /** * @brief Signals all threads to continue. * - * @throw OFConditionBroadcastFailedException Broadcasting the condition failed + * @throw OFBroadcastConditionFailedException Broadcasting the condition failed */ - (void)broadcast; @end OF_ASSUME_NONNULL_END 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 @@ -17,16 +17,17 @@ #include #import "OFCondition.h" #import "OFDate.h" +#import "OFString.h" -#import "OFConditionBroadcastFailedException.h" -#import "OFConditionSignalFailedException.h" +#import "OFBroadcastConditionFailedException.h" #import "OFConditionStillWaitingException.h" -#import "OFConditionWaitFailedException.h" #import "OFInitializationFailedException.h" +#import "OFSignalConditionFailedException.h" +#import "OFWaitForConditionFailedException.h" @implementation OFCondition + (instancetype)condition { return [[[self alloc] init] autorelease]; @@ -66,11 +67,11 @@ - (void)wait { int error = OFPlainConditionWait(&_condition, &_mutex); if (error != 0) - @throw [OFConditionWaitFailedException + @throw [OFWaitForConditionFailedException exceptionWithCondition: self errNo: error]; } #ifdef OF_AMIGAOS @@ -78,11 +79,11 @@ { int error = OFPlainConditionWaitOrExecSignal(&_condition, &_mutex, signalMask); if (error != 0) - @throw [OFConditionWaitFailedException + @throw [OFWaitForConditionFailedException exceptionWithCondition: self errNo: error]; } #endif @@ -93,11 +94,11 @@ if (error == ETIMEDOUT) return false; if (error != 0) - @throw [OFConditionWaitFailedException + @throw [OFWaitForConditionFailedException exceptionWithCondition: self errNo: error]; return true; } @@ -111,11 +112,11 @@ if (error == ETIMEDOUT) return false; if (error != 0) - @throw [OFConditionWaitFailedException + @throw [OFWaitForConditionFailedException exceptionWithCondition: self errNo: error]; return true; } @@ -137,20 +138,20 @@ - (void)signal { int error = OFPlainConditionSignal(&_condition); if (error != 0) - @throw [OFConditionSignalFailedException + @throw [OFSignalConditionFailedException exceptionWithCondition: self errNo: error]; } - (void)broadcast { int error = OFPlainConditionBroadcast(&_condition); if (error != 0) - @throw [OFConditionBroadcastFailedException + @throw [OFBroadcastConditionFailedException exceptionWithCondition: self errNo: error]; } @end 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 ADDED src/OFDDPSocket.h Index: src/OFDDPSocket.h ================================================================== --- src/OFDDPSocket.h +++ src/OFDDPSocket.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "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. + */ +@protocol OFDDPSocketDelegate +@end + +/** + * @class OFDDPSocket OFDDPSocket.h ObjFW/OFDDPSocket.h + * + * @brief A class which provides methods to create and use AppleTalk DDP + * sockets. + * + * Addresses are of type @ref OFSocketAddress. You can use + * @ref OFSocketAddressMakeAppleTalk to create an address or + * @ref OFSocketAddressAppleTalkNetwork to get the AppleTalk network, + * @ref OFSocketAddressAppleTalkNode to get the AppleTalk node and + * @ref OFSocketAddressAppleTalkPort to get the port (sometimes also called + * 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 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 + * than one thread at the same time is not thread-safe, even if copy + * was called to create one "instance" for every thread! + */ +@interface OFDDPSocket: OFDatagramSocket +{ +#if !defined(OF_MACOS) && !defined(OF_WINDOWS) + uint8_t _protocolType; +#endif + OF_RESERVE_IVARS(OFDDPSocket, 4) +} + +/** + * @brief The delegate for asynchronous operations on the socket. + * + * @note The delegate is retained for as long as asynchronous operations are + * still ongoing. + */ +@property OF_NULLABLE_PROPERTY (assign, nonatomic) + id delegate; + +/** + * @brief Bind the socket to the specified network, node and port. + * + * @param network The network to bind to. 0 means any. + * @param node The node to bind to. 0 means "this node". + * @param port The port to bind to. 0 means to pick one and return it via the + * returned socket address. + * @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 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 ADDED src/OFDDPSocket.m Index: src/OFDDPSocket.m ================================================================== --- src/OFDDPSocket.m +++ src/OFDDPSocket.m @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 + +#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 "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 + +/* Unfortulately, there is no struct for the following in userland headers */ +struct ATInterfaceConfig { + char interfaceName[16]; + unsigned int flags; + struct at_addr address, router; + unsigned short netStart, netEnd; + at_nvestr_t zoneName; +}; +#endif + +@implementation OFDDPSocket +@dynamic delegate; + +- (OFSocketAddress)bindToNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + protocolType: (uint8_t)protocolType +{ +#ifdef OF_MACOS + const int one = 1; + struct ATInterfaceConfig config = { { 0 } }; +#endif + OFSocketAddress address; +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + int flags; +#endif + + if (protocolType == 0) + @throw [OFInvalidArgumentException exception]; + + if (_socket != OFInvalidSocketHandle) + @throw [OFAlreadyOpenException exceptionWithObject: self]; + + address = OFSocketAddressMakeAppleTalk(network, node, port); + +#if defined(OF_MACOS) + if ((_socket = socket(address.sockaddr.at.sat_family, + SOCK_RAW | SOCK_CLOEXEC, protocolType)) == OFInvalidSocketHandle) +#elif defined(OF_WINDOWS) + if ((_socket = socket(address.sockaddr.at.sat_family, + SOCK_DGRAM | SOCK_CLOEXEC, ATPROTO_BASE + protocolType)) == + OFInvalidSocketHandle) +#else + if ((_socket = socket(address.sockaddr.at.sat_family, + SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) +#endif + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: self + errNo: OFSocketErrNo()]; + + _canBlock = true; + +#if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) + fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); +#endif + + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: self + errNo: errNo]; + } + + memset(&address, 0, sizeof(address)); + address.family = OFSocketAddressFamilyAppleTalk; + address.length = (socklen_t)sizeof(address.sockaddr); + + if (OFGetSockName(_socket, (struct sockaddr *)&address.sockaddr, + &address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: self + errNo: errNo]; + } + + if (address.sockaddr.at.sat_family != AF_APPLETALK) { + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: self + errNo: EAFNOSUPPORT]; + } + +#ifdef OF_MACOS + if (setsockopt(_socket, ATPROTO_NONE, DDP_STRIPHDR, &one, + sizeof(one)) != 0 || ioctl(_socket, _IOWR('a', 2, + struct ATInterfaceConfig), &config) != 0) + @throw [OFBindDDPSocketFailedException + exceptionWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: self + errNo: OFSocketErrNo()]; + + OFSocketAddressSetAppleTalkNetwork(&address, config.address.s_net); + OFSocketAddressSetAppleTalkNode(&address, config.address.s_node); +#endif + +#if !defined(OF_MACOS) && !defined(OF_WINDOWS) + _protocolType = protocolType; +#endif + + return address; +} + +/* + * Everybody but macOS and Windows is probably using a netatalk-compatible + * implementation, which includes the protocol type as the first byte of the + * data instead of considering it part of the header. + * + * The following overrides prepend the protocol type when sending and compare + * and strip it when receiving. + * + * Unfortunately, the downside of this is that the only way to handle receiving + * a packet with the wrong protocol type is to throw an exception with errNo + * ENOMSG, while macOS and Windows just filter those out in the kernel. + * Returning 0 would mean this is indistinguishable from an empty packet, so it + * has to be an exception. + */ +#if !defined(OF_MACOS) && !defined(OF_WINDOWS) +- (size_t)receiveIntoBuffer: (void *)buffer + length: (size_t)length + sender: (OFSocketAddress *)sender +{ + ssize_t ret; + uint8_t protocolType; + struct iovec iov[2] = { + { &protocolType, 1 }, + { buffer, length } + }; + struct msghdr msg = { + .msg_name = (sender != NULL + ? (struct sockaddr *)&sender->sockaddr : NULL), + .msg_namelen = (sender != NULL + ? (socklen_t)sizeof(sender->sockaddr) : 0), + .msg_iov = iov, + .msg_iovlen = 2 + }; + + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((ret = recvmsg(_socket, &msg, 0)) < 0) + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: length + errNo: OFSocketErrNo()]; + + if (ret < 1 || protocolType != _protocolType) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: length + errNo: ENOMSG]; + + if (sender != NULL) { + sender->length = msg.msg_namelen; + sender->family = OFSocketAddressFamilyAppleTalk; + } + + return ret - 1; +} + +- (void)sendBuffer: (const void *)buffer + length: (size_t)length + receiver: (const OFSocketAddress *)receiver +{ + struct iovec iov[2] = { + { &_protocolType, 1 }, + { (void *)buffer, length } + }; + struct msghdr msg = { + .msg_name = (struct sockaddr *)&receiver->sockaddr, + .msg_namelen = receiver->length, + .msg_iov = iov, + .msg_iovlen = 2 + }; + ssize_t bytesWritten; + + if (_socket == OFInvalidSocketHandle) + @throw [OFNotOpenException exceptionWithObject: self]; + + if ((bytesWritten = sendmsg(_socket, &msg, 0)) < 0) + @throw [OFWriteFailedException + exceptionWithObject: self + requestedLength: length + bytesWritten: 0 + errNo: OFSocketErrNo()]; + + if ((size_t)bytesWritten != length + 1) { + bytesWritten--; + + if (bytesWritten < 0) + bytesWritten = 0; + + @throw [OFWriteFailedException exceptionWithObject: self + requestedLength: length + bytesWritten: bytesWritten + errNo: 0]; + } +} +#endif +@end 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]; @@ -908,11 +908,12 @@ return true; if (context->_TCPSocket != nil) { if ([_TCPQueries objectForKey: context->_TCPSocket] != context) return true; - } else if (!OFSocketAddressEqual(sender, &context->_usedNameServer)) + } else if (sender == NULL || + !OFSocketAddressEqual(sender, &context->_usedNameServer)) return true; [context->_cancelTimer invalidate]; [context->_cancelTimer release]; context->_cancelTimer = nil; @@ -945,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 @@ -266,11 +270,12 @@ return; } staticHosts = [OFMutableDictionary dictionary]; - while ((line = [file readLine]) != nil) { + while ((line = + [file readLineWithEncoding: [OFLocale encoding]]) != nil) { OFArray *components, *hosts; size_t pos; OFString *address; pos = [line rangeOfString: @"#"].location; @@ -287,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]; } @@ -340,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 @@ -366,11 +373,12 @@ } if (nameServers == nil) nameServers = [OFMutableArray array]; - while ((line = [file readLine]) != nil) { + while ((line = + [file readLineWithEncoding: [OFLocale encoding]]) != nil) { void *pool2 = objc_autoreleasePoolPush(); size_t pos; OFArray *components, *arguments; OFString *option; @@ -443,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]; } @@ -489,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]; } @@ -598,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. */ @@ -618,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] @@ -173,40 +172,36 @@ #ifdef OF_HAVE_FILES - (instancetype)initWithContentsOfFile: (OFString *)path { char *buffer = NULL; - unsigned long long size; - - @try { - OFFile *file; - - size = [[OFFileManager defaultManager] - attributesOfItemAtPath: path].fileSize; - -# if ULLONG_MAX > SIZE_MAX - if (size > SIZE_MAX) - @throw [OFOutOfRangeException exception]; -# endif - - buffer = OFAllocMemory((size_t)size, 1); - file = [[OFFile alloc] initWithPath: path mode: @"r"]; - @try { - [file readIntoBuffer: buffer exactLength: (size_t)size]; - } @finally { - [file release]; - } + OFStreamOffset fileSize; + + @try { + void *pool = objc_autoreleasePoolPush(); + OFFile *file = [OFFile fileWithPath: path mode: @"r"]; + fileSize = [file seekToOffset: 0 whence: OFSeekEnd]; + + if (fileSize < 0 || (unsigned long long)fileSize > SIZE_MAX) + @throw [OFOutOfRangeException exception]; + + [file seekToOffset: 0 whence: OFSeekSet]; + + buffer = OFAllocMemory((size_t)fileSize, 1); + [file readIntoBuffer: buffer exactLength: (size_t)fileSize]; + + objc_autoreleasePoolPop(pool); } @catch (id e) { OFFreeMemory(buffer); [self release]; @throw e; } @try { self = [self initWithItemsNoCopy: buffer - count: (size_t)size + count: (size_t)fileSize freeWhenDone: true]; } @catch (id e) { OFFreeMemory(buffer); @throw e; } @@ -213,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; @@ -336,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 { @@ -589,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 @@ -158,11 +158,11 @@ * @throw OFReadFailedException Receiving failed * @throw OFNotOpenException The socket is not open */ - (size_t)receiveIntoBuffer: (void *)buffer length: (size_t)length - sender: (OFSocketAddress *)sender; + sender: (nullable OFSocketAddress *)sender; /** * @brief Asynchronously receives a datagram and stores it into the specified * buffer. * 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 @@ -171,53 +171,68 @@ ssize_t ret; if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; - sender->length = (socklen_t)sizeof(sender->sockaddr); + if (sender != NULL) + sender->length = (socklen_t)sizeof(sender->sockaddr); #ifndef OF_WINDOWS if ((ret = recvfrom(_socket, buffer, length, 0, - (struct sockaddr *)&sender->sockaddr, &sender->length)) < 0) + (sender != NULL ? (struct sockaddr *)&sender->sockaddr : NULL), + (sender != NULL ? &sender->length : NULL))) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: OFSocketErrNo()]; #else if (length > INT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = recvfrom(_socket, buffer, (int)length, 0, - (struct sockaddr *)&sender->sockaddr, &sender->length)) < 0) + (sender != NULL ? (struct sockaddr *)&sender->sockaddr : NULL), + (sender != NULL ? &sender->length : NULL))) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: OFSocketErrNo()]; #endif - switch (((struct sockaddr *)&sender->sockaddr)->sa_family) { - case AF_INET: - sender->family = OFSocketAddressFamilyIPv4; - break; + if (sender != NULL) { + struct sockaddr *sa = (struct sockaddr *)&sender->sockaddr; + + if (sender->length >= (socklen_t)sizeof(sa->sa_family)) { + switch (sa->sa_family) { + case AF_INET: + sender->family = OFSocketAddressFamilyIPv4; + break; #ifdef OF_HAVE_IPV6 - case AF_INET6: - sender->family = OFSocketAddressFamilyIPv6; - break; + case AF_INET6: + sender->family = OFSocketAddressFamilyIPv6; + break; #endif #ifdef OF_HAVE_UNIX_SOCKETS - case AF_UNIX: - sender->family = OFSocketAddressFamilyUNIX; - break; + case AF_UNIX: + sender->family = OFSocketAddressFamilyUNIX; + break; #endif #ifdef OF_HAVE_IPX - case AF_IPX: - sender->family = OFSocketAddressFamilyIPX; - break; + case AF_IPX: + sender->family = OFSocketAddressFamilyIPX; + break; +#endif +#ifdef OF_HAVE_APPLETALK + case AF_APPLETALK: + sender->family = OFSocketAddressFamilyAppleTalk; + break; #endif - default: - sender->family = OFSocketAddressFamilyUnknown; - break; + default: + sender->family = OFSocketAddressFamilyUnknown; + break; + } + } else + sender->family = OFSocketAddressFamilyUnknown; } return ret; } 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 @@ -15,31 +15,26 @@ #include "config.h" #include -#include - #import "OFDictionary.h" #import "OFArray.h" #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 @@ -55,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]; } @@ -113,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; } @@ -137,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 { @@ -330,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 { @@ -510,10 +429,11 @@ - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { + static unsigned long dummyMutations; OFEnumerator *enumerator; int i; memcpy(&enumerator, state->extra, sizeof(enumerator)); @@ -521,11 +441,11 @@ enumerator = [self keyEnumerator]; memcpy(state->extra, &enumerator, sizeof(enumerator)); } state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *)self; + state->mutationsPtr = &dummyMutations; for (i = 0; i < count; i++) { id object = [enumerator nextObject]; if (object == nil) @@ -637,54 +557,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]; } @@ -824,11 +700,11 @@ [data addItems: child.items count: child.count]; objc_autoreleasePoolPop(pool2); } - assert(i == count); + OFAssert(i == count); [data makeImmutable]; objc_autoreleasePoolPop(pool); 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,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 OFEmbeddedURIHandler: OFURIHandler -@end - -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 { - const char *name; - 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(const char *name, 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].name = name; - 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 -{ - const char *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.UTF8String) == NULL) { - @throw [OFInvalidArgumentException exception]; - } - -#ifdef OF_HAVE_THREADS - OFEnsure(OFPlainMutexLock(&mutex) == 0); - @try { -#endif - for (size_t i = 0; i < numEmbeddedFiles; i++) { - if (strcmp(embeddedFiles[i].name, path) != 0) - 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 @@ -59,14 +59,15 @@ - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { + static unsigned long dummyMutations; int i; state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *)self; + state->mutationsPtr = &dummyMutations; for (i = 0; i < count; i++) { id object = [self nextObject]; if (object == nil) 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 @@ -13,11 +13,10 @@ * file. */ #include "config.h" -#include #include #ifdef HAVE_FCNTL_H # include #endif 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,13 +13,14 @@ * file. */ #include "config.h" -#define _LARGEFILE64_SOURCE +#ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +#endif -#include #include #ifdef HAVE_FCNTL_H # include #endif @@ -31,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" @@ -48,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 @@ -19,30 +19,34 @@ #include #include #include "unistd_wrapper.h" -#import "platform.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" - -#import "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 != nil) - 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 DELETED src/OFIPSocketAsyncConnector.h Index: src/OFIPSocketAsyncConnector.h ================================================================== --- src/OFIPSocketAsyncConnector.h +++ src/OFIPSocketAsyncConnector.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 "OFDNSResolver.h" -#import "OFRunLoop.h" -#import "OFRunLoop+Private.h" - -OF_ASSUME_NONNULL_BEGIN - -@protocol OFIPSocketAsyncConnecting -- (bool)of_createSocketForAddress: (const OFSocketAddress *)address - errNo: (int *)errNo; -- (bool)of_connectSocketToAddress: (const OFSocketAddress *)address - errNo: (int *)errNo; -- (void)of_closeSocket; -@end - -@interface OFIPSocketAsyncConnector: OFObject -{ - id _socket; - OFString *_host; - uint16_t _port; - id _Nullable _delegate; - id _Nullable _block; - id _Nullable _exception; - OFData *_Nullable _socketAddresses; - size_t _socketAddressesIndex; -} - -- (instancetype)initWithSocket: (id)sock - host: (OFString *)host - port: (uint16_t)port - delegate: (nullable id)delegate - block: (nullable id)block; -- (void)didConnect; -- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode; -- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFIPSocketAsyncConnector.m Index: src/OFIPSocketAsyncConnector.m ================================================================== --- src/OFIPSocketAsyncConnector.m +++ src/OFIPSocketAsyncConnector.m @@ -1,251 +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 "OFIPSocketAsyncConnector.h" -#import "OFData.h" -#import "OFTCPSocket.h" -#import "OFThread.h" -#import "OFTimer.h" - -#import "OFConnectionFailedException.h" -#import "OFInvalidFormatException.h" - -@implementation OFIPSocketAsyncConnector -- (instancetype)initWithSocket: (id)sock - host: (OFString *)host - port: (uint16_t)port - delegate: (id)delegate - block: (id)block -{ - self = [super init]; - - @try { - _socket = [sock retain]; - _host = [host copy]; - _port = port; - _delegate = [delegate retain]; - _block = [block copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_socket release]; - [_host release]; - [_delegate release]; - [_block release]; - [_exception release]; - [_socketAddresses release]; - - [super dealloc]; -} - -- (void)didConnect -{ - if (_exception == nil) - [_socket setCanBlock: true]; - -#ifdef OF_HAVE_BLOCKS - if (_block != NULL) { - if ([_socket isKindOfClass: [OFTCPSocket class]]) - ((OFTCPSocketAsyncConnectBlock)_block)(_exception); - else - OFEnsure(0); - } else { -#endif - if ([_delegate respondsToSelector: - @selector(socket:didConnectToHost:port:exception:)]) - [_delegate socket: _socket - didConnectToHost: _host - port: _port - exception: _exception]; -#ifdef OF_HAVE_BLOCKS - } -#endif -} - -- (void)of_socketDidConnect: (id)sock exception: (id)exception -{ - if (exception != nil) { - /* - * self might be retained only by the pending async requests, - * which we're about to cancel. - */ - [[self retain] autorelease]; - - [sock cancelAsyncRequests]; - [sock of_closeSocket]; - - if (_socketAddressesIndex >= _socketAddresses.count) { - _exception = [exception retain]; - [self didConnect]; - } else { - /* - * We must not call it before returning, as otherwise - * the new socket would be removed from the queue upon - * return. - */ - OFRunLoop *runLoop = [OFRunLoop currentRunLoop]; - SEL selector = - @selector(tryNextAddressWithRunLoopMode:); - OFTimer *timer = [OFTimer - timerWithTimeInterval: 0 - target: self - selector: selector - object: runLoop.currentMode - repeats: false]; - [runLoop addTimer: timer forMode: runLoop.currentMode]; - } - - return; - } - - [self didConnect]; -} - -- (id)of_connectionFailedExceptionForErrNo: (int)errNo -{ - return [OFConnectionFailedException exceptionWithHost: _host - port: _port - socket: _socket - errNo: errNo]; -} - -- (void)tryNextAddressWithRunLoopMode: (OFRunLoopMode)runLoopMode -{ - OFSocketAddress address = *(const OFSocketAddress *) - [_socketAddresses itemAtIndex: _socketAddressesIndex++]; - int errNo; - - OFSocketAddressSetPort(&address, _port); - - if (![_socket of_createSocketForAddress: &address errNo: &errNo]) { - if (_socketAddressesIndex >= _socketAddresses.count) { - _exception = [[OFConnectionFailedException alloc] - initWithHost: _host - port: _port - socket: _socket - errNo: errNo]; - [self didConnect]; - return; - } - - [self tryNextAddressWithRunLoopMode: runLoopMode]; - return; - } - -#if defined(OF_NINTENDO_3DS) || defined(OF_WII) - /* - * On Wii and 3DS, connect() fails if non-blocking is enabled. - * - * Additionally, on Wii, there is no getsockopt(), so it would not be - * possible to get the error (or success) after connecting anyway. - * - * So for now, connecting is blocking on Wii and 3DS. - * - * FIXME: Use a different thread as a work around. - */ - [_socket setCanBlock: true]; -#else - [_socket setCanBlock: false]; -#endif - - if (![_socket of_connectSocketToAddress: &address errNo: &errNo]) { -#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII) -# ifdef OF_WINDOWS - if (errNo == EINPROGRESS || errNo == EWOULDBLOCK) { -# else - if (errNo == EINPROGRESS) { -# endif - [OFRunLoop of_addAsyncConnectForSocket: _socket - mode: runLoopMode - delegate: self]; - return; - } else { -#endif - [_socket of_closeSocket]; - - if (_socketAddressesIndex >= _socketAddresses.count) { - _exception = [[OFConnectionFailedException - alloc] initWithHost: _host - port: _port - socket: _socket - errNo: errNo]; - [self didConnect]; - return; - } - - [self tryNextAddressWithRunLoopMode: runLoopMode]; - return; -#if !defined(OF_NINTENDO_3DS) && !defined(OF_WII) - } -#endif - } - -#if defined(OF_NINTENDO_3DS) || defined(OF_WII) - [_socket setCanBlock: false]; -#endif - - [self didConnect]; -} - -- (void)resolver: (OFDNSResolver *)resolver - didResolveHost: (OFString *)host - addresses: (OFData *)addresses - exception: (id)exception -{ - if (exception != nil) { - _exception = [exception retain]; - [self didConnect]; - return; - } - - _socketAddresses = [addresses copy]; - - [self tryNextAddressWithRunLoopMode: - [OFRunLoop currentRunLoop].currentMode]; -} - -- (void)startWithRunLoopMode: (OFRunLoopMode)runLoopMode -{ - @try { - OFSocketAddress address = OFSocketAddressParseIP(_host, _port); - - _socketAddresses = [[OFData alloc] - initWithItems: &address - count: 1 - itemSize: sizeof(address)]; - - [self tryNextAddressWithRunLoopMode: runLoopMode]; - return; - } @catch (OFInvalidFormatException *e) { - } - - [[OFThread DNSResolver] - asyncResolveAddressesForHost: _host - addressFamily: OFSocketAddressFamilyAny - runLoopMode: runLoopMode - delegate: self]; -} -@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,12 +33,12 @@ * @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 OFSocketAddressPort to get the port (sometimes also called + * @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. * This is so that the socket can be used as a key for a dictionary, @@ -65,16 +65,23 @@ /** * @brief Bind the socket to the specified network, node and port with the * specified packet type. * + * @param network The IPX network to bind to. 0 means the current network. + * @param node The IPX network to bind to. An all zero node means the + * computer's node. * @param port The port (sometimes called socket number) to bind to. 0 means to - * pick one and return it. + * 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 OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @throw OFBindIPXSocketFailedException Binding failed + * @throw OFAlreadyOpenException The socket is already bound */ -- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType; +- (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,43 +23,51 @@ #import "OFIPXSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindIPXSocketFailedException.h" + +#ifndef NSPROTO_IPX +# define NSPROTO_IPX 0 +#endif @implementation OFIPXSocket @dynamic delegate; -- (OFSocketAddress)bindToPort: (uint16_t)port packetType: (uint8_t)packetType +- (OFSocketAddress)bindToNetwork: (uint32_t)network + node: (const unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + packetType: (uint8_t)packetType { - const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; OFSocketAddress address; int protocol = 0; #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(0, zeroNode, port); + 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 if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_DGRAM | SOCK_CLOEXEC, protocol)) == OFInvalidSocketHandle) - @throw [OFBindFailedException - exceptionWithPort: port - packetType: packetType - socket: self - errNo: OFSocketErrNo()]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: packetType + socket: self + errNo: OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -71,14 +79,17 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: packetType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: packetType + socket: self + errNo: errNo]; } memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); @@ -88,30 +99,36 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: packetType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: packetType + socket: self + errNo: errNo]; } if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: packetType - socket: self - errNo: EAFNOSUPPORT]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: packetType + socket: self + errNo: EAFNOSUPPORT]; } 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 @@ -16,12 +16,10 @@ #include "config.h" #include #include -#include - #ifndef OF_INFLATE64_STREAM_M # import "OFInflateStream.h" #else # import "OFInflate64Stream.h" # define OFInflateStream OFInflate64Stream @@ -105,11 +103,11 @@ static OF_INLINE bool tryReadBits(OFInflateStream *stream, uint16_t *bits, uint8_t count) { uint16_t ret = stream->_savedBits; - assert(stream->_savedBitsLength < count); + OFAssert(stream->_savedBitsLength < count); for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) { if OF_UNLIKELY (stream->_bitIndex == 8) { if OF_LIKELY (stream->_bufferIndex < stream->_bufferLength) 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 @@ -13,11 +13,10 @@ * file. */ #include "config.h" -#include #include #ifdef HAVE_FCNTL_H # include #endif @@ -186,11 +185,11 @@ errNo: (int)eventList[i].data]; if (eventList[i].ident == (uintptr_t)_cancelFD[0]) { char buffer; - assert(eventList[i].filter == EVFILT_READ); + OFAssert(eventList[i].filter == EVFILT_READ); OFEnsure(read(_cancelFD[0], &buffer, 1) == 1); continue; } @@ -208,12 +207,12 @@ @selector(objectIsReadyForWriting:)]) [_delegate objectIsReadyForWriting: (id)eventList[i].udata]; break; default: - assert(0); + OFAssert(0); } objc_autoreleasePoolPop(pool); } } @end 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. @@ -44,20 +44,10 @@ /** * @brief The encoding to use for the archive. Defaults to ISO 8859-1. */ @property (nonatomic) OFStringEncoding encoding; -/** - * @brief A stream for reading the current entry. - * - * @note This is only available in read mode. - * - * @note The returned stream conforms to @ref OFReadyForReadingObserving if the - * underlying stream does so, too. - */ -@property (readonly, nonatomic) OFStream *streamForReadingCurrentEntry; - /** * @brief Creates a new OFLHAArchive object with the specified stream. * * @param stream A stream from which the LHA archive will be read. * For read and append mode, this needs to be an OFSeekableStream. @@ -69,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 @@ -108,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. * @@ -137,10 +127,22 @@ * unsupported version * @throw OFTruncatedDataException The archive was truncated */ - (nullable OFLHAArchiveEntry *)nextEntry; +/** + * @brief Returns a stream for reading the current entry. + * + * @note This is only available in read mode. + * + * @note The returned stream conforms to @ref OFReadyForReadingObserving if the + * underlying stream does so, too. + * + * @return A stream for reading the current entry + */ +- (OFStream *)streamForReadingCurrentEntry; + /** * @brief Returns a stream for writing the specified entry. * * @note This is only available in write and append mode. * @@ -161,10 +163,12 @@ */ - (OFStream *)streamForWritingEntry: (OFLHAArchiveEntry *)entry; /** * @brief Closes the OFLHAArchive. + * + * @throw OFNotOpenException The archive is not open */ - (void)close; @end OF_ASSUME_NONNULL_END 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 @@ -13,12 +13,10 @@ * file. */ #include "config.h" -#include - #import "OFLHADecompressingStream.h" #import "OFKernelEventObserver.h" #import "OFHuffmanTree.h" @@ -48,11 +46,11 @@ static OF_INLINE bool tryReadBits(OFLHADecompressingStream *stream, uint16_t *bits, uint8_t count) { uint16_t ret = stream->_savedBits; - assert(stream->_savedBitsLength < count); + OFAssert(stream->_savedBitsLength < count); for (uint_fast8_t i = stream->_savedBitsLength; i < count; i++) { if OF_UNLIKELY (stream->_bitIndex == 8) { if OF_LIKELY (stream->_bufferIndex < stream->_bufferLength) 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 @@ -14,15 +14,13 @@ */ #include "config.h" #include -#include #import "OFList.h" #import "OFString.h" -#import "OFXMLElement.h" #import "OFArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" @@ -68,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) { @@ -254,11 +223,11 @@ iter = iter->next, iter2 = iter2->next) if (![iter->object isEqual: iter2->object]) return false; /* One is bigger than the other even though we checked the count */ - assert(iter == NULL && iter2 == NULL); + OFAssert(iter == NULL && iter2 == NULL); return true; } - (bool)containsObject: (id)object @@ -372,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 @@ -72,11 +72,11 @@ @interface OFMapTable: OFObject { OFMapTableFunctions _keyFunctions, _objectFunctions; struct OFMapTableBucket *_Nonnull *_Nullable _buckets; uint32_t _count, _capacity; - unsigned char _rotate; + unsigned char _rotation; unsigned long _mutations; } /** * @brief The key functions used by the map table. 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 @@ -18,12 +18,10 @@ #include "config.h" #include #include -#include - #import "OFMapTable.h" #import "OFMapTable+Private.h" #import "OFEnumerator.h" #import "OFEnumerationMutationException.h" @@ -157,11 +155,11 @@ _capacity = minCapacity; _buckets = OFAllocZeroedMemory(_capacity, sizeof(*_buckets)); if (OFHashSeed != 0) - _rotate = OFRandom16() & 31; + _rotation = OFRandom16() & 31; } @catch (id e) { [self release]; @throw e; } @@ -187,10 +185,11 @@ static void resizeForCount(OFMapTable *self, uint32_t count) { uint32_t fullness, capacity; struct OFMapTableBucket **buckets; + unsigned char newRotation; if (count > UINT32_MAX / sizeof(*self->_buckets) || count > UINT32_MAX / 8) @throw [OFOutOfRangeException exception]; @@ -213,24 +212,27 @@ if ((capacity < self->_capacity && count > self->_count) || capacity < minCapacity) return; buckets = OFAllocZeroedMemory(capacity, sizeof(*buckets)); + newRotation = (OFHashSeed != 0 ? OFRandom16() & 31 : 0); for (uint32_t i = 0; i < self->_capacity; i++) { if (self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket) { - uint32_t j, last; + uint32_t rotatedHash, j, last; + rotatedHash = OFRotateLeft(self->_buckets[i]->hash, + newRotation); last = capacity; - for (j = self->_buckets[i]->hash & (capacity - 1); + for (j = rotatedHash & (capacity - 1); j < last && buckets[j] != NULL; j++); /* In case the last bucket is already used */ if (j >= last) { - last = self->_buckets[i]->hash & (capacity - 1); + last = rotatedHash & (capacity - 1); for (j = 0; j < last && buckets[j] != NULL; j++); } @@ -242,25 +244,26 @@ } OFFreeMemory(self->_buckets); self->_buckets = buckets; self->_capacity = capacity; + self->_rotation = newRotation; } static void setObject(OFMapTable *restrict self, void *key, void *object, uint32_t hash) { - uint32_t i, last; + uint32_t rotatedHash, i, last; void *old; if (key == NULL || object == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft(hash, self->_rotate); + rotatedHash = OFRotateLeft(hash, self->_rotation); last = self->_capacity; - for (i = hash & (self->_capacity - 1); + for (i = rotatedHash & (self->_capacity - 1); i < last && self->_buckets[i] != NULL; i++) { if (self->_buckets[i] == &deletedBucket) continue; if (self->_keyFunctions.equal(self->_buckets[i]->key, key)) @@ -267,11 +270,11 @@ break; } /* In case the last bucket is already used */ if (i >= last) { - last = hash & (self->_capacity - 1); + last = rotatedHash & (self->_capacity - 1); for (i = 0; i < last && self->_buckets[i] != NULL; i++) { if (self->_buckets[i] == &deletedBucket) continue; @@ -286,21 +289,23 @@ self->_buckets[i] == &deletedBucket || !self->_keyFunctions.equal(self->_buckets[i]->key, key)) { struct OFMapTableBucket *bucket; resizeForCount(self, self->_count + 1); + /* Resizing can change the rotation */ + rotatedHash = OFRotateLeft(hash, self->_rotation); self->_mutations++; last = self->_capacity; - for (i = hash & (self->_capacity - 1); i < last && + for (i = rotatedHash & (self->_capacity - 1); i < last && self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket; i++); /* In case the last bucket is already used */ if (i >= last) { - last = hash & (self->_capacity - 1); + last = rotatedHash & (self->_capacity - 1); for (i = 0; i < last && self->_buckets[i] != NULL && self->_buckets[i] != &deletedBucket; i++); } @@ -372,11 +377,11 @@ { unsigned long hash = 0; for (unsigned long i = 0; i < _capacity; i++) { if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) { - hash ^= OFRotateRight(_buckets[i]->hash, _rotate); + hash ^= _buckets[i]->hash; hash ^= _objectFunctions.hash(_buckets[i]->object); } } return hash; @@ -392,12 +397,11 @@ @try { for (uint32_t i = 0; i < _capacity; i++) if (_buckets[i] != NULL && _buckets[i] != &deletedBucket) setObject(copy, _buckets[i]->key, - _buckets[i]->object, - OFRotateRight(_buckets[i]->hash, _rotate)); + _buckets[i]->object, _buckets[i]->hash); } @catch (id e) { [copy release]; @throw e; } @@ -409,19 +413,21 @@ return _count; } - (void *)objectForKey: (void *)key { - uint32_t i, hash, last; + uint32_t i, rotatedHash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); + rotatedHash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), + _rotation); last = _capacity; - for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { + for (i = rotatedHash & (_capacity - 1); + i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) return _buckets[i]->object; @@ -429,11 +435,11 @@ if (i < last) return nil; /* In case the last bucket is already used */ - last = hash & (_capacity - 1); + last = rotatedHash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -449,19 +455,21 @@ setObject(self, key, object, (uint32_t)_keyFunctions.hash(key)); } - (void)removeObjectForKey: (void *)key { - uint32_t i, hash, last; + uint32_t i, rotatedHash, last; if (key == NULL) @throw [OFInvalidArgumentException exception]; - hash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), _rotate); + rotatedHash = OFRotateLeft((uint32_t)_keyFunctions.hash(key), + _rotation); last = _capacity; - for (i = hash & (_capacity - 1); i < last && _buckets[i] != NULL; i++) { + for (i = rotatedHash & (_capacity - 1); + i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; if (_keyFunctions.equal(_buckets[i]->key, key)) { _mutations++; @@ -481,11 +489,11 @@ if (i < last) return; /* In case the last bucket is already used */ - last = hash & (_capacity - 1); + last = rotatedHash & (_capacity - 1); for (i = 0; i < last && _buckets[i] != NULL; i++) { if (_buckets[i] == &deletedBucket) continue; @@ -525,15 +533,15 @@ _count = 0; _capacity = minCapacity; _buckets = OFResizeMemory(_buckets, _capacity, sizeof(*_buckets)); /* - * Get a new random value for _rotate, so that it is not less secure + * Get a new random value for _rotation, so that it is not less secure * than creating a new hash map. */ if (OFHashSeed != 0) - _rotate = OFRandom16() & 31; + _rotation = OFRandom16() & 31; } - (bool)containsObject: (void *)object { if (object == NULL || _count == 0) 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 @@ -13,19 +13,16 @@ * file. */ #include "config.h" -#include - #import "OFMapTableDictionary.h" #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" @@ -230,63 +227,10 @@ } 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 { [_mapTable release]; [super dealloc]; @@ -344,11 +288,11 @@ size_t i; i = 0; enumerator = [_mapTable keyEnumerator]; while ((keyPtr = [enumerator nextObject]) != NULL) { - assert(i < count); + OFAssert(i < count); keys[i++] = (id)*keyPtr; } objc_autoreleasePoolPop(pool); @@ -377,11 +321,11 @@ size_t i; i = 0; enumerator = [_mapTable objectEnumerator]; while ((objectPtr = [enumerator nextObject]) != NULL) { - assert(i < count); + OFAssert(i < count); objects[i++] = (id)*objectPtr; } objc_autoreleasePoolPop(pool); 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 @@ -13,15 +13,15 @@ * file. */ #include "config.h" -#include #include #import "OFMethodSignature.h" #import "OFData.h" +#import "OFString.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @@ -34,11 +34,11 @@ static size_t alignmentOfArray(const char **type, size_t *length) { size_t alignment; - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; while (*length > 0 && OFASCIIIsDigit(**type)) { @@ -63,11 +63,11 @@ size_t alignment = 0; #if defined(OF_POWERPC) && defined(OF_MACOS) bool first = true; #endif - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; /* Skip name */ @@ -109,11 +109,11 @@ static size_t alignmentOfUnion(const char **type, size_t *length) { size_t alignment = 0; - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; /* Skip name */ @@ -144,10 +144,15 @@ return alignment; } 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 alignmentOfEncoding(const char **type, size_t *length, bool inStruct) { size_t alignment; if (*length == 0) @@ -286,11 +291,11 @@ sizeOfArray(const char **type, size_t *length) { size_t count = 0; size_t size; - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; while (*length > 0 && OFASCIIIsDigit(**type)) { @@ -326,11 +331,11 @@ size_t alignment = alignmentOfStruct(&typeCopy, &lengthCopy); #if defined(OF_POWERPC) && defined(OF_MACOS) bool first = true; #endif - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; /* Skip name */ @@ -399,11 +404,11 @@ static size_t sizeOfUnion(const char **type, size_t *length) { size_t size = 0; - assert(*length > 0); + OFAssert(*length > 0); (*type)++; (*length)--; /* Skip name */ @@ -434,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 @@ -16,12 +16,10 @@ #include "config.h" #include #include -#include - #import "OFMutableArray.h" #import "OFMutableAdjacentArray.h" #import "OFEnumerationMutationException.h" #import "OFInvalidArgumentException.h" @@ -32,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; @@ -63,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]; @@ -180,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; } @@ -413,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 @@ -15,14 +15,13 @@ #include "config.h" #include -#include - #import "OFMutableSet.h" #import "OFMutableMapTableSet.h" +#import "OFString.h" static struct { Class isa; } placeholder; @@ -68,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]; } @@ -172,11 +165,11 @@ @try { size_t i; i = 0; for (id object in self) { - assert(i < count); + OFAssert(i < count); cArray[i++] = object; } for (i = 0; i < count; i++) if (![set containsObject: cArray[i]]) 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 @@ -24,10 +24,15 @@ @implementation OFMutableTarArchiveEntry @dynamic fileName, POSIXPermissions, ownerAccountID, groupOwnerAccountID; @dynamic compressedSize, uncompressedSize, modificationDate, type; @dynamic targetFileName, ownerAccountName, groupOwnerAccountName, deviceMajor; @dynamic deviceMinor; +/* + * The following is optional in OFMutableArchiveEntry, but Apple GCC 4.0.1 is + * buggy and needs this to stop complaining. + */ +@dynamic fileComment; + (instancetype)entryWithFileName: (OFString *)fileName { return [[[self alloc] initWithFileName: fileName] autorelease]; } 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 @@ -16,11 +16,10 @@ #include "config.h" #include #include #include -#include #import "OFMutableUTF8String.h" #import "OFASPrintF.h" #import "OFString.h" #import "OFUTF8String.h" @@ -77,11 +76,11 @@ if (!_s->isUTF8) { uint8_t t; const OFUnichar *const *table; - assert(startTableSize >= 1 && middleTableSize >= 1); + OFAssert(startTableSize >= 1 && middleTableSize >= 1); _s->hasHash = false; for (i = 0; i < _s->cStringLength; i++) { if (isStart) @@ -171,11 +170,11 @@ @throw [OFInvalidEncodingException exception]; } j += d; } - assert(j == newCStringLength); + OFAssert(j == newCStringLength); newCString[j] = 0; OFFreeMemory(unicodeString); OFFreeMemory(_s->cString); _s->hasHash = false; 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 @@ -27,10 +27,16 @@ @implementation OFMutableZIPArchiveEntry @dynamic fileName, fileComment, extraField, versionMadeBy, minVersionNeeded; @dynamic modificationDate, compressionMethod, compressedSize, uncompressedSize; @dynamic CRC32, versionSpecificAttributes, generalPurposeBitFlag; @dynamic of_localFileHeaderOffset; +/* + * The following are optional in OFMutableArchiveEntry, but Apple GCC 4.0.1 is + * buggy and needs this to stop complaining. + */ +@dynamic POSIXPermissions, ownerAccountID, groupOwnerAccountID; +@dynamic ownerAccountName, groupOwnerAccountName; + (instancetype)entryWithFileName: (OFString *)fileName { return [[[self alloc] initWithFileName: fileName] autorelease]; } 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 */ @@ -1363,10 +1477,17 @@ #endif extern id OFAllocObject(Class class_, size_t extraSize, size_t extraAlignment, void *_Nullable *_Nullable extra); extern void OF_NO_RETURN_FUNC OFMethodNotFound(id self, SEL _cmd); +/** + * @brief Initializes the specified hash. + * + * @param hash A pointer to the hash to initialize + */ +extern void OFHashInit(unsigned long *_Nonnull hash); + /** * @brief Returns 16 bit or non-cryptographical randomness. * * @return 16 bit or non-cryptographical randomness */ @@ -1383,17 +1504,10 @@ * @brief Returns 64 bit or non-cryptographical randomness. * * @return 64 bit or non-cryptographical randomness */ extern uint64_t OFRandom64(void); - -/** - * @brief Initializes the specified hash. - * - * @param hash A pointer to the hash to initialize - */ -extern void OFHashInit(unsigned long *_Nonnull hash); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END @@ -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 @@ -18,12 +18,10 @@ #include #include #include #include "unistd_wrapper.h" -#include - #ifdef OF_APPLE_RUNTIME # include #endif #ifdef HAVE_GETRANDOM @@ -39,10 +37,11 @@ #import "OFMethodSignature.h" #import "OFRunLoop.h" #if !defined(OF_HAVE_ATOMIC_OPS) && defined(OF_HAVE_THREADS) # import "OFPlainMutex.h" /* For OFSpinlock */ #endif +#import "OFStdIOStream.h" #import "OFString.h" #import "OFThread.h" #import "OFTimer.h" #import "OFValue.h" @@ -63,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 @@ -250,17 +251,16 @@ #if !defined(OF_APPLE_RUNTIME) || defined(__OBJC2__) static void uncaughtExceptionHandler(id exception) { - OFString *description = [exception description]; OFArray OF_GENERIC(OFValue *) *stackTraceAddresses = nil; OFArray OF_GENERIC(OFString *) *stackTraceSymbols = nil; OFStringEncoding encoding = [OFLocale encoding]; - fprintf(stderr, "\nRuntime error: Unhandled exception:\n%s\n", - [description cStringWithEncoding: encoding]); + OFLog(@"Runtime error: Unhandled exception:"); + OFLog(@"%@", exception); if ([exception respondsToSelector: @selector(stackTraceAddresses)]) stackTraceAddresses = [exception stackTraceAddresses]; if (stackTraceAddresses != nil) { @@ -271,32 +271,31 @@ stackTraceSymbols = [exception stackTraceSymbols]; if (stackTraceSymbols.count != count) stackTraceSymbols = nil; - fputs("\nStack trace:\n", stderr); + OFLog(@""); + OFLog(@"Stack trace:"); if (stackTraceSymbols != nil) { for (size_t i = 0; i < count; i++) { void *address = [[stackTraceAddresses objectAtIndex: i] pointerValue]; const char *symbol = [[stackTraceSymbols objectAtIndex: i] cStringWithEncoding: encoding]; - fprintf(stderr, " %p %s\n", address, symbol); + OFLog(@" %p %s", address, symbol); } } else { for (size_t i = 0; i < count; i++) { void *address = [[stackTraceAddresses objectAtIndex: i] pointerValue]; - fprintf(stderr, " %p\n", address); + OFLog(@" %p", address); } } - - fputs("\n", stderr); } abort(); } #endif @@ -386,11 +385,10 @@ /* References for static linking */ void _references_to_categories_of_OFObject(void) { _OFObject_KeyValueCoding_reference = 1; - _OFObject_Serialization_reference = 1; } @implementation OFObject + (void)load { @@ -438,15 +436,10 @@ + (instancetype)alloc { return OFAllocObject(self, 0, 0, NULL); } -+ (instancetype)new -{ - return [[self alloc] init]; -} - + (Class)class { return self; } @@ -475,14 +468,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; } @@ -580,16 +571,16 @@ [self inheritMethodsFromClass: superclass]; } + (bool)resolveClassMethod: (SEL)selector { - return NO; + return false; } + (bool)resolveInstanceMethod: (SEL)selector { - return NO; + return false; } - (instancetype)init { return self; @@ -1169,11 +1160,11 @@ return self; } - (unsigned int)retainCount { - assert(PRE_IVARS->retainCount >= 0); + OFAssert(PRE_IVARS->retainCount >= 0); return PRE_IVARS->retainCount; } - (void)release { 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 @@ -13,11 +13,11 @@ * file. */ #include "objfw-defs.h" -#include "platform.h" +#import "macros.h" #if defined(OF_HAVE_PTHREADS) # include typedef pthread_once_t OFOnceControl; # define OFOnceControlInitValue PTHREAD_ONCE_INIT @@ -27,10 +27,16 @@ #elif defined(OF_AMIGAOS) || !defined(OF_HAVE_THREADS) typedef int OFOnceControl; # define OFOnceControlInitValue 0 #endif +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +typedef void (*OFOnceFunction)(void); + #ifdef __cplusplus extern "C" { #endif /** * @brief Executes the specified function exactly once in the application's @@ -38,9 +44,11 @@ * * @param control An OFOnceControl. This should be a static variable * preinitialized to `OFOnceControlInitValue`. * @param function The function to execute once */ -extern void OFOnce(OFOnceControl *control, void (*function)(void)); +extern void OFOnce(OFOnceControl *control, OFOnceFunction function); #ifdef __cplusplus } #endif + +OF_ASSUME_NONNULL_END 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 @@ -64,13 +64,13 @@ * * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it * possible to reuse the `HMAC`, but also meaning all previous results * from the `HMAC` get invalidated if they have not been copied. * - * @param param The parameters to use + * @param parameters The parameters to use */ -extern void OFPBKDF2(OFPBKDF2Parameters param); +extern void OFPBKDF2(OFPBKDF2Parameters parameters); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END 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 @@ -15,11 +15,10 @@ #define __NO_EXT_QNX #include "config.h" -#include #include #ifdef HAVE_POLL_H # include #endif @@ -190,11 +189,11 @@ @throw [OFObserveKernelEventsFailedException exceptionWithObserver: self errNo: errno]; for (size_t i = 0; i < nFDs; i++) { - assert(FDs[i].fd <= _maxFD); + OFAssert(FDs[i].fd <= _maxFD); if (FDs[i].revents & POLLIN) { void *pool2; if (FDs[i].fd == _cancelFD[0]) { 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 @@ -13,11 +13,10 @@ * file. */ #include "config.h" -#include #include #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFArray.h" @@ -272,11 +271,11 @@ * handler called -[cancelAsyncRequests]. */ OFList OF_GENERIC(OF_KINDOF(OFRunLoopReadQueueItem *)) *queue = [[_readQueues objectForKey: object] retain]; - assert(queue != nil); + OFAssert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { OFListItem listItem = queue.firstListItem; @@ -316,11 +315,11 @@ * Retain the queue so that it doesn't disappear from us because the * handler called -[cancelAsyncRequests]. */ OFList *queue = [[_writeQueues objectForKey: object] retain]; - assert(queue != nil); + OFAssert(queue != nil); @try { if (![queue.firstObject handleObject: object]) { OFListItem listItem = queue.firstListItem; @@ -1326,11 +1325,11 @@ if (state == nil) return; if ((queue = [state->_writeQueues objectForKey: object]) != nil) { - assert(queue.count > 0); + OFAssert(queue.count > 0); /* * Clear the queue now, in case this has been called from a * handler, as otherwise, we'd do the cleanups below twice. */ @@ -1339,11 +1338,11 @@ [state->_kernelEventObserver removeObjectForWriting: object]; [state->_writeQueues removeObjectForKey: object]; } if ((queue = [state->_readQueues objectForKey: object]) != nil) { - assert(queue.count > 0); + OFAssert(queue.count > 0); /* * Clear the queue now, in case this has been called from a * handler, as otherwise, we'd do the cleanups below twice. */ 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 @@ -50,11 +50,11 @@ * @param exception An exception that occurred while connecting, or nil on * success */ - (void)socket: (OFSPXSocket *)socket didConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port exception: (nullable id)exception; @end /** @@ -87,15 +87,15 @@ * * @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 OFConnectionFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFConnectSPXSocketFailedException Connecting failed + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * @@ -103,11 +103,11 @@ * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. * @@ -116,11 +116,11 @@ * @param port The port (sometimes also called socket number) on the node to * connect to * @param runLoopMode The run loop mode in which to perform the async connect */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** @@ -131,11 +131,11 @@ * @param port The port (sometimes also called socket number) on the node to * connect to * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port block: (OFSPXSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXSocket to the specified destination. @@ -146,24 +146,30 @@ * connect to * @param runLoopMode The run loop mode in which to perform the async connect * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode block: (OFSPXSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * + * @param network The IPX network to bind to. 0 means the current network. + * @param node The IPX network to bind to. An all zero node means the + * computer's node. * @param port The port (sometimes called socket number) to bind to. 0 means to - * pick one and return it. + * pick one and return via the returned socket address. * @return The address on which this socket can be reached - * @throw OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFBindIPXSocketFailedException Binding failed + * @throw OFAlreadyOpenException The socket is already connected or bound */ -- (OFSocketAddress)bindToPort: (uint16_t)port; +- (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,13 +21,13 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" -#import "OFConnectionFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindIPXSocketFailedException.h" +#import "OFConnectSPXSocketFailedException.h" #import "OFNotOpenException.h" #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif @@ -54,11 +54,11 @@ #endif } - (instancetype)initWithSocket: (OFSPXSocket *)socket network: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXSocketAsyncConnectBlock)block #endif ; @@ -66,11 +66,11 @@ @end @implementation OFSPXSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXSocket *)sock network: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXSocketAsyncConnectBlock)block #endif { @@ -164,15 +164,15 @@ #endif } - (id)of_connectionFailedExceptionForErrNo: (int)errNo { - return [OFConnectionFailedException exceptionWithNetwork: _network - node: _node - port: _port - socket: _socket - errNo: errNo]; + return [OFConnectSPXSocketFailedException exceptionWithNetwork: _network + node: _node + port: _port + socket: _socket + errNo: errNo]; } @end @implementation OFSPXSocket @dynamic delegate; @@ -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(); @@ -222,48 +222,48 @@ closesocket(_socket); _socket = OFInvalidSocketHandle; } - (void)connectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port { OFSocketAddress address = OFSocketAddressMakeIPX(network, node, port); int errNo; if (![self of_createSocketForAddress: &address errNo: &errNo]) - @throw [OFConnectionFailedException + @throw [OFConnectSPXSocketFailedException exceptionWithNetwork: network node: node port: port socket: self errNo: errNo]; if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; - @throw [OFConnectionFailedException + @throw [OFConnectSPXSocketFailedException exceptionWithNetwork: network node: node port: port socket: self errNo: errNo]; } } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port { [self asyncConnectToNetwork: network node: node port: port runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); @@ -280,11 +280,11 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port block: (OFSPXSocketAsyncConnectBlock)block { [self asyncConnectToNetwork: network node: node @@ -292,11 +292,11 @@ runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode block: (OFSPXSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); @@ -311,31 +311,34 @@ objc_autoreleasePoolPop(pool); } #endif -- (OFSocketAddress)bindToPort: (uint16_t)port +- (OFSocketAddress)bindToNetwork: (uint32_t)network + node: (const unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port { - const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; OFSocketAddress address; #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(0, zeroNode, port); + address = OFSocketAddressMakeIPX(network, node, port); if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_SEQPACKET | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) - @throw [OFBindFailedException - exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: OFSocketErrNo()]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -347,14 +350,17 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: errNo]; } memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); @@ -364,24 +370,30 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: errNo]; } if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: EAFNOSUPPORT]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: EAFNOSUPPORT]; } return address; } @end 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 @@ -51,11 +51,11 @@ * @param exception An exception that occurred while connecting, or nil on * success */ - (void)socket: (OFSPXStreamSocket *)socket didConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port exception: (nullable id)exception; @end /** @@ -88,15 +88,15 @@ * * @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 OFConnectionFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFConnectSPXSocketFailedException Connecting failed + * @throw OFAlreadyOpenException The socket is already connected or bound */ - (void)connectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. @@ -105,11 +105,11 @@ * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port; /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified * destination. @@ -119,11 +119,11 @@ * @param port The port (sometimes also called socket number) on the node to * connect to * @param runLoopMode The run loop mode in which to perform the async connect */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** @@ -135,11 +135,11 @@ * @param port The port (sometimes also called socket number) on the node to * connect to * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port block: (OFSPXStreamSocketAsyncConnectBlock)block; /** * @brief Asynchronously connect the OFSPXStreamSocket to the specified @@ -151,24 +151,30 @@ * connect to * @param runLoopMode The run loop mode in which to perform the async connect * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode block: (OFSPXStreamSocketAsyncConnectBlock)block; #endif /** * @brief Bind the socket to the specified network, node and port. * + * @param network The IPX network to bind to. 0 means the current network. + * @param node The IPX network to bind to. An all zero node means the + * computer's node. * @param port The port (sometimes called socket number) to bind to. 0 means to - * pick one and return it. + * pick one and return via the returned socket address. * @return The address on which this socket can be reached - * @throw OFConnectionFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFBindIPXSocketFailedException Binding failed + * @throw OFAlreadyOpenException The socket is already connected or bound */ -- (OFSocketAddress)bindToPort: (uint16_t)port; +- (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,13 +21,13 @@ #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" -#import "OFConnectionFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindIPXSocketFailedException.h" +#import "OFConnectSPXSocketFailedException.h" #import "OFNotOpenException.h" #ifndef NSPROTO_SPX # define NSPROTO_SPX 0 #endif @@ -55,11 +55,11 @@ #endif } - (instancetype)initWithSocket: (OFSPXStreamSocket *)socket network: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXStreamSocketAsyncConnectBlock)block #endif ; @@ -67,11 +67,11 @@ @end @implementation OFSPXStreamSocketAsyncConnectDelegate - (instancetype)initWithSocket: (OFSPXStreamSocket *)sock network: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port #ifdef OF_HAVE_BLOCKS block: (OFSPXStreamSocketAsyncConnectBlock)block #endif { @@ -166,15 +166,15 @@ #endif } - (id)of_connectionFailedExceptionForErrNo: (int)errNo { - return [OFConnectionFailedException exceptionWithNetwork: _network - node: _node - port: _port - socket: _socket - errNo: errNo]; + return [OFConnectSPXSocketFailedException exceptionWithNetwork: _network + node: _node + port: _port + socket: _socket + errNo: errNo]; } @end @implementation OFSPXStreamSocket @dynamic delegate; @@ -185,14 +185,14 @@ #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)) == + SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) { *errNo = OFSocketErrNo(); return false; } @@ -224,48 +224,48 @@ closesocket(_socket); _socket = OFInvalidSocketHandle; } - (void)connectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port { OFSocketAddress address = OFSocketAddressMakeIPX(network, node, port); int errNo; if (![self of_createSocketForAddress: &address errNo: &errNo]) - @throw [OFConnectionFailedException + @throw [OFConnectSPXSocketFailedException exceptionWithNetwork: network node: node port: port socket: self errNo: errNo]; if (![self of_connectSocketToAddress: &address errNo: &errNo]) { [self of_closeSocket]; - @throw [OFConnectionFailedException + @throw [OFConnectSPXSocketFailedException exceptionWithNetwork: network node: node port: port socket: self errNo: errNo]; } } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port { [self asyncConnectToNetwork: network node: node port: port runLoopMode: OFDefaultRunLoopMode]; } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode { void *pool = objc_autoreleasePoolPush(); @@ -282,11 +282,11 @@ objc_autoreleasePoolPop(pool); } #ifdef OF_HAVE_BLOCKS - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port block: (OFSPXStreamSocketAsyncConnectBlock)block { [self asyncConnectToNetwork: network node: node @@ -294,11 +294,11 @@ runLoopMode: OFDefaultRunLoopMode block: block]; } - (void)asyncConnectToNetwork: (uint32_t)network - node: (unsigned char [_Nonnull IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode block: (OFSPXStreamSocketAsyncConnectBlock)block { void *pool = objc_autoreleasePoolPush(); @@ -313,30 +313,33 @@ objc_autoreleasePoolPop(pool); } #endif -- (OFSocketAddress)bindToPort: (uint16_t)port +- (OFSocketAddress)bindToNetwork: (uint32_t)network + node: (const unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port { - const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; OFSocketAddress address; #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(0, zeroNode, port); + address = OFSocketAddressMakeIPX(network, node, port); if ((_socket = socket(address.sockaddr.ipx.sipx_family, SOCK_STREAM | SOCK_CLOEXEC, NSPROTO_SPX)) == OFInvalidSocketHandle) - @throw [OFBindFailedException - exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: OFSocketErrNo()]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: OFSocketErrNo()]; _canBlock = true; #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) @@ -348,14 +351,17 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: errNo]; } memset(&address, 0, sizeof(address)); address.family = OFSocketAddressFamilyIPX; address.length = (socklen_t)sizeof(address.sockaddr); @@ -365,24 +371,30 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: errNo]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: errNo]; } if (address.sockaddr.ipx.sipx_family != AF_IPX) { closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPort: port - packetType: SPXPacketType - socket: self - errNo: EAFNOSUPPORT]; + @throw [OFBindIPXSocketFailedException + exceptionWithNetwork: network + node: node + port: port + packetType: SPXPacketType + socket: self + errNo: EAFNOSUPPORT]; } return address; } @end 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 @@ -68,13 +68,13 @@ size_t costFactor, uint32_t *tmp); /** * @brief Derives a key from a password and a salt using scrypt. * - * @param param The parameters to use + * @param parameters The parameters to use */ -extern void OFScrypt(OFScryptParameters param); +extern void OFScrypt(OFScryptParameters parameters); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END 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 @@ -303,28 +303,28 @@ /** * @brief Listen on the socket. * * @param backlog Maximum length for the queue of pending connections. - * @throw OFListenFailedException Listening failed + * @throw OFListenOnSocketFailedException Listening failed * @throw OFNotOpenException The socket is not open */ - (void)listenWithBacklog: (int)backlog; /** * @brief Listen on the socket. * - * @throw OFListenFailedException Listening failed + * @throw OFListenOnSocketFailedException Listening failed * @throw OFNotOpenException The socket is not open */ - (void)listen; /** * @brief Accept an incoming connection. * * @return An autoreleased sequenced packet socket for the accepted connection. - * @throw OFAcceptFailedException Accepting failed + * @throw OFAcceptSocketFailedException Accepting failed * @throw OFNotOpenException The socket is not open */ - (instancetype)accept; /** 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 @@ -18,11 +18,10 @@ #ifndef _XOPEN_SOURCE_EXTENDED # define _XOPEN_SOURCE_EXTENDED #endif #define _HPUX_ALT_XOPEN_SOCKET_API -#include #include #ifdef HAVE_FCNTL_H # include #endif @@ -33,14 +32,14 @@ #import "OFRunLoop+Private.h" #import "OFRunLoop.h" #import "OFSocket.h" #import "OFSocket+Private.h" -#import "OFAcceptFailedException.h" +#import "OFAcceptSocketFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" -#import "OFListenFailedException.h" +#import "OFListenOnSocketFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" #import "OFWriteFailedException.h" @@ -306,11 +305,11 @@ { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (listen(_socket, backlog) == -1) - @throw [OFListenFailedException + @throw [OFListenOnSocketFailedException exceptionWithSocket: self backlog: backlog errNo: OFSocketErrNo()]; _listening = true; @@ -335,36 +334,36 @@ #if defined(HAVE_PACCEPT) && defined(SOCK_CLOEXEC) if ((client->_socket = paccept(_socket, (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, SOCK_CLOEXEC)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; # if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(client->_socket, F_GETFD, 0)) != -1) fcntl(client->_socket, F_SETFD, flags | FD_CLOEXEC); # endif #endif - assert(client->_remoteAddress.length <= + OFAssert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); switch (((struct sockaddr *)&client->_remoteAddress.sockaddr) ->sa_family) { case AF_INET: 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; } @@ -192,15 +186,10 @@ - (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments { OF_INVALID_INIT_METHOD } -- (instancetype)initWithSerialization: (OFXMLElement *)element -{ - OF_INVALID_INIT_METHOD -} - - (size_t)count { OF_UNRECOGNIZED_SELECTOR } @@ -243,10 +232,11 @@ - (int)countByEnumeratingWithState: (OFFastEnumerationState *)state objects: (id *)objects count: (int)count { + static unsigned long dummyMutations; OFEnumerator *enumerator; int i; memcpy(&enumerator, state->extra, sizeof(enumerator)); @@ -254,11 +244,11 @@ enumerator = [self objectEnumerator]; memcpy(state->extra, &enumerator, sizeof(enumerator)); } state->itemsPtr = objects; - state->mutationsPtr = (unsigned long *)self; + state->mutationsPtr = &dummyMutations; for (i = 0; i < count; i++) { id object = [enumerator nextObject]; if (object == nil) @@ -360,35 +350,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 @@ -33,30 +33,36 @@ # include #endif #ifdef OF_HAVE_NETINET_TCP_H # include #endif -#ifdef OF_HAVE_NETIPX_IPX_H -# include -#endif #ifdef OF_HAVE_SYS_UN_H # include #endif #ifdef OF_HAVE_AFUNIX_H # include +#endif +#ifdef OF_HAVE_NETIPX_IPX_H +# include +#endif +#if defined(OF_HAVE_NETAT_APPLETALK_H) +# include +#elif defined(OF_HAVE_NETATALK_AT_H) +# include #endif #ifdef OF_WINDOWS # include # include # ifdef OF_HAVE_IPX # include # endif +# ifdef OF_HAVE_APPLETALK +# include +# endif #endif -/** @file */ - #ifdef OF_WII # include #endif #ifdef OF_PSP @@ -64,10 +70,12 @@ #endif #import "macros.h" OF_ASSUME_NONNULL_BEGIN + +/** @file */ #ifndef OF_WINDOWS typedef int OFSocketHandle; static const OFSocketHandle OFInvalidSocketHandle = -1; #else @@ -101,10 +109,12 @@ OFSocketAddressFamilyIPv6, /** UNIX */ OFSocketAddressFamilyUNIX, /** IPX */ OFSocketAddressFamilyIPX, + /** AppleTalk */ + OFSocketAddressFamilyAppleTalk, /** Any address family */ OFSocketAddressFamilyAny = 255 } OFSocketAddressFamily; #ifndef OF_HAVE_IPV6 @@ -124,26 +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; + uint16_t sat_net; + uint8_t sat_node; +}; +#else +# 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 * @@ -158,10 +188,18 @@ union { 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 @@ -205,20 +243,32 @@ * @return A UNIX socket address with the specified path */ extern OFSocketAddress OFSocketAddressMakeUNIX(OFString *path); /** - * @brief Creates an IPX address for the specified node, network and port. + * @brief Creates an IPX address for the specified network, node and port. * * @param network The IPX network * @param node The node in the IPX network * @param port The IPX port (sometimes called socket number) on the node * @return An IPX socket address with the specified node, network and port. */ extern OFSocketAddress OFSocketAddressMakeIPX(uint32_t network, const unsigned char node[_Nonnull IPX_NODE_LEN], uint16_t port); +/** + * @brief Creates an AppleTalk address for the specified network, node and port. + * + * @param network The AppleTalk network + * @param node The node in the AppleTalk network + * @param port The AppleTalk (sometimes called socket number) on the node + * @return An AppleTalk socket address with the specified node, network and + * port. + */ +extern OFSocketAddress OFSocketAddressMakeAppleTalk(uint16_t network, + uint8_t node, uint8_t port); + /** * @brief Compares two OFSocketAddress for equality. * * @param address1 The address to compare with the second address * @param address2 The second address @@ -238,41 +288,39 @@ /** * @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); /** - * @brief Sets the port of the specified @ref OFSocketAddress, independent of - * the address family used. + * @brief Sets the IP port of the specified @ref OFSocketAddress. * * @param address The address on which to set the port * @param port The port to set on the address */ -extern void OFSocketAddressSetPort(OFSocketAddress *_Nonnull address, +extern void OFSocketAddressSetIPPort(OFSocketAddress *_Nonnull address, uint16_t port); /** - * @brief Returns the port of the specified @ref OFSocketAddress, independent of - * the address family used. + * @brief Returns the IP port of the specified @ref OFSocketAddress. * * @param address The address on which to get the port * @return The port of the address */ -extern uint16_t OFSocketAddressPort(const OFSocketAddress *_Nonnull address); +extern uint16_t OFSocketAddressIPPort(const OFSocketAddress *_Nonnull address); /** * @brief Gets the UNIX socket path of the specified @ref OFSocketAddress. * * @param address The address on which to get the UNIX socket path * @return The UNIX socket path */ -extern OFString *_Nullable OFSocketAddressUNIXPath( +extern OFString *OFSocketAddressUNIXPath( const OFSocketAddress *_Nonnull address); /** * @brief Sets the IPX network of the specified @ref OFSocketAddress. * @@ -304,13 +352,84 @@ * @brief Gets the IPX node of the specified @ref OFSocketAddress. * * @param address The address on which to get the IPX node * @param node A byte array to store the IPX node of the address */ -extern void OFSocketAddressIPXNode(const OFSocketAddress *_Nonnull address, +extern void OFSocketAddressGetIPXNode(const OFSocketAddress *_Nonnull address, unsigned char node[_Nonnull IPX_NODE_LEN]); +/** + * @brief Sets the IPX port of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the port + * @param port The port to set on the address + */ +extern void OFSocketAddressSetIPXPort(OFSocketAddress *_Nonnull address, + uint16_t port); + +/** + * @brief Returns the IPX port of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the port + * @return The port of the address + */ +extern uint16_t OFSocketAddressIPXPort(const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the AppleTalk network of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the AppleTalk network + * @param network The AppleTalk network to set on the address + */ +extern void OFSocketAddressSetAppleTalkNetwork( + OFSocketAddress *_Nonnull address, uint16_t network); + +/** + * @brief Returns the AppleTalk network of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the AppleTalk network + * @return The AppleTalk network of the address + */ +extern uint16_t OFSocketAddressAppleTalkNetwork( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the AppleTalk node of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the AppleTalk node + * @param node The AppleTalk node to set on the address + */ +extern void OFSocketAddressSetAppleTalkNode(OFSocketAddress *_Nonnull address, + uint8_t node); + +/** + * @brief Gets the AppleTalk node of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the AppleTalk node + * @return The AppleTalk node of the address + */ +extern uint8_t OFSocketAddressAppleTalkNode( + const OFSocketAddress *_Nonnull address); + +/** + * @brief Sets the AppleTalk port of the specified @ref OFSocketAddress. + * + * @param address The address on which to set the port + * @param port The port to set on the address + */ +extern void OFSocketAddressSetAppleTalkPort(OFSocketAddress *_Nonnull address, + uint8_t port); + +/** + * @brief Returns the AppleTalk port of the specified @ref OFSocketAddress. + * + * @param address The address on which to get the port + * @return The port of the address + */ +extern uint8_t OFSocketAddressAppleTalkPort( + const OFSocketAddress *_Nonnull address); + extern bool OFSocketInit(void); #if defined(OF_HAVE_THREADS) && defined(OF_AMIGAOS) && !defined(OF_MORPHOS) extern void OFSocketDeinit(void); #endif extern int OFSocketErrNo(void); 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 @@ -45,13 +45,19 @@ #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFLockFailedException.h" #import "OFOutOfRangeException.h" #import "OFUnlockFailedException.h" + +#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> @@ -424,18 +430,46 @@ 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(); OFSocketAddress ret; struct sockaddr_in6 *addrIn6 = &ret.sockaddr.in6; - size_t doubleColon; + size_t doubleColon, percent; memset(&ret, '\0', sizeof(ret)); ret.family = OFSocketAddressFamilyIPv6; ret.length = sizeof(ret.sockaddr.in6); @@ -443,13 +477,33 @@ addrIn6->sin6_family = AF_INET6; #else addrIn6->sin6_family = AF_UNSPEC; #endif addrIn6->sin6_port = OFToBigEndian16(port); + + if ((percent = [IPv6 rangeOfString: @"%"].location) != OFNotFound) { + OFString *interface = [IPv6 substringFromIndex: percent + 1]; + IPv6 = [IPv6 substringToIndex: percent]; + + @try { + addrIn6->sin6_scope_id = (uint32_t)[interface + unsignedLongLongValueWithBase: 10]; + } @catch (OFInvalidFormatException *e) { +#if defined(HAVE_IF_NAMETOINDEX) && !defined(OF_WINDOWS) + addrIn6->sin6_scope_id = if_nametoindex([interface + cStringWithEncoding: [OFLocale encoding]]); +#endif + } + + 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]; OFArray OF_GENERIC(OFString *) *leftComponents; OFArray OF_GENERIC(OFString *) *rightComponents; @@ -534,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 @@ -570,18 +627,44 @@ memcpy(ret.sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); ret.sockaddr.ipx.sipx_port = OFToBigEndian16(port); return ret; } + +OFSocketAddress +OFSocketAddressMakeAppleTalk(uint16_t network, uint8_t node, uint8_t port) +{ + OFSocketAddress ret; + + memset(&ret, '\0', sizeof(ret)); + ret.family = OFSocketAddressFamilyAppleTalk; + ret.length = sizeof(ret.sockaddr.at); + +#ifdef AF_APPLETALK + ret.sockaddr.at.sat_family = AF_APPLETALK; +#else + ret.sockaddr.at.sat_family = AF_UNSPEC; +#endif +#ifdef OF_WINDOWS + ret.sockaddr.at.sat_net = network; +#else + ret.sockaddr.at.sat_net = OFToBigEndian16(network); +#endif + ret.sockaddr.at.sat_node = node; + ret.sockaddr.at.sat_port = port; + + return ret; +} bool OFSocketAddressEqual(const OFSocketAddress *address1, const OFSocketAddress *address2) { const struct sockaddr_in *addrIn1, *addrIn2; const struct sockaddr_in6 *addrIn6_1, *addrIn6_2; const struct sockaddr_ipx *addrIPX1, *addrIPX2; + const struct sockaddr_at *addrAT1, *addrAT2; void *pool; OFString *path1, *path2; bool ret; if (address1->family != address2->family) @@ -655,10 +738,26 @@ return false; if (memcmp(addrIPX1->sipx_node, addrIPX2->sipx_node, IPX_NODE_LEN) != 0) return false; + return true; + case OFSocketAddressFamilyAppleTalk: + if (address1->length < (socklen_t)sizeof(struct sockaddr_at) || + address2->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + addrAT1 = &address1->sockaddr.at; + addrAT2 = &address2->sockaddr.at; + + if (addrAT1->sat_net != addrAT2->sat_net) + return false; + if (addrAT1->sat_node != addrAT2->sat_node) + return false; + if (addrAT1->sat_port != addrAT2->sat_port) + return false; + return true; default: @throw [OFInvalidArgumentException exception]; } } @@ -731,10 +830,19 @@ for (size_t i = 0; i < IPX_NODE_LEN; i++) OFHashAddByte(&hash, address->sockaddr.ipx.sipx_node[i]); + break; + case OFSocketAddressFamilyAppleTalk: + if (address->length < (socklen_t)sizeof(struct sockaddr_at)) + @throw [OFInvalidArgumentException exception]; + + OFHashAddByte(&hash, address->sockaddr.at.sat_net >> 8); + OFHashAddByte(&hash, address->sockaddr.at.sat_net); + OFHashAddByte(&hash, address->sockaddr.at.sat_port); + break; default: @throw [OFInvalidArgumentException exception]; } @@ -816,57 +924,97 @@ (addrIn6->sin6_addr.s6_addr[i] << 8) | addrIn6->sin6_addr.s6_addr[i + 1]]; first = false; } } + + if (addrIn6->sin6_scope_id != 0) { +#if defined(HAVE_IF_INDEXTONAME) && !defined(OF_WINDOWS) + char interface[IF_NAMESIZE]; + + if (if_indextoname(addrIn6->sin6_scope_id, interface) != NULL) + [string appendFormat: @"%%%s", interface]; + else +# endif + [string appendFormat: @"%%%u", addrIn6->sin6_scope_id]; + } [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 OFSocketAddressFamilyUNIX: + return OFSocketAddressUNIXPath(address); + case OFSocketAddressFamilyIPX: + return IPXString(address); + case OFSocketAddressFamilyAppleTalk: + return appleTalkString(address); default: @throw [OFInvalidArgumentException exception]; } } void -OFSocketAddressSetPort(OFSocketAddress *address, uint16_t port) +OFSocketAddressSetIPPort(OFSocketAddress *address, uint16_t port) { switch (address->family) { case OFSocketAddressFamilyIPv4: address->sockaddr.in.sin_port = OFToBigEndian16(port); break; case OFSocketAddressFamilyIPv6: address->sockaddr.in6.sin6_port = OFToBigEndian16(port); break; - case OFSocketAddressFamilyIPX: - address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); - break; default: @throw [OFInvalidArgumentException exception]; } } uint16_t -OFSocketAddressPort(const OFSocketAddress *address) +OFSocketAddressIPPort(const OFSocketAddress *address) { switch (address->family) { case OFSocketAddressFamilyIPv4: return OFFromBigEndian16(address->sockaddr.in.sin_port); case OFSocketAddressFamilyIPv6: return OFFromBigEndian16(address->sockaddr.in6.sin6_port); - case OFSocketAddressFamilyIPX: - return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); default: @throw [OFInvalidArgumentException exception]; } } @@ -882,13 +1030,10 @@ for (socklen_t i = 0; i < length; i++) if (address->sockaddr.un.sun_path[i] == 0) length = i; - if (length <= 0) - return nil; - return [OFString stringWithCString: address->sockaddr.un.sun_path encoding: [OFLocale encoding] length: length]; } @@ -925,13 +1070,93 @@ memcpy(address->sockaddr.ipx.sipx_node, node, IPX_NODE_LEN); } void -OFSocketAddressIPXNode(const OFSocketAddress *address, +OFSocketAddressGetIPXNode(const OFSocketAddress *address, unsigned char node[IPX_NODE_LEN]) { if (address->family != OFSocketAddressFamilyIPX) @throw [OFInvalidArgumentException exception]; memcpy(node, address->sockaddr.ipx.sipx_node, IPX_NODE_LEN); } + +void +OFSocketAddressSetIPXPort(OFSocketAddress *address, uint16_t port) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.ipx.sipx_port = OFToBigEndian16(port); +} + +uint16_t +OFSocketAddressIPXPort(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyIPX) + @throw [OFInvalidArgumentException exception]; + + return OFFromBigEndian16(address->sockaddr.ipx.sipx_port); +} + +void +OFSocketAddressSetAppleTalkNetwork(OFSocketAddress *address, uint16_t network) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + +#ifdef OF_WINDOWS + address->sockaddr.at.sat_net = network; +#else + address->sockaddr.at.sat_net = OFToBigEndian16(network); +#endif +} + +uint16_t +OFSocketAddressAppleTalkNetwork(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + +#ifdef OF_WINDOWS + return address->sockaddr.at.sat_net; +#else + return OFFromBigEndian16(address->sockaddr.at.sat_net); +#endif +} + +void +OFSocketAddressSetAppleTalkNode(OFSocketAddress *address, uint8_t node) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_node = node; +} + +uint8_t +OFSocketAddressAppleTalkNode(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_node; +} + +void +OFSocketAddressSetAppleTalkPort(OFSocketAddress *address, uint8_t port) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + address->sockaddr.at.sat_port = port; +} + +uint8_t +OFSocketAddressAppleTalkPort(const OFSocketAddress *address) +{ + if (address->family != OFSocketAddressFamilyAppleTalk) + @throw [OFInvalidArgumentException exception]; + + return address->sockaddr.at.sat_port; +} 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 @@ -102,10 +104,13 @@ #ifdef OF_HAVE_FILES me = [OFApplication programName].lastPathComponent; #else me = [OFApplication programName]; #endif + + if (me == nil) + me = @"?"; msg = [[[OFString alloc] initWithFormat: format arguments: arguments] autorelease]; [OFStdErr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString, @@ -434,11 +439,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; @@ -449,11 +454,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 @@ -15,11 +15,10 @@ #define __NO_EXT_QNX #include "config.h" -#include #include #include #include #include #include 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 @@ -104,28 +104,28 @@ /** * @brief Listen on the socket. * * @param backlog Maximum length for the queue of pending connections. - * @throw OFListenFailedException Listening failed + * @throw OFListenOnSocketFailedException Listening failed * @throw OFNotOpenException The socket is not open */ - (void)listenWithBacklog: (int)backlog; /** * @brief Listen on the socket. * - * @throw OFListenFailedException Listening failed + * @throw OFListenOnSocketFailedException Listening failed * @throw OFNotOpenException The socket is not open */ - (void)listen; /** * @brief Accept an incoming connection. * * @return An autoreleased OFStreamSocket for the accepted connection. - * @throw OFAcceptFailedException Accepting failed + * @throw OFAcceptSocketFailedException Accepting failed * @throw OFNotOpenException The socket is not open */ - (instancetype)accept; /** 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 @@ -19,24 +19,23 @@ # define _XOPEN_SOURCE_EXTENDED #endif #define __NO_EXT_QNX #define _HPUX_ALT_XOPEN_SOCKET_API -#include #include #include #import "OFStreamSocket.h" #import "OFStreamSocket+Private.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket+Private.h" -#import "OFAcceptFailedException.h" +#import "OFAcceptSocketFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" -#import "OFListenFailedException.h" +#import "OFListenOnSocketFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFSetOptionFailedException.h" @@ -231,61 +230,65 @@ { if (_socket == OFInvalidSocketHandle) @throw [OFNotOpenException exceptionWithObject: self]; if (listen(_socket, backlog) == -1) - @throw [OFListenFailedException + @throw [OFListenOnSocketFailedException exceptionWithSocket: self backlog: backlog errNo: OFSocketErrNo()]; _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, (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, NULL, SOCK_CLOEXEC)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #elif defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) if ((client->_socket = accept4(_socket, (struct sockaddr * )&client->_remoteAddress.sockaddr, &client->_remoteAddress.length, SOCK_CLOEXEC)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; #else if ((client->_socket = accept(_socket, (struct sockaddr *)&client->_remoteAddress.sockaddr, &client->_remoteAddress.length)) == OFInvalidSocketHandle) - @throw [OFAcceptFailedException + @throw [OFAcceptSocketFailedException exceptionWithSocket: self errNo: OFSocketErrNo()]; # if defined(HAVE_FCNTL) && defined(FD_CLOEXEC) if ((flags = fcntl(client->_socket, F_GETFD, 0)) != -1) fcntl(client->_socket, F_SETFD, flags | FD_CLOEXEC); # endif #endif - assert(client->_remoteAddress.length <= + OFAssert(client->_remoteAddress.length <= (socklen_t)sizeof(client->_remoteAddress.sockaddr)); switch (((struct sockaddr *)&client->_remoteAddress.sockaddr) ->sa_family) { case AF_INET: 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 @@ -18,12 +18,10 @@ #include #include #include -#include - #import "OFString+JSONParsing.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFNumber.h" #import "OFNull.h" @@ -651,14 +649,10 @@ const char *pointer = self.UTF8String; const char *stop = pointer + self.UTF8StringLength; id object; size_t line = 1; -#ifdef __clang_analyzer__ - assert(pointer != NULL); -#endif - object = nextObject(&pointer, stop, &line, depthLimit); skipWhitespacesAndComments(&pointer, stop, &line); if (pointer < stop || object == nil) @throw [OFInvalidJSONException exceptionWithString: self 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,35 +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. - */ -@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,68 +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; - - @try { - root = [OFXMLElement elementWithXMLString: self]; - } @catch (OFMalformedXMLException *e) { - @throw [OFInvalidArgumentException exception]; - } @catch (OFUnboundNamespaceException *e) { - @throw [OFInvalidArgumentException exception]; - } - - 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 @@ -13,11 +13,10 @@ * file. */ #include "config.h" -#include #include #include #import "OFString.h" @@ -86,11 +85,11 @@ memcpy(retCString + j, append, appendLen); j += appendLen; } else retCString[j++] = string[i]; } - assert(j == retLength); + OFAssert(j == retLength); objc_autoreleasePoolPop(pool); @try { ret = [OFString stringWithUTF8String: retCString 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 @@ -72,10 +72,12 @@ /** * @brief Unescapes XML in the string and uses the specified delegate for * unknown entities. * * @param delegate An OFXMLUnescapingDelegate as a handler for unknown entities + * @throw OFInvalidFormatException The string is not a valid XML string + * @throw OFUnknownXMLEntityException The string contains unknown XML entities */ - (OFString *)stringByXMLUnescapingWithDelegate: (nullable id )delegate; #ifdef OF_HAVE_BLOCKS @@ -82,11 +84,13 @@ /** * @brief Unescapes XML in the string and uses the specified block for unknown * entities. * * @param block A block which handles unknown entities + * @throw OFInvalidFormatException The string is not a valid XML string + * @throw OFUnknownXMLEntityException The string contains unknown XML entities */ - (OFString *)stringByXMLUnescapingWithBlock: (OFStringXMLUnescapingBlock)block; #endif @end OF_ASSUME_NONNULL_END 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; @@ -210,20 +209,20 @@ @property (readonly, nonatomic) unsigned long long unsignedLongLongValue; /** * @brief The float value of the string as a float. * - * If the string contains any non-number characters, an - * @ref OFInvalidFormatException is thrown. + * @throw OFInvalidFormatException The string cannot be parsed as a `float` + * @throw OFOutOfRangeException The value cannot be represented as a `float` */ @property (readonly, nonatomic) float floatValue; /** * @brief The double value of the string as a double. * - * If the string contains any non-number characters, an - * @ref OFInvalidFormatException is thrown. + * @throw OFInvalidFormatException The string cannot be parsed as a `double` + * @throw OFOutOfRangeException The value cannot be represented as a `double` */ @property (readonly, nonatomic) double doubleValue; /** * @brief The string as an array of Unicode characters. @@ -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; @@ -312,10 +308,11 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string. * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ + (instancetype)stringWithUTF8String: (const char *)UTF8String; /** * @brief Creates a new OFString from a UTF-8 encoded C string with the @@ -322,10 +319,11 @@ * specified length. * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ + (instancetype)stringWithUTF8String: (const char *)UTF8String length: (size_t)UTF8StringLength; /** @@ -339,10 +337,11 @@ * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when the OFString gets * deallocated * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ + (instancetype)stringWithUTF8StringNoCopy: (char *)UTF8String freeWhenDone: (bool)freeWhenDone; /** @@ -357,10 +356,11 @@ * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string * @param freeWhenDone Whether to free the C string when the OFString gets * deallocated * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ + (instancetype)stringWithUTF8StringNoCopy: (char *)UTF8String length: (size_t)UTF8StringLength freeWhenDone: (bool)freeWhenDone; @@ -368,10 +368,11 @@ * @brief Creates a new OFString from a C string with the specified encoding. * * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ + (instancetype)stringWithCString: (const char *)cString encoding: (OFStringEncoding)encoding; /** @@ -380,10 +381,11 @@ * * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @param cStringLength The length of the C string * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ + (instancetype)stringWithCString: (const char *)cString encoding: (OFStringEncoding)encoding length: (size_t)cStringLength; @@ -391,10 +393,11 @@ * @brief Creates a new OFString from OFData with the specified encoding. * * @param data OFData with the contents of the string * @param encoding The encoding in which the string is stored in the OFData * @return An new autoreleased OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ + (instancetype)stringWithData: (OFData *)data encoding: (OFStringEncoding)encoding; /** @@ -419,10 +422,11 @@ /** * @brief Creates a new OFString from a UTF-16 encoded string. * * @param string A zero-terminated UTF-16 string * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ + (instancetype)stringWithUTF16String: (const OFChar16 *)string; /** * @brief Creates a new OFString from a UTF-16 encoded string with the @@ -429,10 +433,11 @@ * specified length. * * @param string A zero-terminated UTF-16 string * @param length The length of the UTF-16 string * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ + (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length; /** @@ -440,10 +445,11 @@ * specified byte order if no byte order mark is found. * * @param string A zero-terminated UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ + (instancetype)stringWithUTF16String: (const OFChar16 *)string byteOrder: (OFByteOrder)byteOrder; /** @@ -453,10 +459,11 @@ * * @param string A zero-terminated UTF-16 string * @param length The length of the UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ + (instancetype)stringWithUTF16String: (const OFChar16 *)string length: (size_t)length byteOrder: (OFByteOrder)byteOrder; @@ -511,10 +518,13 @@ * format specifier for objects, `%C` for `OFUnichar` and `%S` for * `const OFUnichar *`. * * @param format A string used as format to initialize the OFString * @return A new autoreleased OFString + * @throw OFInvalidFormatException The specified format is invalid + * @throw OFInvalidEncodingException The resulting string is not in not in UTF-8 + * encoding */ + (instancetype)stringWithFormat: (OFConstantString *)format, ...; # ifdef OF_HAVE_FILES /** @@ -521,10 +531,11 @@ * @brief Creates a new OFString with the contents of the specified UTF-8 * encoded file. * * @param path The path to the file * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ + (instancetype)stringWithContentsOfFile: (OFString *)path; /** * @brief Creates a new OFString with the contents of the specified file in the @@ -531,46 +542,50 @@ * specified encoding. * * @param path The path to the file * @param encoding The encoding of the file * @return A new autoreleased OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ + (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. * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ - (instancetype)initWithUTF8String: (const char *)UTF8String; /** * @brief Initializes an already allocated OFString from a UTF-8 encoded C @@ -577,10 +592,11 @@ * string with the specified length. * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ - (instancetype)initWithUTF8String: (const char *)UTF8String length: (size_t)UTF8StringLength; /** @@ -594,10 +610,11 @@ * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when it is not needed * anymore * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String freeWhenDone: (bool)freeWhenDone; /** @@ -613,10 +630,11 @@ * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string * @param freeWhenDone Whether to free the C string when it is not needed * anymore * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ - (instancetype)initWithUTF8StringNoCopy: (char *)UTF8String length: (size_t)UTF8StringLength freeWhenDone: (bool)freeWhenDone; @@ -625,10 +643,11 @@ * specified encoding. * * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ - (instancetype)initWithCString: (const char *)cString encoding: (OFStringEncoding)encoding; /** @@ -637,10 +656,11 @@ * * @param cString A C string to initialize the OFString with * @param encoding The encoding of the C string * @param cStringLength The length of the C string * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ - (instancetype)initWithCString: (const char *)cString encoding: (OFStringEncoding)encoding length: (size_t)cStringLength; @@ -649,10 +669,11 @@ * specified encoding. * * @param data OFData with the contents of the string * @param encoding The encoding in which the string is stored in the OFData * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ - (instancetype)initWithData: (OFData *)data encoding: (OFStringEncoding)encoding; /** @@ -677,10 +698,11 @@ /** * @brief Initializes an already allocated OFString with a UTF-16 string. * * @param string A zero-terminated UTF-16 string * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ - (instancetype)initWithUTF16String: (const OFChar16 *)string; /** * @brief Initializes an already allocated OFString with a UTF-16 string with @@ -687,10 +709,11 @@ * the specified length. * * @param string A zero-terminated UTF-16 string * @param length The length of the UTF-16 string * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ - (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length; /** @@ -698,10 +721,11 @@ * assuming the specified byte order if no byte order mark is found. * * @param string A zero-terminated UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ - (instancetype)initWithUTF16String: (const OFChar16 *)string byteOrder: (OFByteOrder)byteOrder; /** @@ -711,10 +735,11 @@ * * @param string A zero-terminated UTF-16 string * @param length The length of the UTF-16 string * @param byteOrder The byte order to assume if there is no byte order mark * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-16-encoded */ - (instancetype)initWithUTF16String: (const OFChar16 *)string length: (size_t)length byteOrder: (OFByteOrder)byteOrder; @@ -769,10 +794,13 @@ * format specifier for objects, `%C` for `OFUnichar` and `%S` for * `const OFUnichar *`. * * @param format A string used as format to initialize the OFString * @return An initialized OFString + * @throw OFInvalidFormatException The specified format is invalid + * @throw OFInvalidEncodingException The resulting string is not in not in UTF-8 + * encoding */ - (instancetype)initWithFormat: (OFConstantString *)format, ...; /** * @brief Initializes an already allocated OFString with a format string. @@ -782,10 +810,13 @@ * `const OFUnichar *`. * * @param format A string used as format to initialize the OFString * @param arguments The arguments used in the format string * @return An initialized OFString + * @throw OFInvalidFormatException The specified format is invalid + * @throw OFInvalidEncodingException The resulting string is not in not in UTF-8 + * encoding */ - (instancetype)initWithFormat: (OFConstantString *)format arguments: (va_list)arguments; # ifdef OF_HAVE_FILES @@ -793,10 +824,11 @@ * @brief Initializes an already allocated OFString with the contents of the * specified file in the specified encoding. * * @param path The path to the file * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not properly UTF-8-encoded */ - (instancetype)initWithContentsOfFile: (OFString *)path; /** * @brief Initializes an already allocated OFString with the contents of the @@ -803,39 +835,42 @@ * specified file in the specified encoding. * * @param path The path to the file * @param encoding The encoding of the file * @return An initialized OFString + * @throw OFInvalidEncodingException The string is not in the specified encoding */ - (instancetype)initWithContentsOfFile: (OFString *)path 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. @@ -844,10 +879,12 @@ * @param maxLength The maximum number of bytes to write into the C string, * including the terminating zero * @param encoding The encoding to use for writing into the C string * @return The number of bytes written into the C string, without the * terminating zero + * @throw OFInvalidEncodingException The string cannot be represented in the + * specified encoding */ - (size_t)getCString: (char *)cString maxLength: (size_t)maxLength encoding: (OFStringEncoding)encoding; @@ -874,13 +911,14 @@ * use the result outside the scope of the current autorelease pool, you have to * copy it. * * @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. @@ -890,19 +928,20 @@ * 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. * * @param encoding The encoding for the string * @return The number of bytes the string needs in the specified encoding. + * @throw OFInvalidEncodingException The string cannot be represented in the + * specified encoding */ - (size_t)cStringLengthWithEncoding: (OFStringEncoding)encoding; /** * @brief Compares the string to another string. @@ -1049,10 +1088,12 @@ * @param base The base to use. If the base is 0, base 16 is assumed if the * string starts with 0x (after stripping white spaces). If the * string starts with 0, base 8 is assumed. Otherwise, base 10 is * assumed. * @return The value of the string in the specified base + * @throw OFInvalidFormatException The string cannot be parsed as a `long long` + * @throw OFOutOfRangeException The value cannot be represented as a `long long` */ - (long long)longLongValueWithBase: (unsigned char)base; /** * @brief The value of the string in the specified base as an @@ -1069,10 +1110,14 @@ * @param base The base to use. If the base is 0, base 16 is assumed if the * string starts with 0x (after stripping white spaces). If the * string starts with 0, base 8 is assumed. Otherwise, base 10 is * assumed. * @return The value of the string in the specified base + * @throw OFInvalidFormatException The string cannot be parsed as an + * `unsigned long long` + * @throw OFOutOfRangeException The value cannot be represented as an + * `unsigned long long` */ - (unsigned long long)unsignedLongLongValueWithBase: (unsigned char)base; /** * @brief Creates a new string by appending another string. @@ -1085,19 +1130,25 @@ /** * @brief Creates a new string by appending the specified format. * * @param format A format string which generates the string to append * @return A new, autoreleased OFString with the specified format appended + * @throw OFInvalidEncodingException The string was not properly UTF-8-encoded + * after formatting it + * @throw OFInvalidFormatException The specified format is invalid */ - (OFString *)stringByAppendingFormat: (OFConstantString *)format, ...; /** * @brief Creates a new string by appending the specified format. * * @param format A format string which generates the string to append * @param arguments The arguments used in the format string * @return A new, autoreleased OFString with the specified format appended + * @throw OFInvalidEncodingException The string was not properly UTF-8-encoded + * after formatting it + * @throw OFInvalidFormatException The specified format is invalid */ - (OFString *)stringByAppendingFormat: (OFConstantString *)format arguments: (va_list)arguments; /** @@ -1197,13 +1248,13 @@ * * The returned string is null-terminated. * * @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 @@ -1213,18 +1264,19 @@ * 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 * @return The string as OFData with the specified encoding + * @throw OFInvalidEncodingException The string cannot be represented in the + * specified encoding */ - (OFData *)dataWithEncoding: (OFStringEncoding)encoding; # ifdef OF_HAVE_FILES /** @@ -1238,28 +1290,32 @@ * @brief Writes the string into the specified file using the specified * encoding. * * @param path The path of the file to write to * @param encoding The encoding to use to write the string into the file + * @throw OFInvalidEncodingException The string cannot be represented in the + * specified encoding */ - (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. * @@ -1312,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 { @@ -992,96 +985,79 @@ } - (instancetype)initWithContentsOfFile: (OFString *)path encoding: (OFStringEncoding)encoding { - char *tmp; - unsigned long long fileSize; + char *buffer = NULL; + OFStreamOffset fileSize; @try { void *pool = objc_autoreleasePoolPush(); - OFFile *file = nil; - - @try { - fileSize = [[OFFileManager defaultManager] - attributesOfItemAtPath: path].fileSize; - } @catch (OFGetItemAttributesFailedException *e) { - @throw [OFOpenItemFailedException - exceptionWithPath: path - mode: @"r" - errNo: e.errNo]; - } - - objc_autoreleasePoolPop(pool); - -# if ULLONG_MAX > SIZE_MAX - if (fileSize > SIZE_MAX) - @throw [OFOutOfRangeException exception]; -#endif + OFFile *file = [OFFile fileWithPath: path mode: @"r"]; + fileSize = [file seekToOffset: 0 whence: OFSeekEnd]; + + if (fileSize < 0 || (unsigned long long)fileSize > SIZE_MAX) + @throw [OFOutOfRangeException exception]; /* * We need one extra byte for the terminating zero if we want * to use -[initWithUTF8StringNoCopy:length:freeWhenDone:]. */ if (SIZE_MAX - (size_t)fileSize < 1) @throw [OFOutOfRangeException exception]; - tmp = OFAllocMemory((size_t)fileSize + 1, 1); - @try { - file = [[OFFile alloc] initWithPath: path mode: @"r"]; - [file readIntoBuffer: tmp - exactLength: (size_t)fileSize]; - } @catch (id e) { - OFFreeMemory(tmp); - @throw e; - } @finally { - [file release]; - } - - tmp[(size_t)fileSize] = '\0'; - } @catch (id e) { - [self release]; + [file seekToOffset: 0 whence: OFSeekSet]; + + buffer = OFAllocMemory((size_t)fileSize + 1, 1); + [file readIntoBuffer: buffer exactLength: (size_t)fileSize]; + buffer[(size_t)fileSize] = '\0'; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + OFFreeMemory(buffer); + [self release]; + @throw e; } if (encoding == OFStringEncodingUTF8) { @try { - self = [self initWithUTF8StringNoCopy: tmp + self = [self initWithUTF8StringNoCopy: buffer length: (size_t)fileSize freeWhenDone: true]; } @catch (id e) { - OFFreeMemory(tmp); + OFFreeMemory(buffer); @throw e; } } else { @try { - self = [self initWithCString: tmp + self = [self initWithCString: buffer encoding: encoding length: (size_t)fileSize]; } @finally { - OFFreeMemory(tmp); + OFFreeMemory(buffer); } } 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; } @@ -1091,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; } @@ -1697,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]; } @@ -2441,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. @@ -2457,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) @@ -2494,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. @@ -2510,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) @@ -2739,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 @@ -192,18 +192,23 @@ * @brief Closes the write direction of the subprocess. * * This method needs to be called for some programs before data can be read, * since some programs don't start processing before the write direction is * closed. + * + * @throw OFNotOpenException The subprocess was already closed */ - (void)closeForWriting; /** * @brief Waits for the subprocess to terminate and returns the exit status. * * If the subprocess has already exited, this returns the exit status * immediately. + * + * @return The status code of the subprocess + * @throw OFNotOpenException The subprocess was already closed */ - (int)waitForTermination; @end OF_ASSUME_NONNULL_END 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,34 +46,47 @@ #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 #endif + +#if !defined(PATH_MAX) && defined(MAX_PATH) +# define PATH_MAX MAX_PATH +#endif #if defined(OF_MACOS) || defined(OF_IOS) /* * These have been dropped from newer iOS SDKs, however, their replacements are * not available on iOS < 10. This means it's impossible to search for the @@ -95,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 @@ -125,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 @@ -224,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) ); @@ -362,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; @@ -404,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; @@ -494,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]; @@ -570,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; @@ -635,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) @@ -694,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 @@ -154,12 +154,12 @@ /** * @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 OFConnectionFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFConnectIPSocketFailedException Connecting failed + * @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 - * @throw OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @return The address the socket was bound to + * @throw OFBindIPSocketFailedException Binding failed + * @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 @@ -29,24 +29,24 @@ #ifdef HAVE_FCNTL_H # include #endif #import "OFTCPSocket.h" +#import "OFAsyncIPSocketConnector.h" #import "OFDNSResolver.h" #import "OFData.h" #import "OFDate.h" -#import "OFIPSocketAsyncConnector.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFString.h" #import "OFTCPSocketSOCKS5Connector.h" #import "OFThread.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindIPSocketFailedException.h" #import "OFGetOptionFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" #import "OFSetOptionFailedException.h" @@ -54,11 +54,11 @@ @"OFTCPSocketConnectRunLoopMode"; static OFString *defaultSOCKS5Host = nil; static uint16_t defaultSOCKS5Port = 1080; -@interface OFTCPSocket () +@interface OFTCPSocket () @end @interface OFTCPSocketConnectDelegate: OFObject { @public @@ -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(); @@ -234,11 +234,11 @@ host = _SOCKS5Host; port = _SOCKS5Port; } else delegate = _delegate; - [[[[OFIPSocketAsyncConnector alloc] + [[[[OFAsyncIPSocketConnector alloc] initWithSocket: self host: host port: port delegate: delegate block: NULL @@ -275,11 +275,11 @@ block: block] autorelease]; host = _SOCKS5Host; port = _SOCKS5Port; } - [[[[OFIPSocketAsyncConnector alloc] + [[[[OFAsyncIPSocketConnector alloc] initWithSocket: self host: host port: port delegate: delegate block: (delegate == nil ? block : NULL)] autorelease] @@ -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]; @@ -309,16 +309,16 @@ socketAddresses = [[OFThread DNSResolver] resolveAddressesForHost: host addressFamily: OFSocketAddressFamilyAny]; address = *(OFSocketAddress *)[socketAddresses itemAtIndex: 0]; - OFSocketAddressSetPort(&address, port); + OFSocketAddressSetIPPort(&address, port); if ((_socket = socket( ((struct sockaddr *)&address.sockaddr)->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) - @throw [OFBindFailedException + @throw [OFBindIPSocketFailedException exceptionWithHost: host port: port socket: self errNo: OFSocketErrNo()]; @@ -340,14 +340,15 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: errNo]; + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: errNo]; } #if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) } else { for (;;) { uint16_t rnd = 0; @@ -354,40 +355,33 @@ int ret; while (rnd < 1024) rnd = (uint16_t)rand(); - OFSocketAddressSetPort(&address, rnd); + 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); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException + @throw [OFBindIPSocketFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } } } #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, @@ -395,40 +389,40 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithHost: host - port: port - 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 [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: EAFNOSUPPORT]; - } -#else - closesocket(_socket); - _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithHost: host - port: port - socket: self - errNo: EADDRNOTAVAIL]; -#endif + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port + socket: self + errNo: EAFNOSUPPORT]; + } +#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 @@ -13,19 +13,18 @@ * file. */ #include "config.h" -#include #include #import "OFTCPSocketSOCKS5Connector.h" #import "OFData.h" #import "OFRunLoop.h" #import "OFString.h" -#import "OFConnectionFailedException.h" +#import "OFConnectIPSocketFailedException.h" enum { stateSendAuthentication = 1, stateReadVersion, stateSendRequest, @@ -142,11 +141,11 @@ switch (_SOCKS5State) { case stateReadVersion: SOCKSVersion = buffer; if (SOCKSVersion[0] != 5 || SOCKSVersion[1] != 0) { - _exception = [[OFConnectionFailedException alloc] + _exception = [[OFConnectIPSocketFailedException alloc] initWithHost: _host port: _port socket: self errNo: EPROTONOSUPPORT]; [self didConnect]; @@ -171,11 +170,11 @@ return false; case stateReadResponse: response = buffer; if (response[0] != 5 || response[2] != 0) { - _exception = [[OFConnectionFailedException alloc] + _exception = [[OFConnectIPSocketFailedException alloc] initWithHost: _host port: _port socket: self errNo: EPROTONOSUPPORT]; [self didConnect]; @@ -214,11 +213,11 @@ errNo = 0; #endif break; } - _exception = [[OFConnectionFailedException alloc] + _exception = [[OFConnectIPSocketFailedException alloc] initWithHost: _host port: _port socket: _socket errNo: errNo]; [self didConnect]; @@ -244,11 +243,11 @@ [_socket asyncReadIntoBuffer: _buffer exactLength: 16 + 2 runLoopMode: runLoopMode]; return false; default: - _exception = [[OFConnectionFailedException alloc] + _exception = [[OFConnectIPSocketFailedException alloc] initWithHost: _host port: _port socket: self errNo: EPROTONOSUPPORT]; [self didConnect]; @@ -266,11 +265,11 @@ [_socket asyncReadIntoBuffer: _buffer exactLength: addressLength[0] + 2 runLoopMode: runLoopMode]; return false; default: - assert(0); + OFAssert(0); return false; } } - (OFData *)stream: (OFStream *)sock @@ -303,10 +302,10 @@ [_socket asyncReadIntoBuffer: _buffer exactLength: 4 runLoopMode: runLoopMode]; return nil; default: - assert(0); + OFAssert(0); return nil; } } @end 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 @@ -126,28 +126,33 @@ /** * @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 OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host; /** * @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 * @param runLoopMode The run loop mode in which to perform the async handshake + * @throw OFTLSHandshakeFailedException The TLS handshake failed + * @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 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 @@ -48,53 +44,49 @@ /** * @brief The encoding to use for the archive. Defaults to UTF-8. */ @property (nonatomic) OFStringEncoding encoding; -/** - * @brief A stream for reading the current entry. - * - * @note This is only available in read mode. - * - * @note The returned stream conforms to @ref OFReadyForReadingObserving if the - * underlying stream does so, too. - */ -@property (readonly, nonatomic) OFStream *streamForReadingCurrentEntry; - /** * @brief Creates a new OFTarArchive object with the specified stream. * * @param stream A stream from which the tar archive will be read. * For append mode, this needs to be an OFSeekableStream. * @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)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 @@ -104,25 +96,31 @@ * For append mode, this needs to be an OFSeekableStream. * @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)initWithStream: (OFStream *)stream mode: (OFString *)mode OF_DESIGNATED_INITIALIZER; /** * @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. * @@ -134,13 +132,26 @@ * invalidated stream will throw an @ref OFReadFailedException or * @ref OFWriteFailedException! * * @return The next entry from the tar archive or `nil` if all entries have * been read + * @throw OFInvalidFormatException The archive has an invalid format */ - (nullable OFTarArchiveEntry *)nextEntry; +/** + * @brief Returns a stream for reading the current entry. + * + * @note This is only available in read mode. + * + * @note The returned stream conforms to @ref OFReadyForReadingObserving if the + * underlying stream does so, too. + * + * @return A stream for reading the current entry + */ +- (OFStream *)streamForReadingCurrentEntry; + /** * @brief Returns a stream for writing the specified entry. * * @note This is only available in write and append mode. * @@ -158,10 +169,12 @@ */ - (OFStream *)streamForWritingEntry: (OFTarArchiveEntry *)entry; /** * @brief Closes the OFTarArchive. + * + * @throw OFNotOpenException The archive is not open */ - (void)close; @end OF_ASSUME_NONNULL_END 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 @@ -73,10 +73,16 @@ return value; } @implementation OFTarArchiveEntry +/* + * The following is optional in OFArchiveEntry, but Apple GCC 4.0.1 is buggy + * and needs this to stop complaining. + */ +@dynamic fileComment; + - (instancetype)init { OF_INVALID_INIT_METHOD } DELETED src/OFTarURIHandler.h Index: src/OFTarURIHandler.h ================================================================== --- src/OFTarURIHandler.h +++ src/OFTarURIHandler.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 OFTarURIHandler: OFURIHandler -@end - -OF_ASSUME_NONNULL_END 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 @@ -132,26 +132,36 @@ * @note This has to be set before the thread is started! * * This is a value between -1.0 (meaning lowest priority that still schedules) * and +1.0 (meaning highest priority that still allows getting preempted) * with normal priority being 0.0 (meaning being the same as the main thread). + * + * @throw OFThreadStillRunningException The thread is already/still running and + * thus the priority cannot be changed */ @property (nonatomic) float priority; /** * @brief The stack size of the thread. * * @note This has to be set before the thread is started! + * + * @throw OFThreadStillRunningException The thread is already/still running and + * thus the stack size cannot be changed */ @property (nonatomic) size_t stackSize; /** * @brief Whether the thread supports sockets. * * Some operating systems such as AmigaOS need special per-thread * initialization of sockets. If you intend to use sockets in the thread, set * this property to true before starting the thread. + * + * @throw OFThreadStillRunningException The thread is already/still running and + * thus the sockets support cannot be + * enabled/disabled */ @property (nonatomic) bool supportsSockets; /** * @brief Creates a new thread. @@ -241,10 +251,11 @@ /** * @brief Terminates the current thread, letting it return the specified object. * * @param object The object which the terminated thread will return + * @throw OFInvalidArgumentException The method was called from the main thread */ + (void)terminateWithObject: (nullable id)object OF_NO_RETURN; /** * @brief Sets the name of the current thread. @@ -288,20 +299,24 @@ */ - (void)handleTermination OF_REQUIRES_SUPER; /** * @brief Starts the thread. + * + * @throw OFStartThreadFailedException Starting the thread failed + * @throw OFThreadStillRunningException The thread is still running */ - (void)start; /** * @brief Joins a thread. * * @return The object returned by the main method of the thread. + * @throw OFJoinThreadFailedException Joining the thread failed */ - (id)join; #else - (instancetype)init OF_UNAVAILABLE; #endif @end OF_ASSUME_NONNULL_END 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 @@ -73,12 +75,12 @@ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFOutOfRangeException.h" #ifdef OF_HAVE_THREADS -# import "OFThreadJoinFailedException.h" -# import "OFThreadStartFailedException.h" +# import "OFJoinThreadFailedException.h" +# import "OFStartThreadFailedException.h" # import "OFThreadStillRunningException.h" #endif #ifdef OF_MINT /* freemint-gcc does not have trunc() */ @@ -435,11 +437,11 @@ _running = OFThreadStateRunning; if ((error = OFPlainThreadNew(&_thread, [_name cStringWithEncoding: [OFLocale encoding]], callMain, self, &_attr)) != 0) { [self release]; - @throw [OFThreadStartFailedException + @throw [OFStartThreadFailedException exceptionWithThread: self errNo: error]; } } @@ -446,16 +448,16 @@ - (id)join { int error; if (_running == OFThreadStateNotRunning) - @throw [OFThreadJoinFailedException + @throw [OFJoinThreadFailedException exceptionWithThread: self errNo: EINVAL]; if ((error = OFPlainThreadJoin(_thread)) != 0) - @throw [OFThreadJoinFailedException exceptionWithThread: self + @throw [OFJoinThreadFailedException exceptionWithThread: self errNo: error]; _running = OFThreadStateNotRunning; return _returnValue; 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 @@ -15,12 +15,10 @@ #include "config.h" #include -#include - #import "OFTimer.h" #import "OFTimer+Private.h" #import "OFDate.h" #import "OFRunLoop.h" #import "OFRunLoop+Private.h" @@ -485,12 +483,12 @@ { /* * The run loop references the timer, so it should never be deallocated * if it is still in a run loop. */ - assert(_inRunLoop == nil); - assert(_inRunLoopMode == nil); + OFAssert(_inRunLoop == nil); + OFAssert(_inRunLoopMode == nil); [_fireDate release]; [_target release]; [_object1 release]; [_object2 release]; 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 @@ -33,11 +33,11 @@ * @brief A class which provides methods to create and use UDP sockets. * * Addresses are of type @ref OFSocketAddress. You can use the current thread's * @ref OFDNSResolver to create an address for a host / port pair, * @ref OFSocketAddressString to get the IP address string for an address and - * @ref OFSocketAddressPort to get the port for an address. If you want to + * @ref OFSocketAddressIPPort to get the port for an address. If you want to * compare two addresses, you can use * @ref OFSocketAddressEqual and you can use @ref OFSocketAddressHash to get a * hash to use in e.g. @ref OFMapTable. * * @warning Even though the OFCopying protocol is implemented, it does *not* @@ -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 - * @throw OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @return The address the socket was bound to + * @throw OFBindIPSocketFailedException Binding failed + * @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,31 +32,33 @@ #import "OFData.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFThread.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.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) - @throw [OFBindFailedException + @throw [OFBindIPSocketFailedException exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressPort(address) + port: OFSocketAddressIPPort(address) socket: self errNo: OFSocketErrNo()]; _canBlock = true; @@ -66,22 +68,22 @@ fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); } #endif #if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) - if (OFSocketAddressPort(address) != 0) { + if (OFSocketAddressIPPort(address) != 0) { #endif if (bind(_socket, (struct sockaddr *)&address->sockaddr, address->length) != 0) { int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException + @throw [OFBindIPSocketFailedException exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressPort(address) + port: OFSocketAddressIPPort(address) socket: self errNo: errNo]; } #if defined(OF_HPUX) || defined(OF_WII) || defined(OF_NINTENDO_3DS) } else { @@ -90,41 +92,39 @@ int ret; while (rnd < 1024) rnd = (uint16_t)rand(); - OFSocketAddressSetPort(address, rnd); + OFSocketAddressSetIPPort(address, rnd); if ((ret = bind(_socket, (struct sockaddr *)&address->sockaddr, address->length)) == 0) break; if (OFSocketErrNo() != EADDRINUSE) { int errNo = OFSocketErrNo(); OFString *host = OFSocketAddressString(address); - port = OFSocketAddressPort(address); + uint16_t port = OFSocketAddressIPPort(address); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException + @throw [OFBindIPSocketFailedException exceptionWithHost: host port: port socket: self errNo: errNo]; } } } #endif - objc_autoreleasePoolPop(pool); - - if ((port = OFSocketAddressPort(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 [OFBindFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressPort(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 [OFBindFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressPort(address) + @throw [OFBindIPSocketFailedException + exceptionWithHost: host + port: port socket: self errNo: EAFNOSUPPORT]; } -#else - closesocket(_socket); - _socket = OFInvalidSocketHandle; - - @throw [OFBindFailedException - exceptionWithHost: OFSocketAddressString(address) - port: OFSocketAddressPort(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]; - OFSocketAddressSetPort(&address, port); + 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 @@ -61,14 +61,15 @@ id delegate; /** * @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 OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already bound + * @param path The path to bind to or `nil` for an anonymous socket + * @return The address on which this socket can be reached, if a path was + * specified + * @throw OFBindUNIXSocketFailedException Binding failed + * @throw OFAlreadyOpenException The socket is already bound */ -- (OFSocketAddress)bindToPath: (OFString *)path; +- (OFSocketAddress)bindToPath: (nullable 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,12 +22,12 @@ #import "OFUNIXDatagramSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFString.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindUNIXSocketFailedException.h" @implementation OFUNIXDatagramSocket @dynamic delegate; - (OFSocketAddress)bindToPath: (OFString *)path @@ -36,17 +36,22 @@ #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 (path != nil) + address = OFSocketAddressMakeUNIX(path); + else { + address.family = OFSocketAddressFamilyUnknown; + address.length = 0; + } - if ((_socket = socket(address.sockaddr.un.sun_family, - SOCK_DGRAM | SOCK_CLOEXEC, 0)) == OFInvalidSocketHandle) - @throw [OFBindFailedException + if ((_socket = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == + OFInvalidSocketHandle) + @throw [OFBindUNIXSocketFailedException exceptionWithPath: path socket: self errNo: OFSocketErrNo()]; _canBlock = true; @@ -54,20 +59,23 @@ #if SOCK_CLOEXEC == 0 && defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) if ((flags = fcntl(_socket, F_GETFD, 0)) != -1) fcntl(_socket, F_SETFD, flags | FD_CLOEXEC); #endif - if (bind(_socket, (struct sockaddr *)&address.sockaddr, - address.length) != 0) { - int errNo = OFSocketErrNo(); - - closesocket(_socket); - _socket = OFInvalidSocketHandle; - - @throw [OFBindFailedException exceptionWithPath: path - socket: self - errNo: errNo]; + if (path != nil) { + if (bind(_socket, (struct sockaddr *)&address.sockaddr, + address.length) != 0) { + int errNo = OFSocketErrNo(); + + closesocket(_socket); + _socket = OFInvalidSocketHandle; + + @throw [OFBindUNIXSocketFailedException + exceptionWithPath: path + socket: self + errNo: errNo]; + } } return address; } @end 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 @@ -52,21 +52,21 @@ /** * @brief Connects the OFUNIXStreamSocket to the specified destination. * * @param path The path to connect to - * @throw OFConnectionFailedException Connecting failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFConnectUNIXSocketFailedException Connecting failed + * @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 OFBindFailedException Binding failed - * @throw OFAlreadyConnectedException The socket is already connected or bound + * @throw OFBindUNIXSocketFailedException Binding failed + * @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,13 +22,13 @@ #import "OFUNIXStreamSocket.h" #import "OFSocket.h" #import "OFSocket+Private.h" #import "OFString.h" -#import "OFAlreadyConnectedException.h" -#import "OFBindFailedException.h" -#import "OFConnectionFailedException.h" +#import "OFAlreadyOpenException.h" +#import "OFBindUNIXSocketFailedException.h" +#import "OFConnectUNIXSocketFailedException.h" @implementation OFUNIXStreamSocket @dynamic delegate; - (void)connectToPath: (OFString *)path @@ -37,17 +37,17 @@ #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) - @throw [OFConnectionFailedException + @throw [OFConnectUNIXSocketFailedException exceptionWithPath: path socket: self errNo: OFSocketErrNo()]; _canBlock = true; @@ -62,13 +62,14 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFConnectionFailedException exceptionWithPath: path - socket: self - errNo: errNo]; + @throw [OFConnectUNIXSocketFailedException + exceptionWithPath: path + socket: self + errNo: errNo]; } } - (void)bindToPath: (OFString *)path { @@ -76,17 +77,17 @@ #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) - @throw [OFBindFailedException + @throw [OFBindUNIXSocketFailedException exceptionWithPath: path socket: self errNo: OFSocketErrNo()]; _canBlock = true; @@ -101,11 +102,12 @@ int errNo = OFSocketErrNo(); closesocket(_socket); _socket = OFInvalidSocketHandle; - @throw [OFBindFailedException exceptionWithPath: path - socket: self - errNo: errNo]; + @throw [OFBindUNIXSocketFailedException + exceptionWithPath: path + socket: self + errNo: errNo]; } } @end 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,385 +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 - */ -+ (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 - */ -- (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 @@ -77,10 +77,11 @@ * @param accessRights Please refer to the `RegOpenKeyEx()` documentation for * `samDesired` * @param options Please refer to the `RegOpenKeyEx()` documentation for * `ulOptions`. Usually 0. * @return The subkey with the specified path + * @throw OFOpenWindowsRegistryKeyFailedException Opening the key failed */ - (OFWindowsRegistryKey *)openSubkeyAtPath: (OFString *)path accessRights: (REGSAM)accessRights options: (DWORD)options; /** @@ -98,10 +99,11 @@ * @param disposition A pointer to a variable that will be set to whether the * key was created or already existed, or `NULL`. Please * refer to the `RegCreateKeyEx()` documentation for * `lpdwDisposition`. * @return The subkey with the specified path + * @throw OFCreateWindowsRegistryKeyFailedException Creating the key failed */ - (OFWindowsRegistryKey *) createSubkeyAtPath: (OFString *)path accessRights: (REGSAM)accessRights securityAttributes: (nullable SECURITY_ATTRIBUTES *)securityAttributes @@ -112,10 +114,11 @@ * @brief Returns the data for the specified value at the specified path. * * @param name The name of the value to return * @param type A pointer to store the type of the value, or NULL * @return The data for the specified value + * @throw OFGetWindowsRegistryValueFailedException Getting the value failed */ - (nullable OFData *)dataForValueNamed: (nullable OFString *)name type: (nullable DWORD *)type; /** @@ -122,10 +125,11 @@ * @brief Sets the data for the specified value. * * @param data The data to set the value to * @param name The name of the value to set * @param type The type for the value + * @throw OFSetWindowsRegistryValueFailedException Setting the value failed */ - (void)setData: (nullable OFData *)data forValueNamed: (nullable OFString *)name type: (DWORD)type; @@ -132,28 +136,33 @@ /** * @brief Returns the string for the specified value at the specified path. * * @param name The name of the value to return * @return The string for the specified value + * @throw OFGetWindowsRegistryValueFailedException Getting the value failed + * @throw OFInvalidEncodingException The encoding of the value is invalid */ - (nullable OFString *)stringForValueNamed: (nullable OFString *)name; /** * @brief Returns the string for the specified value at the specified path. * * @param name The name of the value to return * @param type A pointer to store the type of the value, or NULL * @return The string for the specified value + * @throw OFGetWindowsRegistryValueFailedException Getting the value failed + * @throw OFInvalidEncodingException The encoding of the value is invalid */ - (nullable OFString *)stringForValueNamed: (nullable OFString *)name type: (nullable DWORD *)type; /** * @brief Sets the string for the specified value. * * @param string The string to set the value to * @param name The name of the value to set + * @throw OFSetWindowsRegistryValueFailedException Setting the value failed */ - (void)setString: (nullable OFString *)string forValueNamed: (nullable OFString *)name; /** @@ -160,10 +169,11 @@ * @brief Sets the string for the specified value. * * @param string The string to set the value to * @param name The name of the value to set * @param type The type for the value + * @throw OFSetWindowsRegistryValueFailedException Setting the value failed */ - (void)setString: (nullable OFString *)string forValueNamed: (nullable OFString *)name type: (DWORD)type; @@ -170,48 +180,56 @@ /** * @brief Returns the DWORD for the specified value at the specified path. * * @param name The name of the value to return * @return The DWORD for the specified value + * @throw OFGetWindowsRegistryValueFailedException Getting the value failed + * @throw OFUndefinedKeyException There is no value with the specified key */ - (uint32_t)DWORDForValueNamed: (nullable OFString *)name; /** * @brief Sets the DWORD for the specified value. * * @param dword The DWORD to set the value to * @param name The name of the value to set + * @throw OFSetWindowsRegistryValueFailedException Setting the value failed */ - (void)setDWORD: (uint32_t)dword forValueNamed: (nullable OFString *)name; /** * @brief Returns the QWORD for the specified value at the specified path. * * @param name The name of the value to return * @return The QWORD for the specified value + * @throw OFGetWindowsRegistryValueFailedException Getting the value failed + * @throw OFUndefinedKeyException There is no value with the specified key */ - (uint64_t)QWORDForValueNamed: (nullable OFString *)name; /** * @brief Sets the QWORD for the specified value. * * @param qword The QWORD to set the value to * @param name The name of the value to set + * @throw OFSetWindowsRegistryValueFailedException Setting the value failed */ - (void)setQWORD: (uint64_t)qword forValueNamed: (nullable OFString *)name; /** * @brief Deletes the specified value. * * @param name The value to delete + * @throw OFDeleteWindowsRegistryValueFailedException Deleting the value failed */ - (void)deleteValueNamed: (nullable OFString *)name; /** * @brief Deletes the specified subkey. * * @param subkeyPath The path of the subkey to delete + * @throw OFDeleteWindowsRegistryKeyFailedException Deleting the key failed */ - (void)deleteSubkeyAtPath: (OFString *)subkeyPath; @end OF_ASSUME_NONNULL_END 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 @@ -119,19 +119,27 @@ /** * @brief Parses the string and returns an OFXMLElement for it. * * @param string The string to parse * @return A new autoreleased OFXMLElement with the contents of the string + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ + (instancetype)elementWithXMLString: (OFString *)string; /** * @brief Parses the specified stream and returns an OFXMLElement for it. * * @param stream The stream to parse * @return A new autoreleased OFXMLElement with the contents of the specified * stream + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ + (instancetype)elementWithStream: (OFStream *)stream; - (instancetype)init OF_UNAVAILABLE; @@ -186,19 +194,27 @@ * @brief Parses the string and initializes an already allocated OFXMLElement * with it. * * @param string The string to parse * @return An initialized OFXMLElement with the contents of the string + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (instancetype)initWithXMLString: (OFString *)string; /** * @brief Parses the specified stream and initializes an already allocated * OFXMLElement with it. * * @param stream The stream to parse * @return An initialized OFXMLElement with the contents of the specified stream + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (instancetype)initWithStream: (OFStream *)stream; /** * @brief Sets a prefix for a namespace. @@ -393,10 +409,13 @@ * with the specified indentation per level. * * @param indentation The indentation per level * @return An OFString representing the OFXMLNode as an XML string with * indentation + * @throw OFUnboundNamespaceException The node uses a namespace that was not + * bound to a prefix in a context where it + * needs a prefix */ - (OFString *)XMLStringWithIndentation: (unsigned int)indentation; /** * @brief Returns an OFString representing the OFXMLElement as an XML string @@ -404,13 +423,14 @@ * * @param defaultNS The default namespace * @param indentation The indentation per level * @return An OFString representing the OFXMLNode as an XML string with * indentation + * @throw OFUnboundNamespaceException The node uses a namespace that was not + * bound to a prefix in a context where it + * needs a prefix */ - (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 @@ -18,12 +18,10 @@ #define OF_XML_ELEMENT_M #include #include -#include - #import "OFXMLElement.h" #import "OFArray.h" #import "OFData.h" #import "OFDictionary.h" #import "OFStream.h" @@ -38,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; @@ -267,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; } @@ -631,11 +524,11 @@ i += _name.UTF8StringLength; } else cString[i++] = '/'; cString[i++] = '>'; - assert(i == length); + OFAssert(i == length); objc_autoreleasePoolPop(pool); ret = [OFString stringWithUTF8String: cString length: length]; @@ -668,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) } /** @@ -38,35 +35,47 @@ */ @property (nonatomic, copy) OFString *stringValue; /** * @brief The contents of the receiver as a `long long` value. + * + * @throw OFInvalidFormatException The node cannot be parsed as a `long long` */ @property (readonly, nonatomic) long long longLongValue; /** * @brief The contents of the receiver as an `unsigned long long` value. + * + * @throw OFInvalidFormatException The node cannot be parsed as an + * `unsigned long long` */ @property (readonly, nonatomic) unsigned long long unsignedLongLongValue; /** * @brief The contents of the receiver as a float value. + * + * @throw OFInvalidFormatException The node cannot be parsed as a `float` */ @property (readonly, nonatomic) float floatValue; /** * @brief The contents of the receiver as a double value. + * + * @throw OFInvalidFormatException The node cannot be parsed as a `double` */ @property (readonly, nonatomic) double doubleValue; /** * @brief A string representing the node as an XML string. + * + * @throw OFUnboundNamespaceException The node uses a namespace that was not + * bound to a prefix in a context where it + * 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 @@ -185,24 +185,36 @@ /** * @brief Parses the specified buffer with the specified size. * * @param buffer The buffer to parse * @param length The length of the buffer + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseBuffer: (const char *)buffer length: (size_t)length; /** * @brief Parses the specified string. * * @param string The string to parse + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseString: (OFString *)string; /** * @brief Parses the specified stream. * * @param stream The stream to parse + * @throw OFMalformedXMLException The XML was malformed + * @throw OFUnboundPrefixException A prefix was used that was not bound to any + * namespace + * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseStream: (OFStream *)stream; @end OF_ASSUME_NONNULL_END 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 @@ -76,34 +76,36 @@ * For read and append mode, this needs to be an OFSeekableStream. * @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)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 @@ -113,25 +115,27 @@ * For read and append mode, this needs to be an OFSeekableStream. * @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)initWithStream: (OFStream *)stream mode: (OFString *)mode OF_DESIGNATED_INITIALIZER; /** * @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. @@ -145,10 +149,18 @@ * invalidated stream will throw an @ref OFReadFailedException or * @ref OFWriteFailedException! * * @param path The path to the file inside the archive * @return A stream for reading the specified file form the archive + * @throw OFNotOpenException The archive is not open + * @throw OFInvalidArgumentException The archive is not in read mode + * @throw OFOpenItemFailedException Opening the specified file within the + * archive failed + * @throw OFInvalidFormatException The local header and the header in the + * central directory do not match enough + * @throw OFUnsupportedVersionException The file uses a version of the ZIP + * format that is not supported */ - (OFStream *)streamForReadingFile: (OFString *)path; /** * @brief Returns a stream for writing the specified entry to the archive. @@ -171,15 +183,27 @@ * * The compressed size. * * The uncompressed size. * * The CRC32. * * 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 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; /** * @brief Closes the OFZIPArchive. + * + * @throw OFNotOpenException The archive is not open */ - (void)close; @end #ifdef __cplusplus 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 @@ -170,10 +170,17 @@ *size = 0; return OFNotFound; } @implementation OFZIPArchiveEntry +/* + * The following are optional in OFArchiveEntry, but Apple GCC 4.0.1 is buggy + * and needs this to stop complaining. + */ +@dynamic POSIXPermissions, ownerAccountID, groupOwnerAccountID; +@dynamic ownerAccountName, groupOwnerAccountName; + - (instancetype)init { OF_INVALID_INIT_METHOD } 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" @@ -82,24 +82,23 @@ # import "OFKernelEventObserver.h" # import "OFDNSQuery.h" # import "OFDNSResourceRecord.h" # import "OFDNSResponse.h" # import "OFDNSResolver.h" +# ifdef OF_HAVE_UNIX_SOCKETS +# import "OFUNIXDatagramSocket.h" +# import "OFUNIXStreamSocket.h" +# endif # ifdef OF_HAVE_IPX # import "OFIPXSocket.h" # import "OFSPXSocket.h" # import "OFSPXStreamSocket.h" # endif -# ifdef OF_HAVE_UNIX_SOCKETS -# import "OFUNIXDatagramSocket.h" -# import "OFUNIXStreamSocket.h" -# endif -#endif -#ifdef OF_HAVE_SOCKETS -# ifdef OF_HAVE_THREADS -# import "OFHTTPClient.h" -# endif +# ifdef OF_HAVE_APPLETALK +# import "OFDDPSocket.h" +# endif +# import "OFHTTPClient.h" # import "OFHTTPCookie.h" # import "OFHTTPCookieManager.h" # import "OFHTTPRequest.h" # import "OFHTTPResponse.h" # import "OFHTTPServer.h" @@ -137,120 +136,110 @@ #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" -#ifdef OF_HAVE_SOCKETS -# import "OFAcceptFailedException.h" -# import "OFAlreadyConnectedException.h" -# import "OFBindFailedException.h" -#endif #import "OFChangeCurrentDirectoryFailedException.h" #import "OFChecksumMismatchException.h" -#ifdef OF_HAVE_THREADS -# import "OFConditionBroadcastFailedException.h" -# import "OFConditionSignalFailedException.h" -# import "OFConditionStillWaitingException.h" -# import "OFConditionWaitFailedException.h" -#endif -#ifdef OF_HAVE_SOCKETS -# import "OFConnectionFailedException.h" -#endif #import "OFCopyItemFailedException.h" #import "OFCreateDirectoryFailedException.h" #import "OFCreateSymbolicLinkFailedException.h" -#ifdef OF_WINDOWS -# import "OFCreateWindowsRegistryKeyFailedException.h" -#endif -#ifdef OF_HAVE_SOCKETS -# import "OFDNSQueryFailedException.h" -#endif -#ifdef OF_WINDOWS -# import "OFDeleteWindowsRegistryKeyFailedException.h" -# import "OFDeleteWindowsRegistryValueFailedException.h" -#endif #import "OFEnumerationMutationException.h" #ifdef OF_HAVE_FILES # import "OFGetCurrentDirectoryFailedException.h" #endif #import "OFGetItemAttributesFailedException.h" #import "OFGetOptionFailedException.h" -#ifdef OF_WINDOWS -# import "OFGetWindowsRegistryValueFailedException.h" -#endif #import "OFHashAlreadyCalculatedException.h" #import "OFHashNotCalculatedException.h" -#ifdef OF_HAVE_SOCKETS -# import "OFHTTPRequestFailedException.h" -#endif #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidEncodingException.h" #import "OFInvalidFormatException.h" #import "OFInvalidJSONException.h" #import "OFInvalidServerResponseException.h" #import "OFLinkItemFailedException.h" -#ifdef OF_HAVE_SOCKETS -# import "OFListenFailedException.h" -#endif #ifdef OF_HAVE_PLUGINS # import "OFLoadPluginFailedException.h" #endif #import "OFLockFailedException.h" #import "OFMalformedXMLException.h" #import "OFMoveItemFailedException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" -#ifdef OF_HAVE_SOCKETS -# import "OFObserveKernelEventsFailedException.h" -#endif #import "OFOpenItemFailedException.h" -#ifdef OF_WINDOWS -# import "OFOpenWindowsRegistryKeyFailedException.h" -#endif #import "OFOutOfMemoryException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFReadOrWriteFailedException.h" #import "OFRemoveItemFailedException.h" -#ifdef OF_HAVE_SOCKETS -# import "OFResolveHostFailedException.h" -#endif #import "OFSeekFailedException.h" #import "OFSetItemAttributesFailedException.h" #import "OFSetOptionFailedException.h" -#ifdef OF_WINDOWS -# import "OFSetWindowsRegistryValueFailedException.h" -#endif #import "OFStillLockedException.h" -#ifdef OF_HAVE_THREADS -# import "OFThreadJoinFailedException.h" -# import "OFThreadStartFailedException.h" -# import "OFThreadStillRunningException.h" -#endif -#ifdef OF_HAVE_SOCKETS -# import "OFTLSHandshakeFailedException.h" -#endif #import "OFTruncatedDataException.h" #import "OFUnboundNamespaceException.h" #import "OFUnboundPrefixException.h" #import "OFUndefinedKeyException.h" #import "OFUnknownXMLEntityException.h" #import "OFUnlockFailedException.h" #import "OFUnsupportedProtocolException.h" #import "OFUnsupportedVersionException.h" #import "OFWriteFailedException.h" - +#ifdef OF_HAVE_SOCKETS +# import "OFAcceptSocketFailedException.h" +# import "OFBindIPSocketFailedException.h" +# import "OFBindSocketFailedException.h" +# import "OFConnectIPSocketFailedException.h" +# import "OFConnectSocketFailedException.h" +# import "OFDNSQueryFailedException.h" +# import "OFHTTPRequestFailedException.h" +# import "OFListenOnSocketFailedException.h" +# import "OFObserveKernelEventsFailedException.h" +# import "OFResolveHostFailedException.h" +# import "OFTLSHandshakeFailedException.h" +# ifdef OF_HAVE_UNIX_SOCKETS +# import "OFBindUNIXSocketFailedException.h" +# import "OFConnectUNIXSocketFailedException.h" +# endif +# ifdef OF_HAVE_IPX +# import "OFBindIPXSocketFailedException.h" +# import "OFConnectSPXSocketFailedException.h" +# endif +# ifdef OF_HAVE_APPLETALK +# import "OFBindDDPSocketFailedException.h" +# endif +#endif +#ifdef OF_HAVE_THREADS +# import "OFBroadcastConditionFailedException.h" +# import "OFConditionStillWaitingException.h" +# import "OFJoinThreadFailedException.h" +# import "OFSignalConditionFailedException.h" +# import "OFStartThreadFailedException.h" +# import "OFThreadStillRunningException.h" +# import "OFWaitForConditionFailedException.h" +#endif #ifdef OF_HAVE_PLUGINS # import "OFPlugin.h" #endif +#ifdef OF_WINDOWS +# import "OFCreateWindowsRegistryKeyFailedException.h" +# import "OFDeleteWindowsRegistryKeyFailedException.h" +# import "OFDeleteWindowsRegistryValueFailedException.h" +# import "OFGetWindowsRegistryValueFailedException.h" +# import "OFOpenWindowsRegistryKeyFailedException.h" +# import "OFSetWindowsRegistryValueFailedException.h" +#endif #ifdef OF_HAVE_ATOMIC_OPS # import "OFAtomic.h" #endif #import "OFLocking.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 @@ -2,10 +2,11 @@ STATIC_PIC_LIB_NOINST = ${EXCEPTIONS_LIB_A} STATIC_LIB_NOINST = ${EXCEPTIONS_A} SRCS = OFAllocFailedException.m \ + OFAlreadyOpenException.m \ OFChecksumMismatchException.m \ OFCopyItemFailedException.m \ OFCreateDirectoryFailedException.m \ OFCreateSymbolicLinkFailedException.m \ OFEnumerationMutationException.m \ @@ -51,36 +52,45 @@ ${USE_SRCS_THREADS} \ ${USE_SRCS_WINDOWS} SRCS_FILES = OFChangeCurrentDirectoryFailedException.m \ OFGetCurrentDirectoryFailedException.m SRCS_PLUGINS = OFLoadPluginFailedException.m -SRCS_SOCKETS = OFAcceptFailedException.m \ - OFAlreadyConnectedException.m \ - OFBindFailedException.m \ - OFConnectionFailedException.m \ +SRCS_SOCKETS = OFAcceptSocketFailedException.m \ + OFBindIPSocketFailedException.m \ + OFBindSocketFailedException.m \ + OFConnectIPSocketFailedException.m \ + OFConnectSocketFailedException.m \ OFDNSQueryFailedException.m \ OFHTTPRequestFailedException.m \ - OFListenFailedException.m \ + OFListenOnSocketFailedException.m \ OFObserveKernelEventsFailedException.m \ OFResolveHostFailedException.m \ - OFTLSHandshakeFailedException.m -SRCS_THREADS = OFConditionBroadcastFailedException.m \ - OFConditionSignalFailedException.m \ + OFTLSHandshakeFailedException.m \ + ${USE_SRCS_APPLETALK} \ + ${USE_SRCS_IPX} \ + ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFBindDDPSocketFailedException.m +SRCS_IPX = OFBindIPXSocketFailedException.m \ + OFConnectSPXSocketFailedException.m +SRCS_UNIX_SOCKETS = OFBindUNIXSocketFailedException.m \ + OFConnectUNIXSocketFailedException.m +SRCS_THREADS = OFBroadcastConditionFailedException.m \ OFConditionStillWaitingException.m \ - OFConditionWaitFailedException.m \ - OFThreadJoinFailedException.m \ - OFThreadStartFailedException.m \ - OFThreadStillRunningException.m + OFJoinThreadFailedException.m \ + OFSignalConditionFailedException.m \ + OFStartThreadFailedException.m \ + OFThreadStillRunningException.m \ + OFWaitForConditionFailedException.m SRCS_WINDOWS = OFCreateWindowsRegistryKeyFailedException.m \ OFDeleteWindowsRegistryKeyFailedException.m \ OFDeleteWindowsRegistryValueFailedException.m \ OFGetWindowsRegistryValueFailedException.m \ OFOpenWindowsRegistryKeyFailedException.m \ OFSetWindowsRegistryValueFailedException.m INCLUDES := ${SRCS:.m=.h} -SRCS += OFSandboxActivationFailedException.m +SRCS += OFActivateSandboxFailedException.m include ../../buildsys.mk CPPFLAGS += -I. -I.. -I../.. -I../runtime DELETED src/exceptions/OFAcceptFailedException.h Index: src/exceptions/OFAcceptFailedException.h ================================================================== --- src/exceptions/OFAcceptFailedException.h +++ src/exceptions/OFAcceptFailedException.h @@ -1,71 +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 OFAcceptFailedException \ - * OFAcceptFailedException.h ObjFW/OFAcceptFailedException.h - * - * @brief An exception indicating that accepting a connection failed. - */ -@interface OFAcceptFailedException: OFException -{ - id _socket; - int _errNo; - OF_RESERVE_IVARS(OFAcceptFailedException, 4) -} - -/** - * @brief The socket which could not accept a connection. - */ -@property (readonly, nonatomic) id socket; - -/** - * @brief The errno from when the exception was created. - */ -@property (readonly, nonatomic) int errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Creates a new, autoreleased accept failed exception. - * - * @param socket The socket which could not accept a connection - * @param errNo The errno for the error - * @return A new, autoreleased accept failed exception - */ -+ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated accept failed exception. - * - * @param socket The socket which could not accept a connection - * @param errNo The errno for the error - * @return An initialized accept failed exception - */ -- (instancetype)initWithSocket: (id)socket - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFAcceptFailedException.m Index: src/exceptions/OFAcceptFailedException.m ================================================================== --- src/exceptions/OFAcceptFailedException.m +++ src/exceptions/OFAcceptFailedException.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 "OFAcceptFailedException.h" -#import "OFString.h" - -@implementation OFAcceptFailedException -@synthesize socket = _socket, errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo -{ - return [[[self alloc] initWithSocket: socket errNo: errNo] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSocket: (id)socket errNo: (int)errNo -{ - self = [super init]; - - _socket = [socket retain]; - _errNo = errNo; - - return self; -} - -- (void)dealloc -{ - [_socket release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Failed to accept connection in socket of class %@: %@", - [_socket class], OFStrError(_errNo)]; -} -@end ADDED src/exceptions/OFAcceptSocketFailedException.h Index: src/exceptions/OFAcceptSocketFailedException.h ================================================================== --- src/exceptions/OFAcceptSocketFailedException.h +++ src/exceptions/OFAcceptSocketFailedException.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 OFAcceptSocketFailedException \ + * OFAcceptSocketFailedException.h ObjFW/OFAcceptSocketFailedException.h + * + * @brief An exception indicating that accepting a connection failed. + */ +@interface OFAcceptSocketFailedException: OFException +{ + id _socket; + int _errNo; + OF_RESERVE_IVARS(OFAcceptSocketFailedException, 4) +} + +/** + * @brief The socket which could not accept a connection. + */ +@property (readonly, nonatomic) id socket; + +/** + * @brief The errno from when the exception was created. + */ +@property (readonly, nonatomic) int errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Creates a new, autoreleased accept failed exception. + * + * @param socket The socket which could not accept a connection + * @param errNo The errno for the error + * @return A new, autoreleased accept failed exception + */ ++ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated accept failed exception. + * + * @param socket The socket which could not accept a connection + * @param errNo The errno for the error + * @return An initialized accept failed exception + */ +- (instancetype)initWithSocket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFAcceptSocketFailedException.m Index: src/exceptions/OFAcceptSocketFailedException.m ================================================================== --- src/exceptions/OFAcceptSocketFailedException.m +++ src/exceptions/OFAcceptSocketFailedException.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 "OFAcceptSocketFailedException.h" +#import "OFString.h" + +@implementation OFAcceptSocketFailedException +@synthesize socket = _socket, errNo = _errNo; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + return [[[self alloc] initWithSocket: sock errNo: errNo] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + self = [super init]; + + _socket = [sock retain]; + _errNo = errNo; + + return self; +} + +- (void)dealloc +{ + [_socket release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Failed to accept connection in socket of class %@: %@", + [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFActivateSandboxFailedException.h Index: src/exceptions/OFActivateSandboxFailedException.h ================================================================== --- src/exceptions/OFActivateSandboxFailedException.h +++ src/exceptions/OFActivateSandboxFailedException.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 OFSandbox; + +@interface OFActivateSandboxFailedException: OFException +{ + OFSandbox *_sandbox; + int _errNo; +} + +@property (readonly, nonatomic) OFSandbox *sandbox; +@property (readonly, nonatomic) int errNo; + ++ (instancetype)exception OF_UNAVAILABLE; ++ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo; +- (instancetype)init OF_UNAVAILABLE; +- (instancetype)initWithSandbox: (OFSandbox *)sandbox + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFActivateSandboxFailedException.m Index: src/exceptions/OFActivateSandboxFailedException.m ================================================================== --- src/exceptions/OFActivateSandboxFailedException.m +++ src/exceptions/OFActivateSandboxFailedException.m @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFActivateSandboxFailedException.h" +#import "OFString.h" +#import "OFSandbox.h" + +@implementation OFActivateSandboxFailedException +@synthesize sandbox = _sandbox, errNo = _errNo; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo +{ + return [[[self alloc] initWithSandbox: sandbox + errNo: errNo] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo +{ + self = [super init]; + + _sandbox = [sandbox retain]; + _errNo = errNo; + + return self; +} + +- (void)dealloc +{ + [_sandbox release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"The sandbox could not be applied: %@", OFStrError(_errNo)]; +} +@end 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)socket -{ - return [[[self alloc] initWithSocket: socket] autorelease]; -} - -- (instancetype)init -{ - return [self initWithSocket: nil]; -} - -- (instancetype)initWithSocket: (id)socket -{ - self = [super init]; - - _socket = [socket 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 ADDED src/exceptions/OFBindDDPSocketFailedException.h Index: src/exceptions/OFBindDDPSocketFailedException.h ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.h +++ src/exceptions/OFBindDDPSocketFailedException.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindDDPSocketFailedException \ + * OFBindDDPSocketFailedException.h \ + * ObjFW/OFBindDDPSocketFailedException.h + * + * @brief An exception indicating that binding a DDP socket failed. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFBindDDPSocketFailedException: OFBindSocketFailedException +{ + uint16_t _network; + uint8_t _node, _port, _protocolType; +} + +/** + * @brief The DDP network on which binding failed. + */ +@property (readonly, nonatomic) uint16_t network; + +/** + * @brief The DDP node for which binding failed. + */ +@property (readonly, nonatomic) uint8_t node; + +/** + * @brief The DDP port on which binding failed. + */ +@property (readonly, nonatomic) uint8_t port; + +/** + * @brief The DDP protocol type for which binding failed. + */ +@property (readonly, nonatomic) uint8_t protocolType; + +/** + * @brief Creates a new, autoreleased bind DDP socket failed exception. + * + * @param network The DDP network on which binding failed + * @param node The DDP node for which binding failed + * @param port The DDP port on which binding failed + * @param protocolType The DDP protocol type for which binding failed. + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind DDP socket failed exception + */ ++ (instancetype)exceptionWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + protocolType: (uint8_t)protocolType + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind DDP socket failed exception. + * + * @param network The DDP network on which binding failed + * @param node The DDP node for which binding failed + * @param port The DDP port on which binding failed + * @param protocolType The DDP protocol type for which binding failed. + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind DDP socket failed exception + */ +- (instancetype)initWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + protocolType: (uint8_t)protocolType + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindDDPSocketFailedException.m Index: src/exceptions/OFBindDDPSocketFailedException.m ================================================================== --- src/exceptions/OFBindDDPSocketFailedException.m +++ src/exceptions/OFBindDDPSocketFailedException.m @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindDDPSocketFailedException.h" +#import "OFData.h" +#import "OFString.h" + +@implementation OFBindDDPSocketFailedException +@synthesize network = _network, node = _node, port = _port; +@synthesize protocolType = _protocolType; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + protocolType: (uint8_t)protocolType + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithNetwork: network + node: node + port: port + protocolType: protocolType + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithNetwork: (uint16_t)network + node: (uint8_t)node + port: (uint8_t)port + protocolType: (uint8_t)protocolType + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _network = network; + _node = node; + _port = port; + _protocolType = protocolType; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Binding to port %" @PRIx8 @" of node %" @PRIx8 @" on network " + @"%" PRIx16 @" with protocol type 0x%" @PRIX8 @" failed in socket " + @"of type %@: %@", + _port, _node, _network, _protocolType, [_socket class], + OFStrError(_errNo)]; +} +@end DELETED src/exceptions/OFBindFailedException.h Index: src/exceptions/OFBindFailedException.h ================================================================== --- src/exceptions/OFBindFailedException.h +++ src/exceptions/OFBindFailedException.h @@ -1,160 +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 - -#import "OFSocket.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFBindFailedException \ - * OFBindFailedException.h ObjFW/OFBindFailedException.h - * - * @brief An exception indicating that binding a socket failed. - */ -@interface OFBindFailedException: OFException -{ - /* IP */ - OFString *_Nullable _host; - uint16_t _port; - /* IPX */ - uint8_t _packetType; - /* UNIX socket */ - OFString *_Nullable _path; - id _socket; - int _errNo; - OF_RESERVE_IVARS(OFBindFailedException, 4) -} - -/** - * @brief The host on which binding failed. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; - -/** - * @brief The port on which binding failed. - */ -@property (readonly, nonatomic) uint16_t port; - -/** - * @brief The IPX packet type for which binding failed. - */ -@property (readonly, nonatomic) uint8_t packetType; - -/** - * @brief The path on which binding failed. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; - -/** - * @brief The socket which could not be bound. - */ -@property (readonly, nonatomic) id socket; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased bind failed exception. - * - * @param host The host on which binding failed - * @param port The port on which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return A new, autoreleased bind failed exception - */ -+ (instancetype)exceptionWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Creates a new, autoreleased bind failed exception. - * - * @param port The IPX port to which binding failed - * @param packetType The IPX packet type for which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return A new, autoreleased bind failed exception - */ -+ (instancetype)exceptionWithPort: (uint16_t)port - packetType: (uint8_t)packetType - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Creates a new, autoreleased bind failed exception. - * - * @param path The path on which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return A new, autoreleased bind failed exception - */ -+ (instancetype)exceptionWithPath: (OFString *)path - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Initializes an already allocated bind failed exception. - * - * @param host The host on which binding failed - * @param port The port on which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return An initialized bind failed exception - */ -- (instancetype)initWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Initializes an already allocated bind failed exception. - * - * @param port The IPX port to which binding failed - * @param packetType The IPX packet type for which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return An initialized bind failed exception - */ -- (instancetype)initWithPort: (uint16_t)port - packetType: (uint8_t)packetType - socket: (id)socket - errNo: (int)errNo; -/** - * @brief Initializes an already allocated bind failed exception. - * - * @param path The path on which binding failed - * @param socket The socket which could not be bound - * @param errNo The errno of the error that occurred - * @return An initialized bind failed exception - */ -- (instancetype)initWithPath: (OFString *)path - socket: (id)socket - errNo: (int)errNo; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFBindFailedException.m Index: src/exceptions/OFBindFailedException.m ================================================================== --- src/exceptions/OFBindFailedException.m +++ src/exceptions/OFBindFailedException.m @@ -1,150 +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 "OFBindFailedException.h" -#import "OFString.h" - -@implementation OFBindFailedException -@synthesize host = _host, port = _port, packetType = _packetType, path = _path; -@synthesize socket = _socket, errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithHost: host - port: port - socket: sock - errNo: errNo] autorelease]; -} - -+ (instancetype)exceptionWithPort: (uint16_t)port - packetType: (uint8_t)packetType - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithPort: port - packetType: packetType - socket: sock - errNo: errNo] autorelease]; -} - -+ (instancetype)exceptionWithPath: (OFString *)path - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithPath: path - socket: sock - errNo: errNo] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _host = [host copy]; - _port = port; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithPort: (uint16_t)port - packetType: (uint8_t)packetType - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _port = port; - _packetType = packetType; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithPath: (OFString *)path - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _path = [path copy]; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_host release]; - [_path release]; - [_socket release]; - - [super dealloc]; -} - -- (OFString *)description -{ - if (_path != nil) - return [OFString stringWithFormat: - @"Binding to path %@ failed in socket of type %@: %@", - _path, [_socket class], OFStrError(_errNo)]; - else if (_host != nil) - return [OFString stringWithFormat: - @"Binding to port %" @PRIu16 @" on host %@ failed in " - @"socket of type %@: %@", - _port, _host, [_socket class], OFStrError(_errNo)]; - else - return [OFString stringWithFormat: - @"Binding to port %" @PRIx16 @" for packet type %" @PRIx8 - @" failed in socket of type %@: %@", - _port, _packetType, [_socket class], OFStrError(_errNo)]; -} -@end ADDED src/exceptions/OFBindIPSocketFailedException.h Index: src/exceptions/OFBindIPSocketFailedException.h ================================================================== --- src/exceptions/OFBindIPSocketFailedException.h +++ src/exceptions/OFBindIPSocketFailedException.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindSocketFailedException.h" + +#ifndef OF_HAVE_SOCKETS +# error No sockets available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindIPSocketFailedException \ + * OFBindIPSocketFailedException.h ObjFW/OFBindIPSocketFailedException.h + * + * @brief An exception indicating that binding an IP socket failed. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFBindIPSocketFailedException: OFBindSocketFailedException +{ + OFString *_Nullable _host; + uint16_t _port; +} + +/** + * @brief The host on which binding failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; + +/** + * @brief The port on which binding failed. + */ +@property (readonly, nonatomic) uint16_t port; + +/** + * @brief Creates a new, autoreleased bind IP socket failed exception. + * + * @param host The host on which binding failed + * @param port The port on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind IP socket failed exception + */ ++ (instancetype)exceptionWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind IP socket failed exception. + * + * @param host The host on which binding failed + * @param port The port on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind IP socket failed exception + */ +- (instancetype)initWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindIPSocketFailedException.m Index: src/exceptions/OFBindIPSocketFailedException.m ================================================================== --- src/exceptions/OFBindIPSocketFailedException.m +++ src/exceptions/OFBindIPSocketFailedException.m @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindIPSocketFailedException.h" +#import "OFString.h" + +@implementation OFBindIPSocketFailedException +@synthesize host = _host, port = _port; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithHost: host + port: port + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _host = [host copy]; + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_host release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Binding to port %" @PRIu16 @" on host %@ failed in socket of " + @"type %@: %@", + _port, _host, [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFBindIPXSocketFailedException.h Index: src/exceptions/OFBindIPXSocketFailedException.h ================================================================== --- src/exceptions/OFBindIPXSocketFailedException.h +++ src/exceptions/OFBindIPXSocketFailedException.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 "OFBindSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindIPXSocketFailedException \ + * OFBindIPXSocketFailedException.h \ + * ObjFW/OFBindIPXSocketFailedException.h + * + * @brief An exception indicating that binding an IPX socket failed. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFBindIPXSocketFailedException: OFBindSocketFailedException +{ + uint32_t _network; + unsigned char _node[IPX_NODE_LEN]; + uint16_t _port; + uint8_t _packetType; +} + +/** + * @brief The IPX network on which binding failed. + */ +@property (readonly, nonatomic) uint32_t network; + +/** + * @brief The IPX port on which binding failed. + */ +@property (readonly, nonatomic) uint16_t port; + +/** + * @brief The IPX packet type for which binding failed. + */ +@property (readonly, nonatomic) uint8_t packetType; + +/** + * @brief Creates a new, autoreleased bind IPX socket failed exception. + * + * @param network The IPX network to which binding failed + * @param node The IPX node to which binding failed + * @param port The IPX port to which binding failed + * @param packetType The IPX packet type for which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind IPX socket failed exception + */ ++ (instancetype) + exceptionWithNetwork: (uint32_t)network + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + packetType: (uint8_t)packetType + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind IPX socket failed exception. + * + * @param network The IPX network to which binding failed + * @param node The IPX node to which binding failed + * @param port The IPX port to which binding failed + * @param packetType The IPX packet type for which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind IPX socket failed exception + */ +- (instancetype) + initWithNetwork: (uint32_t)network + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + packetType: (uint8_t)packetType + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Get the IPX node for which binding failed. + * + * @param node A pointer to where to write the node to + */ +- (void)getNode: (unsigned char [_Nonnull IPX_NODE_LEN])node; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindIPXSocketFailedException.m Index: src/exceptions/OFBindIPXSocketFailedException.m ================================================================== --- src/exceptions/OFBindIPXSocketFailedException.m +++ src/exceptions/OFBindIPXSocketFailedException.m @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindIPXSocketFailedException.h" +#import "OFData.h" +#import "OFString.h" + +@implementation OFBindIPXSocketFailedException +@synthesize network = _network, port = _port, packetType = _packetType; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype) + exceptionWithNetwork: (uint32_t)network + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + packetType: (uint8_t)packetType + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithNetwork: network + node: node + port: port + packetType: packetType + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype) + initWithNetwork: (uint32_t)network + node: (const unsigned char [_Nonnull IPX_NODE_LEN])node + port: (uint16_t)port + packetType: (uint8_t)packetType + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _network = network; + memcpy(_node, node, sizeof(_node)); + _port = port; + _packetType = packetType; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)getNode: (unsigned char [IPX_NODE_LEN])node +{ + memcpy(node, _node, sizeof(_node)); +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"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 ADDED src/exceptions/OFBindSocketFailedException.h Index: src/exceptions/OFBindSocketFailedException.h ================================================================== --- src/exceptions/OFBindSocketFailedException.h +++ src/exceptions/OFBindSocketFailedException.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 + +#import "OFSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindSocketFailedException \ + * OFBindSocketFailedException.h ObjFW/OFBindSocketFailedException.h + * + * @brief An exception indicating that binding a socket failed. + */ +@interface OFBindSocketFailedException: OFException +{ + id _socket; + int _errNo; + OF_RESERVE_IVARS(OFBindSocketFailedException, 4) +} + +/** + * @brief The socket which could not be bound. + */ +@property (readonly, nonatomic) id socket; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased bind socket failed exception. + * + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind socket failed exception + */ ++ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind socket failed exception. + * + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind socket failed exception + */ +- (instancetype)initWithSocket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindSocketFailedException.m Index: src/exceptions/OFBindSocketFailedException.m ================================================================== --- src/exceptions/OFBindSocketFailedException.m +++ src/exceptions/OFBindSocketFailedException.m @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindSocketFailedException.h" +#import "OFString.h" + +@implementation OFBindSocketFailedException +@synthesize socket = _socket, errNo = _errNo; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + return [[[self alloc] initWithSocket: sock errNo: errNo] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + self = [super init]; + + @try { + _socket = [sock retain]; + _errNo = errNo; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_socket release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Binding a socket of type %@ failed: %@", + [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFBindUNIXSocketFailedException.h Index: src/exceptions/OFBindUNIXSocketFailedException.h ================================================================== --- src/exceptions/OFBindUNIXSocketFailedException.h +++ src/exceptions/OFBindUNIXSocketFailedException.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFBindUNIXSocketFailedException \ + * OFBindUNIXSocketFailedException.h \ + * ObjFW/OFBindUNIXSocketFailedException.h + * + * @brief An exception indicating that binding a UNIX socket failed. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFBindUNIXSocketFailedException: OFBindSocketFailedException +{ + OFString *_Nullable _path; +} + +/** + * @brief The path on which binding failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; + +/** + * @brief Creates a new, autoreleased bind UNIX socket failed exception. + * + * @param path The path on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return A new, autoreleased bind UNIX socket failed exception + */ ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated bind UNIX socket failed exception. + * + * @param path The path on which binding failed + * @param socket The socket which could not be bound + * @param errNo The errno of the error that occurred + * @return An initialized bind UNIX socket failed exception + */ +- (instancetype)initWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBindUNIXSocketFailedException.m Index: src/exceptions/OFBindUNIXSocketFailedException.m ================================================================== --- src/exceptions/OFBindUNIXSocketFailedException.m +++ src/exceptions/OFBindUNIXSocketFailedException.m @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBindUNIXSocketFailedException.h" +#import "OFString.h" + +@implementation OFBindUNIXSocketFailedException +@synthesize path = _path; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithPath: path + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _path = [path copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_path release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Binding to path %@ failed in socket of type %@: %@", + _path, [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFBroadcastConditionFailedException.h Index: src/exceptions/OFBroadcastConditionFailedException.h ================================================================== --- src/exceptions/OFBroadcastConditionFailedException.h +++ src/exceptions/OFBroadcastConditionFailedException.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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_THREADS +# error No threads available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFCondition; + +/** + * @class OFBroadcastConditionFailedException \ + * OFBroadcastConditionFailedException.h \ + * ObjFW/OFBroadcastConditionFailedException.h + * + * @brief An exception indicating broadcasting a condition failed. + */ +@interface OFBroadcastConditionFailedException: OFException +{ + OFCondition *_condition; + int _errNo; + OF_RESERVE_IVARS(OFBroadcastConditionFailedException, 4) +} + +/** + * @brief The condition which could not be broadcasted. + */ +@property (readonly, nonatomic) OFCondition *condition; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Returns a new, autoreleased condition broadcast failed exception. + * + * @param condition The condition which could not be broadcasted + * @param errNo The errno of the error that occurred + * @return A new, autoreleased condition broadcast failed exception + */ ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated condition broadcast failed exception. + * + * @param condition The condition which could not be broadcasted + * @param errNo The errno of the error that occurred + * @return An initialized condition broadcast failed exception + */ +- (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFBroadcastConditionFailedException.m Index: src/exceptions/OFBroadcastConditionFailedException.m ================================================================== --- src/exceptions/OFBroadcastConditionFailedException.m +++ src/exceptions/OFBroadcastConditionFailedException.m @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFBroadcastConditionFailedException.h" +#import "OFString.h" +#import "OFCondition.h" + +@implementation OFBroadcastConditionFailedException +@synthesize condition = _condition, errNo = _errNo; + ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo +{ + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo +{ + self = [super init]; + + _condition = [condition retain]; + _errNo = errNo; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_condition release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Broadcasting a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; +} +@end 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 DELETED src/exceptions/OFConditionBroadcastFailedException.h Index: src/exceptions/OFConditionBroadcastFailedException.h ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.h +++ src/exceptions/OFConditionBroadcastFailedException.h @@ -1,75 +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_THREADS -# error No threads available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFCondition; - -/** - * @class OFConditionBroadcastFailedException \ - * OFConditionBroadcastFailedException.h \ - * ObjFW/OFConditionBroadcastFailedException.h - * - * @brief An exception indicating broadcasting a condition failed. - */ -@interface OFConditionBroadcastFailedException: OFException -{ - OFCondition *_condition; - int _errNo; - OF_RESERVE_IVARS(OFConditionBroadcastFailedException, 4) -} - -/** - * @brief The condition which could not be broadcasted. - */ -@property (readonly, nonatomic) OFCondition *condition; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Returns a new, autoreleased condition broadcast failed exception. - * - * @param condition The condition which could not be broadcasted - * @param errNo The errno of the error that occurred - * @return A new, autoreleased condition broadcast failed exception - */ -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated condition broadcast failed exception. - * - * @param condition The condition which could not be broadcasted - * @param errNo The errno of the error that occurred - * @return An initialized condition broadcast failed exception - */ -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFConditionBroadcastFailedException.m Index: src/exceptions/OFConditionBroadcastFailedException.m ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.m +++ src/exceptions/OFConditionBroadcastFailedException.m @@ -1,67 +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 "OFConditionBroadcastFailedException.h" -#import "OFString.h" -#import "OFCondition.h" - -@implementation OFConditionBroadcastFailedException -@synthesize condition = _condition, errNo = _errNo; - -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo -{ - return [[[self alloc] initWithCondition: condition - errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo -{ - self = [super init]; - - _condition = [condition retain]; - _errNo = errNo; - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_condition release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Broadcasting a condition of type %@ failed: %s", - _condition.class, strerror(_errNo)]; -} -@end DELETED src/exceptions/OFConditionSignalFailedException.h Index: src/exceptions/OFConditionSignalFailedException.h ================================================================== --- src/exceptions/OFConditionSignalFailedException.h +++ src/exceptions/OFConditionSignalFailedException.h @@ -1,75 +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_THREADS -# error No threads available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFCondition; - -/** - * @class OFConditionSignalFailedException \ - * OFConditionSignalFailedException.h \ - * ObjFW/OFConditionSignalFailedException.h - * - * @brief An exception indicating signaling a condition failed. - */ -@interface OFConditionSignalFailedException: OFException -{ - OFCondition *_condition; - int _errNo; - OF_RESERVE_IVARS(OFConditionSignalFailedException, 4) -} - -/** - * @brief The condition which could not be signaled. - */ -@property (readonly, nonatomic) OFCondition *condition; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased condition signal failed exception. - * - * @param condition The condition which could not be signaled - * @param errNo The errno of the error that occurred - * @return A new, autoreleased condition signal failed exception - */ -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated condition signal failed exception. - * - * @param condition The condition which could not be signaled - * @param errNo The errno of the error that occurred - * @return An initialized condition signal failed exception - */ -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFConditionSignalFailedException.m Index: src/exceptions/OFConditionSignalFailedException.m ================================================================== --- src/exceptions/OFConditionSignalFailedException.m +++ src/exceptions/OFConditionSignalFailedException.m @@ -1,67 +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 "OFConditionSignalFailedException.h" -#import "OFString.h" -#import "OFCondition.h" - -@implementation OFConditionSignalFailedException -@synthesize condition = _condition, errNo = _errNo; - -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo -{ - return [[[self alloc] initWithCondition: condition - errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo -{ - self = [super init]; - - _condition = [condition retain]; - _errNo = errNo; - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_condition release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Signaling a condition of type %@ failed: %s", - _condition.class, strerror(_errNo)]; -} -@end 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 DELETED src/exceptions/OFConditionWaitFailedException.h Index: src/exceptions/OFConditionWaitFailedException.h ================================================================== --- src/exceptions/OFConditionWaitFailedException.h +++ src/exceptions/OFConditionWaitFailedException.h @@ -1,75 +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_THREADS -# error No threads available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFCondition; - -/** - * @class OFConditionWaitFailedException \ - * OFConditionWaitFailedException.h \ - * ObjFW/OFConditionWaitFailedException.h - * - * @brief An exception indicating waiting for a condition failed. - */ -@interface OFConditionWaitFailedException: OFException -{ - OFCondition *_condition; - int _errNo; - OF_RESERVE_IVARS(OFConditionWaitFailedException, 4) -} - -/** - * @brief The condition for which could not be waited. - */ -@property (readonly, nonatomic) OFCondition *condition; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased condition wait failed exception. - * - * @param condition The condition for which could not be waited - * @param errNo The errno of the error that occurred - * @return A new, autoreleased condition wait failed exception - */ -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated condition wait failed exception. - * - * @param condition The condition for which could not be waited - * @param errNo The errno of the error that occurred - * @return An initialized condition wait failed exception - */ -- (instancetype)initWithCondition: (OFCondition *)condition - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFConditionWaitFailedException.m Index: src/exceptions/OFConditionWaitFailedException.m ================================================================== --- src/exceptions/OFConditionWaitFailedException.m +++ src/exceptions/OFConditionWaitFailedException.m @@ -1,67 +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 "OFConditionWaitFailedException.h" -#import "OFString.h" -#import "OFCondition.h" - -@implementation OFConditionWaitFailedException -@synthesize condition = _condition, errNo = _errNo; - -+ (instancetype)exceptionWithCondition: (OFCondition *)condition - errNo: (int)errNo -{ - return [[[self alloc] initWithCondition: condition - errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo -{ - self = [super init]; - - _condition = [condition retain]; - _errNo = errNo; - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_condition release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Waiting for a condition of type %@ failed: %s", - _condition.class, strerror(_errNo)]; -} -@end ADDED src/exceptions/OFConnectIPSocketFailedException.h Index: src/exceptions/OFConnectIPSocketFailedException.h ================================================================== --- src/exceptions/OFConnectIPSocketFailedException.h +++ src/exceptions/OFConnectIPSocketFailedException.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFConnectIPSocketFailedException \ + * OFConnectIPSocketFailedException.h \ + * ObjFW/OFConnectIPSocketFailedException.h + * + * @brief An exception indicating that an IP connection could not be + * established. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFConnectIPSocketFailedException: OFConnectSocketFailedException +{ + OFString *_Nullable _host; + uint16_t _port; +} + +/** + * @brief The host to which the connection failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; + +/** + * @brief The port on the host to which the connection failed. + */ +@property (readonly, nonatomic) uint16_t port; + +/** + * @brief Creates a new, autoreleased connect IP socket failed exception. + * + * @param host The host to which the connection failed + * @param port The port on the host to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return A new, autoreleased connect IP socket failed exception + */ ++ (instancetype)exceptionWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated connect IP socket failed exception. + * + * @param host The host to which the connection failed + * @param port The port on the host to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return An initialized connect IP socket failed exception + */ +- (instancetype)initWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFConnectIPSocketFailedException.m Index: src/exceptions/OFConnectIPSocketFailedException.m ================================================================== --- src/exceptions/OFConnectIPSocketFailedException.m +++ src/exceptions/OFConnectIPSocketFailedException.m @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectIPSocketFailedException.h" +#import "OFString.h" + +@implementation OFConnectIPSocketFailedException +@synthesize host = _host, port = _port; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithHost: host + port: port + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithHost: (OFString *)host + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _host = [host copy]; + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_host release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"A connection to %@ on port %" @PRIu16 @" could not be " + @"established in socket of type %@: %@", + _host, _port, [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFConnectSPXSocketFailedException.h Index: src/exceptions/OFConnectSPXSocketFailedException.h ================================================================== --- src/exceptions/OFConnectSPXSocketFailedException.h +++ src/exceptions/OFConnectSPXSocketFailedException.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFConnectSPXSocketFailedException \ + * OFConnectSPXSocketFailedException.h \ + * ObjFW/OFConnectSocketFailedException.h + * + * @brief An exception indicating that an SPX connection could not be + * established. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFConnectSPXSocketFailedException: OFConnectSocketFailedException +{ + uint32_t _network; + unsigned char _node[IPX_NODE_LEN]; + uint16_t _port; +} + + +/** + * @brief The IPX network of the node to which the connection failed. + */ +@property (readonly, nonatomic) uint32_t network; + +/** + * @brief The IPX port on the host to which the connection failed. + */ +@property (readonly, nonatomic) uint16_t port; + +/** + * @brief Creates a new, autoreleased connect SPX socket failed exception. + * + * @param network The IPX network of the node to which the connection failed + * @param node The node to which the connection failed + * @param port The port on the node to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return A new, autoreleased connect SPX socket failed exception + */ ++ (instancetype) + exceptionWithNetwork: (uint32_t)network + node: (const unsigned char [_Nullable IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated connect SPX socket failed exception. + * + * @param network The IPX network of the node to which the connection failed + * @param node The node to which the connection failed + * @param port The port on the node to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return An initialized connect SPX socket failed exception + */ +- (instancetype) + initWithNetwork: (uint32_t)network + node: (const unsigned char [_Nullable IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Get the IPX node to which the connection failed. + * + * @param node A pointer to where to write the node to + */ +- (void)getNode: (unsigned char [_Nonnull IPX_NODE_LEN])node; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFConnectSPXSocketFailedException.m Index: src/exceptions/OFConnectSPXSocketFailedException.m ================================================================== --- src/exceptions/OFConnectSPXSocketFailedException.m +++ src/exceptions/OFConnectSPXSocketFailedException.m @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectSPXSocketFailedException.h" +#import "OFData.h" +#import "OFString.h" + +@implementation OFConnectSPXSocketFailedException +@synthesize network = _network, port = _port; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithNetwork: (uint32_t)network + node: (const unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithNetwork: network + node: node + port: port + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithNetwork: (uint32_t)network + node: (const unsigned char [IPX_NODE_LEN])node + port: (uint16_t)port + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _network = network; + memcpy(_node, node, IPX_NODE_LEN); + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)getNode: (unsigned char [IPX_NODE_LEN])node +{ + memcpy(node, _node, sizeof(_node)); +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"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 ADDED src/exceptions/OFConnectSocketFailedException.h Index: src/exceptions/OFConnectSocketFailedException.h ================================================================== --- src/exceptions/OFConnectSocketFailedException.h +++ src/exceptions/OFConnectSocketFailedException.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 + +#import "OFSocket.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFConnectSocketFailedException \ + * OFConnectSocketFailedException.h \ + * ObjFW/OFConnectSocketFailedException.h + * + * @brief An exception indicating that a connection could not be established. + */ +@interface OFConnectSocketFailedException: OFException +{ + id _socket; + int _errNo; + OF_RESERVE_IVARS(OFConnectSocketFailedException, 4) +} + +/** + * @brief The socket which could not connect. + */ +@property (readonly, nonatomic) id socket; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased connect socket failed exception. + * + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return A new, autoreleased connect socket failed exception + */ ++ (instancetype)exceptionWithSocket: (id)socket errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated connect socket failed exception. + * + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return An initialized connect socket failed exception + */ +- (instancetype)initWithSocket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFConnectSocketFailedException.m Index: src/exceptions/OFConnectSocketFailedException.m ================================================================== --- src/exceptions/OFConnectSocketFailedException.m +++ src/exceptions/OFConnectSocketFailedException.m @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectSocketFailedException.h" +#import "OFString.h" + +@implementation OFConnectSocketFailedException +@synthesize socket = _socket, errNo = _errNo; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + return [[[self alloc] initWithSocket: sock errNo: errNo] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + self = [super init]; + + @try { + _socket = [sock retain]; + _errNo = errNo; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_socket release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"A connection to could not be established in socket of type " + @"%@: %@", + [_socket class], OFStrError(_errNo)]; +} +@end ADDED src/exceptions/OFConnectUNIXSocketFailedException.h Index: src/exceptions/OFConnectUNIXSocketFailedException.h ================================================================== --- src/exceptions/OFConnectUNIXSocketFailedException.h +++ src/exceptions/OFConnectUNIXSocketFailedException.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectSocketFailedException.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFConnectUNIXSocketFailedException \ + * OFConnectUNIXSocketFailedException.h \ + * ObjFW/OFConnectUNIXSocketFailedException.h + * + * @brief An exception indicating that a UNIX socket connection could not be + * established. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFConnectUNIXSocketFailedException: OFConnectSocketFailedException +{ + OFString *_Nullable _path; +} + +/** + * @brief The path to which the connection failed. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; + +/** + * @brief Creates a new, autoreleased connect UNIX socket failed exception. + * + * @param path The path to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return A new, autoreleased connect UNIX socket failed exception + */ ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo; + ++ (instancetype)exceptionWithSocket: (id)socket + errNo: (int)errNo OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated connect UNIX socket failed exception. + * + * @param path The path to which the connection failed + * @param socket The socket which could not connect + * @param errNo The errno of the error that occurred + * @return An initialized connect UNIX socket failed exception + */ +- (instancetype)initWithPath: (OFString *)path + socket: (id)socket + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)initWithSocket: (id)socket errNo: (int)errNo OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFConnectUNIXSocketFailedException.m Index: src/exceptions/OFConnectUNIXSocketFailedException.m ================================================================== --- src/exceptions/OFConnectUNIXSocketFailedException.m +++ src/exceptions/OFConnectUNIXSocketFailedException.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFConnectUNIXSocketFailedException.h" +#import "OFString.h" + +@implementation OFConnectUNIXSocketFailedException +@synthesize path = _path; + ++ (instancetype)exceptionWithSocket: (id)sock errNo: (int)errNo +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + return [[[self alloc] initWithPath: path + socket: sock + errNo: errNo] autorelease]; +} + +- (instancetype)initWithSocket: (id)sock errNo: (int)errNo +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithPath: (OFString *)path + socket: (id)sock + errNo: (int)errNo +{ + self = [super initWithSocket: sock errNo: errNo]; + + @try { + _path = [path copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_path release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"A connection to %@ could not be established in socket of type " + @"%@: %@", + _path, [_socket class], OFStrError(_errNo)]; +} +@end DELETED src/exceptions/OFConnectionFailedException.h Index: src/exceptions/OFConnectionFailedException.h ================================================================== --- src/exceptions/OFConnectionFailedException.h +++ src/exceptions/OFConnectionFailedException.h @@ -1,169 +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 - -#import "OFSocket.h" - -OF_ASSUME_NONNULL_BEGIN - -/** - * @class OFConnectionFailedException \ - * OFConnectionFailedException.h ObjFW/OFConnectionFailedException.h - * - * @brief An exception indicating that a connection could not be established. - */ -@interface OFConnectionFailedException: OFException -{ - OFString *_Nullable _host; - uint16_t _port; - OFString *_Nullable _path; - uint32_t _network; - unsigned char _node[IPX_NODE_LEN]; - id _socket; - int _errNo; - OF_RESERVE_IVARS(OFConnectionFailedException, 4) -} - -/** - * @brief The host to which the connection failed. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host; - -/** - * @brief The port on the host to which the connection failed. - */ -@property (readonly, nonatomic) uint16_t port; - -/** - * @brief The path to which the connection failed. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *path; - -/** - * @brief The IPX network of the node to which the connection failed. - */ -@property (readonly, nonatomic) uint32_t network; - -/** - * @brief The IPX node to which the connection failed. - */ -@property (readonly, nonatomic) unsigned char *node; - -/** - * @brief The socket which could not connect. - */ -@property (readonly, nonatomic) id socket; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased connection failed exception. - * - * @param host The host to which the connection failed - * @param port The port on the host to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return A new, autoreleased connection failed exception - */ -+ (instancetype)exceptionWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Creates a new, autoreleased connection failed exception. - * - * @param path The path to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return A new, autoreleased connection failed exception - */ -+ (instancetype)exceptionWithPath: (OFString *)path - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Creates a new, autoreleased connection failed exception. - * - * @param network The IPX network of the node to which the connection failed - * @param node The node to which the connection failed - * @param port The port on the node to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return A new, autoreleased connection failed exception - */ -+ (instancetype) - exceptionWithNetwork: (uint32_t)network - node: (unsigned char [_Nullable IPX_NODE_LEN])node - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated connection failed exception. - * - * @param host The host to which the connection failed - * @param port The port on the host to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return An initialized connection failed exception - */ -- (instancetype)initWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Initializes an already allocated connection failed exception. - * - * @param path The path to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return An initialized connection failed exception - */ -- (instancetype)initWithPath: (OFString *)path - socket: (id)socket - errNo: (int)errNo; - -/** - * @brief Initializes an already allocated connection failed exception. - * - * @param network The IPX network of the node to which the connection failed - * @param node The node to which the connection failed - * @param port The port on the node to which the connection failed - * @param socket The socket which could not connect - * @param errNo The errno of the error that occurred - * @return An initialized connection failed exception - */ -- (instancetype)initWithNetwork: (uint32_t)network - node: (unsigned char [_Nullable IPX_NODE_LEN])node - port: (uint16_t)port - socket: (id)socket - errNo: (int)errNo; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFConnectionFailedException.m Index: src/exceptions/OFConnectionFailedException.m ================================================================== --- src/exceptions/OFConnectionFailedException.m +++ src/exceptions/OFConnectionFailedException.m @@ -1,167 +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 "OFConnectionFailedException.h" -#import "OFString.h" - -@implementation OFConnectionFailedException -@synthesize host = _host, port = _port, path = _path, network = _network; -@synthesize socket = _socket, errNo = _errNo; - -+ (instancetype)exceptionWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithHost: host - port: port - socket: sock - errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithPath: (OFString *)path - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithPath: path - socket: sock - errNo: errNo] autorelease]; -} - -+ (instancetype)exceptionWithNetwork: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - return [[[self alloc] initWithNetwork: network - node: node - port: port - socket: sock - errNo: errNo] autorelease]; -} - -- (instancetype)initWithHost: (OFString *)host - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _host = [host copy]; - _port = port; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithPath: (OFString *)path - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _path = [path copy]; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithNetwork: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node - port: (uint16_t)port - socket: (id)sock - errNo: (int)errNo -{ - self = [super init]; - - @try { - _network = network; - memcpy(_node, node, IPX_NODE_LEN); - _port = port; - _socket = [sock retain]; - _errNo = errNo; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_host release]; - [_path release]; - [_socket release]; - - [super dealloc]; -} - -- (unsigned char *)node -{ - return _node; -} - -- (OFString *)description -{ - if (_path != nil) - return [OFString stringWithFormat: - @"A connection to %@ could not be established in socket of " - @"type %@: %@", - _path, [_socket class], OFStrError(_errNo)]; - else if (_host != nil) - return [OFString stringWithFormat: - @"A connection to %@ on port %" @PRIu16 @" could not be " - @"established in socket of type %@: %@", - _host, _port, [_socket class], OFStrError(_errNo)]; - else if (memcmp(_node, "\0\0\0\0\0", IPX_NODE_LEN) == 0) - return [OFString stringWithFormat: - @"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)]; - else - return [OFString stringWithFormat: - @"A connection could not be established in socket of " - @"type %@: %@", - [_socket class], OFStrError(_errNo)]; -} -@end 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 ADDED src/exceptions/OFJoinThreadFailedException.h Index: src/exceptions/OFJoinThreadFailedException.h ================================================================== --- src/exceptions/OFJoinThreadFailedException.h +++ src/exceptions/OFJoinThreadFailedException.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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_THREADS +# error No threads available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFThread; + +/** + * @class OFJoinThreadFailedException \ + * OFJoinThreadFailedException.h ObjFW/OFJoinThreadFailedException.h + * + * @brief An exception indicating that joining a thread failed. + */ +@interface OFJoinThreadFailedException: OFException +{ + OFThread *_Nullable _thread; + int _errNo; + OF_RESERVE_IVARS(OFJoinThreadFailedException, 4) +} + +/** + * @brief The thread which could not be joined. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased thread join failed exception. + * + * @param thread The thread which could not be joined + * @param errNo The errno of the error that occurred + * @return A new, autoreleased thread join failed exception + */ ++ (instancetype)exceptionWithThread: (nullable OFThread *)thread + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated thread join failed exception. + * + * @param thread The thread which could not be joined + * @param errNo The errno of the error that occurred + * @return An initialized thread join failed exception + */ +- (instancetype)initWithThread: (nullable OFThread *)thread + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFJoinThreadFailedException.m Index: src/exceptions/OFJoinThreadFailedException.m ================================================================== --- src/exceptions/OFJoinThreadFailedException.m +++ src/exceptions/OFJoinThreadFailedException.m @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFJoinThreadFailedException.h" +#import "OFString.h" +#import "OFThread.h" + +@implementation OFJoinThreadFailedException +@synthesize thread = _thread, errNo = _errNo; + ++ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo +{ + return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo +{ + self = [super init]; + + _thread = [thread retain]; + _errNo = errNo; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_thread release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Joining a thread of type %@ failed: %s", + _thread.class, strerror(_errNo)]; +} +@end 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 DELETED src/exceptions/OFListenFailedException.h Index: src/exceptions/OFListenFailedException.h ================================================================== --- src/exceptions/OFListenFailedException.h +++ src/exceptions/OFListenFailedException.h @@ -1,81 +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 OFListenFailedException \ - * OFListenFailedException.h ObjFW/OFListenFailedException.h - * - * @brief An exception indicating that listening on the socket failed. - */ -@interface OFListenFailedException: OFException -{ - id _socket; - int _backlog, _errNo; - OF_RESERVE_IVARS(OFListenFailedException, 4) -} - -/** - * @brief The socket which failed to listen. - */ -@property (readonly, nonatomic) id socket; - -/** - * @brief The requested back log. - */ -@property (readonly, nonatomic) int backlog; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased listen failed exception. - * - * @param socket The socket which failed to listen - * @param backlog The requested size of the back log - * @param errNo The errno of the error that occurred - * @return A new, autoreleased listen failed exception - */ -+ (instancetype)exceptionWithSocket: (id)socket - backlog: (int)backlog - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated listen failed exception. - * - * @param socket The socket which failed to listen - * @param backlog The requested size of the back log - * @param errNo The errno of the error that occurred - * @return An initialized listen failed exception - */ -- (instancetype)initWithSocket: (id)socket - backlog: (int)backlog - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFListenFailedException.m Index: src/exceptions/OFListenFailedException.m ================================================================== --- src/exceptions/OFListenFailedException.m +++ src/exceptions/OFListenFailedException.m @@ -1,69 +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 "OFListenFailedException.h" -#import "OFString.h" - -@implementation OFListenFailedException -@synthesize socket = _socket, backlog = _backlog, errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithSocket: (id)socket - backlog: (int)backlog - errNo: (int)errNo -{ - return [[[self alloc] initWithSocket: socket - backlog: backlog - errNo: errNo] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSocket: (id)socket - backlog: (int)backlog - errNo: (int)errNo -{ - self = [super init]; - - _socket = [socket retain]; - _backlog = backlog; - _errNo = errNo; - - return self; -} - -- (void)dealloc -{ - [_socket release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Failed to listen in socket of type %@ with a back log of %d: %@", - [_socket class], _backlog, OFStrError(_errNo)]; -} -@end ADDED src/exceptions/OFListenOnSocketFailedException.h Index: src/exceptions/OFListenOnSocketFailedException.h ================================================================== --- src/exceptions/OFListenOnSocketFailedException.h +++ src/exceptions/OFListenOnSocketFailedException.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 OFListenOnSocketFailedException \ + * OFListenOnSocketFailedException.h \ + * ObjFW/OFListenOnSocketFailedException.h + * + * @brief An exception indicating that listening on the socket failed. + */ +@interface OFListenOnSocketFailedException: OFException +{ + id _socket; + int _backlog, _errNo; + OF_RESERVE_IVARS(OFListenOnSocketFailedException, 4) +} + +/** + * @brief The socket which failed to listen. + */ +@property (readonly, nonatomic) id socket; + +/** + * @brief The requested back log. + */ +@property (readonly, nonatomic) int backlog; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased listen failed exception. + * + * @param socket The socket which failed to listen + * @param backlog The requested size of the back log + * @param errNo The errno of the error that occurred + * @return A new, autoreleased listen failed exception + */ ++ (instancetype)exceptionWithSocket: (id)socket + backlog: (int)backlog + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated listen failed exception. + * + * @param socket The socket which failed to listen + * @param backlog The requested size of the back log + * @param errNo The errno of the error that occurred + * @return An initialized listen failed exception + */ +- (instancetype)initWithSocket: (id)socket + backlog: (int)backlog + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFListenOnSocketFailedException.m Index: src/exceptions/OFListenOnSocketFailedException.m ================================================================== --- src/exceptions/OFListenOnSocketFailedException.m +++ src/exceptions/OFListenOnSocketFailedException.m @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFListenOnSocketFailedException.h" +#import "OFString.h" + +@implementation OFListenOnSocketFailedException +@synthesize socket = _socket, backlog = _backlog, errNo = _errNo; + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + ++ (instancetype)exceptionWithSocket: (id)sock + backlog: (int)backlog + errNo: (int)errNo +{ + return [[[self alloc] initWithSocket: sock + backlog: backlog + errNo: errNo] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithSocket: (id)sock backlog: (int)backlog errNo: (int)errNo +{ + self = [super init]; + + _socket = [sock retain]; + _backlog = backlog; + _errNo = errNo; + + return self; +} + +- (void)dealloc +{ + [_socket release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Failed to listen in socket of type %@ with a back log of %d: %@", + [_socket class], _backlog, OFStrError(_errNo)]; +} +@end 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 DELETED src/exceptions/OFSandboxActivationFailedException.h Index: src/exceptions/OFSandboxActivationFailedException.h ================================================================== --- src/exceptions/OFSandboxActivationFailedException.h +++ src/exceptions/OFSandboxActivationFailedException.h @@ -1,38 +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" - -OF_ASSUME_NONNULL_BEGIN - -@class OFSandbox; - -@interface OFSandboxActivationFailedException: OFException -{ - OFSandbox *_sandbox; - int _errNo; -} - -@property (readonly, nonatomic) OFSandbox *sandbox; -@property (readonly, nonatomic) int errNo; - -+ (instancetype)exception OF_UNAVAILABLE; -+ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo; -- (instancetype)init OF_UNAVAILABLE; -- (instancetype)initWithSandbox: (OFSandbox *)sandbox - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFSandboxActivationFailedException.m Index: src/exceptions/OFSandboxActivationFailedException.m ================================================================== --- src/exceptions/OFSandboxActivationFailedException.m +++ src/exceptions/OFSandboxActivationFailedException.m @@ -1,63 +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 "OFSandboxActivationFailedException.h" -#import "OFString.h" -#import "OFSandbox.h" - -@implementation OFSandboxActivationFailedException -@synthesize sandbox = _sandbox, errNo = _errNo; - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -+ (instancetype)exceptionWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo -{ - return [[[self alloc] initWithSandbox: sandbox - errNo: errNo] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithSandbox: (OFSandbox *)sandbox errNo: (int)errNo -{ - self = [super init]; - - _sandbox = [sandbox retain]; - _errNo = errNo; - - return self; -} - -- (void)dealloc -{ - [_sandbox release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"The sandbox could not be applied: %@", OFStrError(_errNo)]; -} -@end 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 ADDED src/exceptions/OFSignalConditionFailedException.h Index: src/exceptions/OFSignalConditionFailedException.h ================================================================== --- src/exceptions/OFSignalConditionFailedException.h +++ src/exceptions/OFSignalConditionFailedException.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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_THREADS +# error No threads available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFCondition; + +/** + * @class OFSignalConditionFailedException \ + * OFSignalConditionFailedException.h \ + * ObjFW/OFSignalConditionFailedException.h + * + * @brief An exception indicating signaling a condition failed. + */ +@interface OFSignalConditionFailedException: OFException +{ + OFCondition *_condition; + int _errNo; + OF_RESERVE_IVARS(OFSignalConditionFailedException, 4) +} + +/** + * @brief The condition which could not be signaled. + */ +@property (readonly, nonatomic) OFCondition *condition; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased condition signal failed exception. + * + * @param condition The condition which could not be signaled + * @param errNo The errno of the error that occurred + * @return A new, autoreleased condition signal failed exception + */ ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated condition signal failed exception. + * + * @param condition The condition which could not be signaled + * @param errNo The errno of the error that occurred + * @return An initialized condition signal failed exception + */ +- (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFSignalConditionFailedException.m Index: src/exceptions/OFSignalConditionFailedException.m ================================================================== --- src/exceptions/OFSignalConditionFailedException.m +++ src/exceptions/OFSignalConditionFailedException.m @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFSignalConditionFailedException.h" +#import "OFString.h" +#import "OFCondition.h" + +@implementation OFSignalConditionFailedException +@synthesize condition = _condition, errNo = _errNo; + ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo +{ + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo +{ + self = [super init]; + + _condition = [condition retain]; + _errNo = errNo; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_condition release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Signaling a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; +} +@end ADDED src/exceptions/OFStartThreadFailedException.h Index: src/exceptions/OFStartThreadFailedException.h ================================================================== --- src/exceptions/OFStartThreadFailedException.h +++ src/exceptions/OFStartThreadFailedException.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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_THREADS +# error No threads available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFThread; + +/** + * @class OFStartThreadFailedException \ + * OFStartThreadFailedException.h ObjFW/OFStartThreadFailedException.h + * + * @brief An exception indicating that starting a thread failed. + */ +@interface OFStartThreadFailedException: OFException +{ + OFThread *_Nullable _thread; + int _errNo; + OF_RESERVE_IVARS(OFStartThreadFailedException, 4) +} + +/** + * @brief The thread which could not be started. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased thread start failed exception. + * + * @param thread The thread which could not be started + * @param errNo The errno of the error that occurred + * @return A new, autoreleased thread start failed exception + */ ++ (instancetype)exceptionWithThread: (nullable OFThread *)thread + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated thread start failed exception. + * + * @param thread The thread which could not be started + * @param errNo The errno of the error that occurred + * @return An initialized thread start failed exception + */ +- (instancetype)initWithThread: (nullable OFThread *)thread + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFStartThreadFailedException.m Index: src/exceptions/OFStartThreadFailedException.m ================================================================== --- src/exceptions/OFStartThreadFailedException.m +++ src/exceptions/OFStartThreadFailedException.m @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFStartThreadFailedException.h" +#import "OFString.h" +#import "OFThread.h" + +@implementation OFStartThreadFailedException +@synthesize thread = _thread, errNo = _errNo; + ++ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo +{ + return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo +{ + self = [super init]; + + _thread = [thread retain]; + _errNo = errNo; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_thread release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Starting a thread of type %@ failed: %s", + _thread.class, strerror(_errNo)]; +} +@end 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 DELETED src/exceptions/OFThreadJoinFailedException.h Index: src/exceptions/OFThreadJoinFailedException.h ================================================================== --- src/exceptions/OFThreadJoinFailedException.h +++ src/exceptions/OFThreadJoinFailedException.h @@ -1,74 +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_THREADS -# error No threads available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFThread; - -/** - * @class OFThreadJoinFailedException \ - * OFThreadJoinFailedException.h ObjFW/OFThreadJoinFailedException.h - * - * @brief An exception indicating that joining a thread failed. - */ -@interface OFThreadJoinFailedException: OFException -{ - OFThread *_Nullable _thread; - int _errNo; - OF_RESERVE_IVARS(OFThreadJoinFailedException, 4) -} - -/** - * @brief The thread which could not be joined. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased thread join failed exception. - * - * @param thread The thread which could not be joined - * @param errNo The errno of the error that occurred - * @return A new, autoreleased thread join failed exception - */ -+ (instancetype)exceptionWithThread: (nullable OFThread *)thread - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated thread join failed exception. - * - * @param thread The thread which could not be joined - * @param errNo The errno of the error that occurred - * @return An initialized thread join failed exception - */ -- (instancetype)initWithThread: (nullable OFThread *)thread - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFThreadJoinFailedException.m Index: src/exceptions/OFThreadJoinFailedException.m ================================================================== --- src/exceptions/OFThreadJoinFailedException.m +++ src/exceptions/OFThreadJoinFailedException.m @@ -1,65 +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 "OFThreadJoinFailedException.h" -#import "OFString.h" -#import "OFThread.h" - -@implementation OFThreadJoinFailedException -@synthesize thread = _thread, errNo = _errNo; - -+ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo -{ - return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo -{ - self = [super init]; - - _thread = [thread retain]; - _errNo = errNo; - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_thread release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Joining a thread of type %@ failed: %s", - _thread.class, strerror(_errNo)]; -} -@end DELETED src/exceptions/OFThreadStartFailedException.h Index: src/exceptions/OFThreadStartFailedException.h ================================================================== --- src/exceptions/OFThreadStartFailedException.h +++ src/exceptions/OFThreadStartFailedException.h @@ -1,74 +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_THREADS -# error No threads available! -#endif - -OF_ASSUME_NONNULL_BEGIN - -@class OFThread; - -/** - * @class OFThreadStartFailedException \ - * OFThreadStartFailedException.h ObjFW/OFThreadStartFailedException.h - * - * @brief An exception indicating that starting a thread failed. - */ -@interface OFThreadStartFailedException: OFException -{ - OFThread *_Nullable _thread; - int _errNo; - OF_RESERVE_IVARS(OFThreadStartFailedException, 4) -} - -/** - * @brief The thread which could not be started. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; - -/** - * @brief The errno of the error that occurred. - */ -@property (readonly, nonatomic) int errNo; - -/** - * @brief Creates a new, autoreleased thread start failed exception. - * - * @param thread The thread which could not be started - * @param errNo The errno of the error that occurred - * @return A new, autoreleased thread start failed exception - */ -+ (instancetype)exceptionWithThread: (nullable OFThread *)thread - errNo: (int)errNo; - -+ (instancetype)exception OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated thread start failed exception. - * - * @param thread The thread which could not be started - * @param errNo The errno of the error that occurred - * @return An initialized thread start failed exception - */ -- (instancetype)initWithThread: (nullable OFThread *)thread - errNo: (int)errNo OF_DESIGNATED_INITIALIZER; - -- (instancetype)init OF_UNAVAILABLE; -@end - -OF_ASSUME_NONNULL_END DELETED src/exceptions/OFThreadStartFailedException.m Index: src/exceptions/OFThreadStartFailedException.m ================================================================== --- src/exceptions/OFThreadStartFailedException.m +++ src/exceptions/OFThreadStartFailedException.m @@ -1,65 +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 "OFThreadStartFailedException.h" -#import "OFString.h" -#import "OFThread.h" - -@implementation OFThreadStartFailedException -@synthesize thread = _thread, errNo = _errNo; - -+ (instancetype)exceptionWithThread: (OFThread *)thread errNo: (int)errNo -{ - return [[[self alloc] initWithThread: thread errNo: errNo] autorelease]; -} - -+ (instancetype)exception -{ - OF_UNRECOGNIZED_SELECTOR -} - -- (instancetype)initWithThread: (OFThread *)thread errNo: (int)errNo -{ - self = [super init]; - - _thread = [thread retain]; - _errNo = errNo; - - return self; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (void)dealloc -{ - [_thread release]; - - [super dealloc]; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"Starting a thread of type %@ failed: %s", - _thread.class, strerror(_errNo)]; -} -@end 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 ADDED src/exceptions/OFWaitForConditionFailedException.h Index: src/exceptions/OFWaitForConditionFailedException.h ================================================================== --- src/exceptions/OFWaitForConditionFailedException.h +++ src/exceptions/OFWaitForConditionFailedException.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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_THREADS +# error No threads available! +#endif + +OF_ASSUME_NONNULL_BEGIN + +@class OFCondition; + +/** + * @class OFWaitForConditionFailedException \ + * OFWaitForConditionFailedException.h \ + * ObjFW/OFWaitForConditionFailedException.h + * + * @brief An exception indicating waiting for a condition failed. + */ +@interface OFWaitForConditionFailedException: OFException +{ + OFCondition *_condition; + int _errNo; + OF_RESERVE_IVARS(OFWaitForConditionFailedException, 4) +} + +/** + * @brief The condition for which could not be waited. + */ +@property (readonly, nonatomic) OFCondition *condition; + +/** + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + +/** + * @brief Creates a new, autoreleased condition wait failed exception. + * + * @param condition The condition for which could not be waited + * @param errNo The errno of the error that occurred + * @return A new, autoreleased condition wait failed exception + */ ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo; + ++ (instancetype)exception OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated condition wait failed exception. + * + * @param condition The condition for which could not be waited + * @param errNo The errno of the error that occurred + * @return An initialized condition wait failed exception + */ +- (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/exceptions/OFWaitForConditionFailedException.m Index: src/exceptions/OFWaitForConditionFailedException.m ================================================================== --- src/exceptions/OFWaitForConditionFailedException.m +++ src/exceptions/OFWaitForConditionFailedException.m @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "OFWaitForConditionFailedException.h" +#import "OFString.h" +#import "OFCondition.h" + +@implementation OFWaitForConditionFailedException +@synthesize condition = _condition, errNo = _errNo; + ++ (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo +{ + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFCondition *)condition errNo: (int)errNo +{ + self = [super init]; + + _condition = [condition retain]; + _errNo = errNo; + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_condition release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Waiting for a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; +} +@end 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 @@ -314,34 +314,34 @@ #else # define OF_DIRECT_MEMBERS #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 @@ -357,20 +357,27 @@ objc_error("ObjFWRT @ " __FILE__ ":" \ OF_STRINGIFY(__LINE__), \ "Failed to ensure condition:\n" #cond); \ } while(0) #else +@class OFConstantString; +extern void OFLog(OFConstantString *_Nonnull, ...); # define OFEnsure(cond) \ do { \ if OF_UNLIKELY (!(cond)) { \ - fprintf(stderr, "Failed to ensure condition " \ - "in " __FILE__ ":%d:\n" #cond "\n", \ - __LINE__); \ + OFLog(@"Failed to ensure condition in " \ + @__FILE__ ":%d: " @#cond, __LINE__); \ abort(); \ } \ } while (0) #endif + +#ifndef NDEBUG +# define OFAssert(...) OFEnsure(__VA_ARGS__) +#else +# define OFAssert(...) +#endif #define OF_UNRECOGNIZED_SELECTOR OFMethodNotFound(self, _cmd); #if __has_feature(objc_arc) # define OF_INVALID_INIT_METHOD OFMethodNotFound(self, _cmd); #else @@ -383,17 +390,18 @@ } \ \ abort(); #endif #ifdef __clang__ -# define OF_DEALLOC_UNSUPPORTED \ - [self doesNotRecognizeSelector: _cmd]; \ - \ - abort(); \ - \ - _Pragma("clang diagnostic push ignored \"-Wunreachable-code\""); \ - [super dealloc]; /* Get rid of a stupid warning */ \ +# define OF_DEALLOC_UNSUPPORTED \ + [self doesNotRecognizeSelector: _cmd]; \ + \ + abort(); \ + \ + _Pragma("clang diagnostic push"); \ + _Pragma("clang diagnostic ignored \"-Wunreachable-code\""); \ + [super dealloc]; /* Get rid of a stupid warning */ \ _Pragma("clang diagnostic pop"); #else # define OF_DEALLOC_UNSUPPORTED \ [self doesNotRecognizeSelector: _cmd]; \ \ @@ -440,11 +448,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) ); @@ -470,11 +478,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) ); @@ -502,11 +510,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,9 +1,11 @@ #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 #undef OF_HAVE_BUILTIN_BSWAP16 #undef OF_HAVE_BUILTIN_BSWAP32 #undef OF_HAVE_BUILTIN_BSWAP64 @@ -14,25 +16,28 @@ #undef OF_HAVE_IPV6 #undef OF_HAVE_IPX #undef OF_HAVE_LIMITS_H #undef OF_HAVE_LINK #undef OF_HAVE_MAX_ALIGN_T +#undef OF_HAVE_NETATALK_AT_H +#undef OF_HAVE_NETAT_APPLETALK_H #undef OF_HAVE_NETINET_IN_H #undef OF_HAVE_NETINET_TCP_H #undef OF_HAVE_NETIPX_IPX_H #undef OF_HAVE_OSATOMIC #undef OF_HAVE_OSATOMIC_64 #undef OF_HAVE_PIPE #undef OF_HAVE_PLEDGE #undef OF_HAVE_PLUGINS -#undef OF_HAVE_SUBPROCESSES #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 #undef OF_HAVE_SYS_SOCKET_H #undef OF_HAVE_SYS_TYPES_H #undef OF_HAVE_SYS_UN_H 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 @@ -13,20 +13,22 @@ * file. */ #include "config.h" -#include #include #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; @@ -191,11 +193,11 @@ } Wait(1ul << thread->joinSigBit); FreeSignal(thread->joinSigBit); - assert(thread->done); + OFAssert(thread->done); free(thread); return 0; } 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 @@ -361,12 +361,14 @@ return _writePipe[1]; } - (void)closeForWriting { - if (_writePipe[1] != -1) - close(_writePipe[1]); + if (_readPipe[0] == -1 || _writePipe[1] == -1) + @throw [OFNotOpenException exceptionWithObject: self]; + + close(_writePipe[1]); _writePipe[1] = -1; } - (void)close 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 @@ -368,12 +368,14 @@ return (size_t)bytesWritten; } - (void)closeForWriting { - if (_writePipe[1] != NULL) - CloseHandle(_writePipe[1]); + if (_readPipe[0] == NULL || _writePipe[1] == NULL) + @throw [OFNotOpenException exceptionWithObject: self]; + + CloseHandle(_writePipe[1]); _writePipe[1] = NULL; } - (void)close 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 @@ -37,11 +37,10 @@ * writing binary), it checks that the handle is indeed a console. */ #include "config.h" -#include #include #include #import "OFWin32ConsoleStdIOStream.h" #import "OFColor.h" @@ -293,11 +292,11 @@ UTF8Len = OFUTF8StringDecode( _incompleteUTF8Surrogate, _incompleteUTF8SurrogateLen, &c); if (UTF8Len <= 0 || c > 0x10FFFF) { - assert(UTF8Len == 0 || UTF8Len < -4); + OFAssert(UTF8Len == 0 || UTF8Len < -4); UTF16[0] = 0xFFFD; UTF16Len = 1; } else { if (c > 0xFFFF) { 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/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -1,15 +1,13 @@ include ../../extra.mk SUBDIRS = lookup-asm -SUBDIRS_AFTER = ${LINKLIB} DISTCLEAN = Info.plist SHARED_LIB = ${OBJFWRT_SHARED_LIB} STATIC_LIB = ${OBJFWRT_STATIC_LIB} FRAMEWORK = ${OBJFWRT_FRAMEWORK} -AMIGA_LIB = ${OBJFWRT_AMIGA_LIB} LIB_MAJOR = ${OBJFWRT_LIB_MAJOR} LIB_MINOR = ${OBJFWRT_LIB_MINOR} SRCS = arc.m \ autorelease.m \ @@ -41,25 +39,19 @@ INCLUDES = ObjFWRT.h includesubdir = ObjFWRT OBJS_EXTRA = lookup-asm/lookup-asm.a LIB_OBJS_EXTRA = lookup-asm/lookup-asm.lib.a -AMIGA_LIB_OBJS_START = amiga-library.amigalib.o -AMIGA_LIB_OBJS_EXTRA = amiga-glue.amigalib.o \ - lookup-asm/lookup-asm.amigalib.a \ - amiga-end.amigalib.o include ../../buildsys.mk CPPFLAGS += -I. -I.. -I../.. \ -DOBJC_COMPILING_RUNTIME \ - -DOBJFWRT_AMIGA_LIB=\"${OBJFWRT_AMIGA_LIB}\" \ -DOBJFWRT_LIB_MAJOR=${OBJFWRT_LIB_MAJOR} \ -DOBJFWRT_LIB_MINOR=${OBJFWRT_LIB_MINOR} -AMIGA_LIB_CFLAGS += -DOBJC_COMPILING_AMIGA_LIBRARY LD = ${OBJC} FRAMEWORK_LIBS = ${LIBS} RCFLAGS = --use-temp-file \ -DOBJFWRT_LIB_MAJOR=${OBJFWRT_LIB_MAJOR} \ -DOBJFWRT_LIB_MINOR=${OBJFWRT_LIB_MINOR} \ -DOBJFWRT_LIB_VERSION=\"${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR}\" \ -DOBJFWRT_SHARED_LIB=\"${OBJFWRT_SHARED_LIB}\" 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 DELETED src/runtime/amiga-end.m Index: src/runtime/amiga-end.m ================================================================== --- src/runtime/amiga-end.m +++ src/runtime/amiga-end.m @@ -1,31 +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 "platform.h" - -#ifdef OF_MORPHOS -__asm__ ( - ".section .eh_frame, \"aw\"\n" - " .long 0\n" - ".section .ctors, \"aw\"\n" - " .long 0" -); -#else -__asm__ ( - "" -); -#endif DELETED src/runtime/amiga-funcarray.inc Index: src/runtime/amiga-funcarray.inc ================================================================== --- src/runtime/amiga-funcarray.inc +++ src/runtime/amiga-funcarray.inc @@ -1,106 +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. - */ - -/* This file is automatically generated from amiga-library.xml */ - -(CONST_APTR)glue_objc_init, -(CONST_APTR)glue___objc_exec_class, -(CONST_APTR)glue_objc_msg_lookup, -(CONST_APTR)glue_objc_msg_lookup_stret, -(CONST_APTR)glue_objc_msg_lookup_super, -(CONST_APTR)glue_objc_msg_lookup_super_stret, -(CONST_APTR)glue_objc_lookUpClass, -(CONST_APTR)glue_objc_getClass, -(CONST_APTR)glue_objc_getRequiredClass, -(CONST_APTR)glue_objc_lookup_class, -(CONST_APTR)glue_objc_get_class, -(CONST_APTR)glue_objc_exception_throw, -(CONST_APTR)glue_objc_sync_enter, -(CONST_APTR)glue_objc_sync_exit, -(CONST_APTR)glue_objc_getProperty, -(CONST_APTR)glue_objc_setProperty, -(CONST_APTR)glue_objc_getPropertyStruct, -(CONST_APTR)glue_objc_setPropertyStruct, -(CONST_APTR)glue_objc_enumerationMutation, -(CONST_APTR)glue___gnu_objc_personality, -(CONST_APTR)glue_objc_retain, -(CONST_APTR)glue_objc_retainBlock, -(CONST_APTR)glue_objc_retainAutorelease, -(CONST_APTR)glue_objc_release, -(CONST_APTR)glue_objc_autorelease, -(CONST_APTR)glue_objc_autoreleaseReturnValue, -(CONST_APTR)glue_objc_retainAutoreleaseReturnValue, -(CONST_APTR)glue_objc_retainAutoreleasedReturnValue, -(CONST_APTR)glue_objc_storeStrong, -(CONST_APTR)glue_objc_storeWeak, -(CONST_APTR)glue_objc_loadWeakRetained, -(CONST_APTR)glue_objc_initWeak, -(CONST_APTR)glue_objc_destroyWeak, -(CONST_APTR)glue_objc_loadWeak, -(CONST_APTR)glue_objc_copyWeak, -(CONST_APTR)glue_objc_moveWeak, -(CONST_APTR)glue_sel_registerName, -(CONST_APTR)glue_sel_getName, -(CONST_APTR)glue_sel_isEqual, -(CONST_APTR)glue_objc_allocateClassPair, -(CONST_APTR)glue_objc_registerClassPair, -(CONST_APTR)glue_objc_getClassList, -(CONST_APTR)glue_objc_copyClassList, -(CONST_APTR)glue_class_isMetaClass, -(CONST_APTR)glue_class_getName, -(CONST_APTR)glue_class_getSuperclass, -(CONST_APTR)glue_class_getInstanceSize, -(CONST_APTR)glue_class_respondsToSelector, -(CONST_APTR)glue_class_conformsToProtocol, -(CONST_APTR)glue_class_getMethodImplementation, -(CONST_APTR)glue_class_getMethodImplementation_stret, -(CONST_APTR)glue_class_getInstanceMethod, -(CONST_APTR)glue_class_addMethod, -(CONST_APTR)glue_class_replaceMethod, -(CONST_APTR)glue_object_getClass, -(CONST_APTR)glue_object_setClass, -(CONST_APTR)glue_object_getClassName, -(CONST_APTR)glue_protocol_getName, -(CONST_APTR)glue_protocol_isEqual, -(CONST_APTR)glue_protocol_conformsToProtocol, -(CONST_APTR)glue_objc_setUncaughtExceptionHandler, -(CONST_APTR)glue_objc_setForwardHandler, -(CONST_APTR)glue_objc_setEnumerationMutationHandler, -(CONST_APTR)glue_objc_constructInstance, -(CONST_APTR)glue_objc_deinit, -(CONST_APTR)glue_class_copyIvarList, -(CONST_APTR)glue_ivar_getName, -(CONST_APTR)glue_ivar_getTypeEncoding, -(CONST_APTR)glue_ivar_getOffset, -(CONST_APTR)glue_class_copyMethodList, -(CONST_APTR)glue_method_getName, -(CONST_APTR)glue_method_getTypeEncoding, -(CONST_APTR)glue_class_copyPropertyList, -(CONST_APTR)glue_property_getName, -(CONST_APTR)glue_property_copyAttributeValue, -(CONST_APTR)glue_objc_destructInstance, -(CONST_APTR)glue_objc_autoreleasePoolPush, -(CONST_APTR)glue_objc_autoreleasePoolPop, -(CONST_APTR)glue__objc_rootAutorelease, -(CONST_APTR)glue_objc_hashtable_new, -(CONST_APTR)glue_objc_hashtable_set, -(CONST_APTR)glue_objc_hashtable_get, -(CONST_APTR)glue_objc_hashtable_delete, -(CONST_APTR)glue_objc_hashtable_free, -(CONST_APTR)glue_objc_setTaggedPointerSecret, -(CONST_APTR)glue_objc_registerTaggedPointerClass, -(CONST_APTR)glue_object_isTaggedPointer, -(CONST_APTR)glue_object_getTaggedPointerValue, -(CONST_APTR)glue_objc_createTaggedPointer, DELETED src/runtime/amiga-glue.h Index: src/runtime/amiga-glue.h ================================================================== --- src/runtime/amiga-glue.h +++ src/runtime/amiga-glue.h @@ -1,119 +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. - */ - -/* This file is automatically generated from amiga-library.xml */ - -#import "ObjFWRT.h" -#import "private.h" - -#ifdef OF_AMIGAOS_M68K -# define PPC_PARAMS(...) (void) -# define M68K_ARG(type, name, reg) \ - register type reg##name __asm__(#reg); \ - type name = reg##name; -#else -# define PPC_PARAMS(...) (__VA_ARGS__) -# define M68K_ARG(...) -#endif - -extern bool glue_objc_init PPC_PARAMS(unsigned int version, struct objc_libc *libc); -extern void glue___objc_exec_class PPC_PARAMS(struct objc_module *_Nonnull module); -extern IMP _Nonnull glue_objc_msg_lookup PPC_PARAMS(id _Nullable object, SEL _Nonnull selector); -extern IMP _Nonnull glue_objc_msg_lookup_stret PPC_PARAMS(id _Nullable object, SEL _Nonnull selector); -extern IMP _Nonnull glue_objc_msg_lookup_super PPC_PARAMS(struct objc_super *_Nonnull super, SEL _Nonnull selector); -extern IMP _Nonnull glue_objc_msg_lookup_super_stret PPC_PARAMS(struct objc_super *_Nonnull super, SEL _Nonnull selector); -extern Class _Nullable glue_objc_lookUpClass PPC_PARAMS(const char *_Nonnull name); -extern Class _Nullable glue_objc_getClass PPC_PARAMS(const char *_Nonnull name); -extern Class _Nonnull glue_objc_getRequiredClass PPC_PARAMS(const char *_Nonnull name); -extern Class _Nullable glue_objc_lookup_class PPC_PARAMS(const char *_Nonnull name); -extern Class _Nonnull glue_objc_get_class PPC_PARAMS(const char *_Nonnull name); -extern void glue_objc_exception_throw PPC_PARAMS(id _Nonnull object); -extern int glue_objc_sync_enter PPC_PARAMS(id _Nullable object); -extern int glue_objc_sync_exit PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_getProperty PPC_PARAMS(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic); -extern void glue_objc_setProperty PPC_PARAMS(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id _Nullable value, bool atomic, signed char copy); -extern void glue_objc_getPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong); -extern void glue_objc_setPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong); -extern void glue_objc_enumerationMutation PPC_PARAMS(id _Nonnull object); -extern int glue___gnu_objc_personality PPC_PARAMS(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx); -extern id _Nullable glue_objc_retain PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_retainBlock PPC_PARAMS(id _Nullable block); -extern id _Nullable glue_objc_retainAutorelease PPC_PARAMS(id _Nullable object); -extern void glue_objc_release PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_autorelease PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_autoreleaseReturnValue PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_retainAutoreleaseReturnValue PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_retainAutoreleasedReturnValue PPC_PARAMS(id _Nullable object); -extern id _Nullable glue_objc_storeStrong PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value); -extern id _Nullable glue_objc_storeWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value); -extern id _Nullable glue_objc_loadWeakRetained PPC_PARAMS(id _Nullable *_Nonnull object); -extern id _Nullable glue_objc_initWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value); -extern void glue_objc_destroyWeak PPC_PARAMS(id _Nullable *_Nonnull object); -extern id _Nullable glue_objc_loadWeak PPC_PARAMS(id _Nullable *_Nonnull object); -extern void glue_objc_copyWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src); -extern void glue_objc_moveWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src); -extern SEL _Nonnull glue_sel_registerName PPC_PARAMS(const char *_Nonnull name); -extern const char *_Nonnull glue_sel_getName PPC_PARAMS(SEL _Nonnull selector); -extern bool glue_sel_isEqual PPC_PARAMS(SEL _Nonnull selector1, SEL _Nonnull selector2); -extern Class _Nonnull glue_objc_allocateClassPair PPC_PARAMS(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes); -extern void glue_objc_registerClassPair PPC_PARAMS(Class _Nonnull class); -extern unsigned int glue_objc_getClassList PPC_PARAMS(Class _Nonnull *_Nullable buffer, unsigned int count); -extern Class _Nonnull *_Nonnull glue_objc_copyClassList PPC_PARAMS(unsigned int *_Nullable length); -extern bool glue_class_isMetaClass PPC_PARAMS(Class _Nullable class); -extern const char *_Nullable glue_class_getName PPC_PARAMS(Class _Nullable class); -extern Class _Nullable glue_class_getSuperclass PPC_PARAMS(Class _Nullable class); -extern unsigned long glue_class_getInstanceSize PPC_PARAMS(Class _Nullable class); -extern bool glue_class_respondsToSelector PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector); -extern bool glue_class_conformsToProtocol PPC_PARAMS(Class _Nullable class, Protocol *_Nonnull p); -extern IMP _Nullable glue_class_getMethodImplementation PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector); -extern IMP _Nullable glue_class_getMethodImplementation_stret PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector); -extern Method _Nullable glue_class_getInstanceMethod PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector); -extern bool glue_class_addMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding); -extern IMP _Nullable glue_class_replaceMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding); -extern Class _Nullable glue_object_getClass PPC_PARAMS(id _Nullable object); -extern Class _Nullable glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class); -extern const char *_Nullable glue_object_getClassName PPC_PARAMS(id _Nullable object); -extern const char *_Nonnull glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol); -extern bool glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); -extern bool glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); -extern _Nullable objc_uncaught_exception_handler glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler); -extern void glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward); -extern void glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler); -extern id _Nullable glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes); -extern void glue_objc_deinit(void); -extern Ivar _Nullable *_Nullable glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount); -extern const char *_Nonnull glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar); -extern const char *_Nonnull glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar); -extern ptrdiff_t glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar); -extern Method _Nullable *_Nullable glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount); -extern SEL _Nonnull glue_method_getName PPC_PARAMS(Method _Nonnull method); -extern const char *_Nullable glue_method_getTypeEncoding PPC_PARAMS(Method _Nonnull method); -extern objc_property_t _Nullable *_Nullable glue_class_copyPropertyList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount); -extern const char *_Nonnull glue_property_getName PPC_PARAMS(objc_property_t _Nonnull property); -extern char *_Nullable glue_property_copyAttributeValue PPC_PARAMS(objc_property_t _Nonnull property, const char *_Nonnull name); -extern void *_Nullable glue_objc_destructInstance PPC_PARAMS(id _Nullable object); -extern void *_Null_unspecified glue_objc_autoreleasePoolPush(void); -extern void glue_objc_autoreleasePoolPop PPC_PARAMS(void *_Null_unspecified pool); -extern id _Nullable glue__objc_rootAutorelease PPC_PARAMS(id _Nullable object); -extern struct objc_hashtable *_Nonnull glue_objc_hashtable_new PPC_PARAMS(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size); -extern void glue_objc_hashtable_set PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object); -extern void *_Nullable glue_objc_hashtable_get PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key); -extern void glue_objc_hashtable_delete PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key); -extern void glue_objc_hashtable_free PPC_PARAMS(struct objc_hashtable *_Nonnull table); -extern void glue_objc_setTaggedPointerSecret PPC_PARAMS(uintptr_t secret); -extern int glue_objc_registerTaggedPointerClass PPC_PARAMS(Class _Nonnull class); -extern bool glue_object_isTaggedPointer PPC_PARAMS(id _Nullable object); -extern uintptr_t glue_object_getTaggedPointerValue PPC_PARAMS(id _Nonnull object); -extern id _Nullable glue_objc_createTaggedPointer PPC_PARAMS(int class, uintptr_t value); DELETED src/runtime/amiga-glue.m Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -1,800 +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. - */ - -/* This file is automatically generated from amiga-library.xml */ - -#include "config.h" - -#import "amiga-glue.h" - -#ifdef OF_MORPHOS -/* All __saveds functions in this file need to use the SysV ABI */ -__asm__ ( - ".section .text\n" - ".align 2\n" - "__restore_r13:\n" - " lwz %r13, 44(%r12)\n" - " blr\n" -); -#endif - -bool __saveds -glue_objc_init PPC_PARAMS(unsigned int version, struct objc_libc *libc) -{ - M68K_ARG(unsigned int, version, d0) - M68K_ARG(struct objc_libc *, libc, a0) - - return objc_init(version, libc); -} - -void __saveds -glue___objc_exec_class PPC_PARAMS(struct objc_module *_Nonnull module) -{ - M68K_ARG(struct objc_module *_Nonnull, module, a0) - - __objc_exec_class(module); -} - -IMP _Nonnull __saveds -glue_objc_msg_lookup PPC_PARAMS(id _Nullable object, SEL _Nonnull selector) -{ - M68K_ARG(id _Nullable, object, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return objc_msg_lookup(object, selector); -} - -IMP _Nonnull __saveds -glue_objc_msg_lookup_stret PPC_PARAMS(id _Nullable object, SEL _Nonnull selector) -{ - M68K_ARG(id _Nullable, object, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return objc_msg_lookup_stret(object, selector); -} - -IMP _Nonnull __saveds -glue_objc_msg_lookup_super PPC_PARAMS(struct objc_super *_Nonnull super, SEL _Nonnull selector) -{ - M68K_ARG(struct objc_super *_Nonnull, super, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return objc_msg_lookup_super(super, selector); -} - -IMP _Nonnull __saveds -glue_objc_msg_lookup_super_stret PPC_PARAMS(struct objc_super *_Nonnull super, SEL _Nonnull selector) -{ - M68K_ARG(struct objc_super *_Nonnull, super, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return objc_msg_lookup_super_stret(super, selector); -} - -Class _Nullable __saveds -glue_objc_lookUpClass PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return objc_lookUpClass(name); -} - -Class _Nullable __saveds -glue_objc_getClass PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return objc_getClass(name); -} - -Class _Nonnull __saveds -glue_objc_getRequiredClass PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return objc_getRequiredClass(name); -} - -Class _Nullable __saveds -glue_objc_lookup_class PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return objc_lookup_class(name); -} - -Class _Nonnull __saveds -glue_objc_get_class PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return objc_get_class(name); -} - -void __saveds -glue_objc_exception_throw PPC_PARAMS(id _Nonnull object) -{ - M68K_ARG(id _Nonnull, object, a0) - - objc_exception_throw(object); -} - -int __saveds -glue_objc_sync_enter PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_sync_enter(object); -} - -int __saveds -glue_objc_sync_exit PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_sync_exit(object); -} - -id _Nullable __saveds -glue_objc_getProperty PPC_PARAMS(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic) -{ - M68K_ARG(id _Nonnull, self, a0) - M68K_ARG(SEL _Nonnull, _cmd, a1) - M68K_ARG(ptrdiff_t, offset, d0) - M68K_ARG(bool, atomic, d1) - - return objc_getProperty(self, _cmd, offset, atomic); -} - -void __saveds -glue_objc_setProperty PPC_PARAMS(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id _Nullable value, bool atomic, signed char copy) -{ - M68K_ARG(id _Nonnull, self, a0) - M68K_ARG(SEL _Nonnull, _cmd, a1) - M68K_ARG(ptrdiff_t, offset, d0) - M68K_ARG(id _Nullable, value, a2) - M68K_ARG(bool, atomic, d1) - M68K_ARG(signed char, copy, d2) - - objc_setProperty(self, _cmd, offset, value, atomic, copy); -} - -void __saveds -glue_objc_getPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) -{ - M68K_ARG(void *_Nonnull, dest, a0) - M68K_ARG(const void *_Nonnull, src, a1) - M68K_ARG(ptrdiff_t, size, d0) - M68K_ARG(bool, atomic, d1) - M68K_ARG(bool, strong, d2) - - objc_getPropertyStruct(dest, src, size, atomic, strong); -} - -void __saveds -glue_objc_setPropertyStruct PPC_PARAMS(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) -{ - M68K_ARG(void *_Nonnull, dest, a0) - M68K_ARG(const void *_Nonnull, src, a1) - M68K_ARG(ptrdiff_t, size, d0) - M68K_ARG(bool, atomic, d1) - M68K_ARG(bool, strong, d2) - - objc_setPropertyStruct(dest, src, size, atomic, strong); -} - -void __saveds -glue_objc_enumerationMutation PPC_PARAMS(id _Nonnull object) -{ - M68K_ARG(id _Nonnull, object, a0) - - objc_enumerationMutation(object); -} - -int __saveds -glue___gnu_objc_personality PPC_PARAMS(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx) -{ - M68K_ARG(int, version, d0) - M68K_ARG(int, actions, d1) - M68K_ARG(uint64_t *_Nonnull, exClass, d2) - M68K_ARG(void *_Nonnull, ex, a0) - M68K_ARG(void *_Nonnull, ctx, a1) - - return __gnu_objc_personality(version, actions, exClass, ex, ctx); -} - -id _Nullable __saveds -glue_objc_retain PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_retain(object); -} - -id _Nullable __saveds -glue_objc_retainBlock PPC_PARAMS(id _Nullable block) -{ - M68K_ARG(id _Nullable, block, a0) - - return objc_retainBlock(block); -} - -id _Nullable __saveds -glue_objc_retainAutorelease PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_retainAutorelease(object); -} - -void __saveds -glue_objc_release PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - objc_release(object); -} - -id _Nullable __saveds -glue_objc_autorelease PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_autorelease(object); -} - -id _Nullable __saveds -glue_objc_autoreleaseReturnValue PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_autoreleaseReturnValue(object); -} - -id _Nullable __saveds -glue_objc_retainAutoreleaseReturnValue PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_retainAutoreleaseReturnValue(object); -} - -id _Nullable __saveds -glue_objc_retainAutoreleasedReturnValue PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_retainAutoreleasedReturnValue(object); -} - -id _Nullable __saveds -glue_objc_storeStrong PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - M68K_ARG(id _Nullable, value, a1) - - return objc_storeStrong(object, value); -} - -id _Nullable __saveds -glue_objc_storeWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - M68K_ARG(id _Nullable, value, a1) - - return objc_storeWeak(object, value); -} - -id _Nullable __saveds -glue_objc_loadWeakRetained PPC_PARAMS(id _Nullable *_Nonnull object) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - - return objc_loadWeakRetained(object); -} - -id _Nullable __saveds -glue_objc_initWeak PPC_PARAMS(id _Nullable *_Nonnull object, id _Nullable value) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - M68K_ARG(id _Nullable, value, a1) - - return objc_initWeak(object, value); -} - -void __saveds -glue_objc_destroyWeak PPC_PARAMS(id _Nullable *_Nonnull object) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - - objc_destroyWeak(object); -} - -id _Nullable __saveds -glue_objc_loadWeak PPC_PARAMS(id _Nullable *_Nonnull object) -{ - M68K_ARG(id _Nullable *_Nonnull, object, a0) - - return objc_loadWeak(object); -} - -void __saveds -glue_objc_copyWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) -{ - M68K_ARG(id _Nullable *_Nonnull, dest, a0) - M68K_ARG(id _Nullable *_Nonnull, src, a1) - - objc_copyWeak(dest, src); -} - -void __saveds -glue_objc_moveWeak PPC_PARAMS(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) -{ - M68K_ARG(id _Nullable *_Nonnull, dest, a0) - M68K_ARG(id _Nullable *_Nonnull, src, a1) - - objc_moveWeak(dest, src); -} - -SEL _Nonnull __saveds -glue_sel_registerName PPC_PARAMS(const char *_Nonnull name) -{ - M68K_ARG(const char *_Nonnull, name, a0) - - return sel_registerName(name); -} - -const char *_Nonnull __saveds -glue_sel_getName PPC_PARAMS(SEL _Nonnull selector) -{ - M68K_ARG(SEL _Nonnull, selector, a0) - - return sel_getName(selector); -} - -bool __saveds -glue_sel_isEqual PPC_PARAMS(SEL _Nonnull selector1, SEL _Nonnull selector2) -{ - M68K_ARG(SEL _Nonnull, selector1, a0) - M68K_ARG(SEL _Nonnull, selector2, a1) - - return sel_isEqual(selector1, selector2); -} - -Class _Nonnull __saveds -glue_objc_allocateClassPair PPC_PARAMS(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes) -{ - M68K_ARG(Class _Nullable, superclass, a0) - M68K_ARG(const char *_Nonnull, name, a1) - M68K_ARG(size_t, extraBytes, d0) - - return objc_allocateClassPair(superclass, name, extraBytes); -} - -void __saveds -glue_objc_registerClassPair PPC_PARAMS(Class _Nonnull class) -{ - M68K_ARG(Class _Nonnull, class, a0) - - objc_registerClassPair(class); -} - -unsigned int __saveds -glue_objc_getClassList PPC_PARAMS(Class _Nonnull *_Nullable buffer, unsigned int count) -{ - M68K_ARG(Class _Nonnull *_Nullable, buffer, a0) - M68K_ARG(unsigned int, count, d0) - - return objc_getClassList(buffer, count); -} - -Class _Nonnull *_Nonnull __saveds -glue_objc_copyClassList PPC_PARAMS(unsigned int *_Nullable length) -{ - M68K_ARG(unsigned int *_Nullable, length, a0) - - return objc_copyClassList(length); -} - -bool __saveds -glue_class_isMetaClass PPC_PARAMS(Class _Nullable class) -{ - M68K_ARG(Class _Nullable, class, a0) - - return class_isMetaClass(class); -} - -const char *_Nullable __saveds -glue_class_getName PPC_PARAMS(Class _Nullable class) -{ - M68K_ARG(Class _Nullable, class, a0) - - return class_getName(class); -} - -Class _Nullable __saveds -glue_class_getSuperclass PPC_PARAMS(Class _Nullable class) -{ - M68K_ARG(Class _Nullable, class, a0) - - return class_getSuperclass(class); -} - -unsigned long __saveds -glue_class_getInstanceSize PPC_PARAMS(Class _Nullable class) -{ - M68K_ARG(Class _Nullable, class, a0) - - return class_getInstanceSize(class); -} - -bool __saveds -glue_class_respondsToSelector PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return class_respondsToSelector(class, selector); -} - -bool __saveds -glue_class_conformsToProtocol PPC_PARAMS(Class _Nullable class, Protocol *_Nonnull p) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(Protocol *_Nonnull, p, a1) - - return class_conformsToProtocol(class, p); -} - -IMP _Nullable __saveds -glue_class_getMethodImplementation PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return class_getMethodImplementation(class, selector); -} - -IMP _Nullable __saveds -glue_class_getMethodImplementation_stret PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return class_getMethodImplementation_stret(class, selector); -} - -Method _Nullable __saveds -glue_class_getInstanceMethod PPC_PARAMS(Class _Nullable class, SEL _Nonnull selector) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - - return class_getInstanceMethod(class, selector); -} - -bool __saveds -glue_class_addMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding) -{ - M68K_ARG(Class _Nonnull, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - M68K_ARG(IMP _Nonnull, implementation, a2) - M68K_ARG(const char *_Nullable, typeEncoding, a3) - - return class_addMethod(class, selector, implementation, typeEncoding); -} - -IMP _Nullable __saveds -glue_class_replaceMethod PPC_PARAMS(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding) -{ - M68K_ARG(Class _Nonnull, class, a0) - M68K_ARG(SEL _Nonnull, selector, a1) - M68K_ARG(IMP _Nonnull, implementation, a2) - M68K_ARG(const char *_Nullable, typeEncoding, a3) - - return class_replaceMethod(class, selector, implementation, typeEncoding); -} - -Class _Nullable __saveds -glue_object_getClass PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return object_getClass(object); -} - -Class _Nullable __saveds -glue_object_setClass PPC_PARAMS(id _Nullable object, Class _Nonnull class) -{ - M68K_ARG(id _Nullable, object, a0) - M68K_ARG(Class _Nonnull, class, a1) - - return object_setClass(object, class); -} - -const char *_Nullable __saveds -glue_object_getClassName PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return object_getClassName(object); -} - -const char *_Nonnull __saveds -glue_protocol_getName PPC_PARAMS(Protocol *_Nonnull protocol) -{ - M68K_ARG(Protocol *_Nonnull, protocol, a0) - - return protocol_getName(protocol); -} - -bool __saveds -glue_protocol_isEqual PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) -{ - M68K_ARG(Protocol *_Nonnull, protocol1, a0) - M68K_ARG(Protocol *_Nonnull, protocol2, a1) - - return protocol_isEqual(protocol1, protocol2); -} - -bool __saveds -glue_protocol_conformsToProtocol PPC_PARAMS(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) -{ - M68K_ARG(Protocol *_Nonnull, protocol1, a0) - M68K_ARG(Protocol *_Nonnull, protocol2, a1) - - return protocol_conformsToProtocol(protocol1, protocol2); -} - -_Nullable objc_uncaught_exception_handler __saveds -glue_objc_setUncaughtExceptionHandler PPC_PARAMS(objc_uncaught_exception_handler _Nullable handler) -{ - M68K_ARG(objc_uncaught_exception_handler _Nullable, handler, a0) - - return objc_setUncaughtExceptionHandler(handler); -} - -void __saveds -glue_objc_setForwardHandler PPC_PARAMS(IMP _Nullable forward, IMP _Nullable stretForward) -{ - M68K_ARG(IMP _Nullable, forward, a0) - M68K_ARG(IMP _Nullable, stretForward, a1) - - objc_setForwardHandler(forward, stretForward); -} - -void __saveds -glue_objc_setEnumerationMutationHandler PPC_PARAMS(objc_enumeration_mutation_handler _Nullable hadler) -{ - M68K_ARG(objc_enumeration_mutation_handler _Nullable, hadler, a0) - - objc_setEnumerationMutationHandler(hadler); -} - -id _Nullable __saveds -glue_objc_constructInstance PPC_PARAMS(Class _Nullable class, void *_Nullable bytes) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(void *_Nullable, bytes, a1) - - return objc_constructInstance(class, bytes); -} - -void __saveds -glue_objc_deinit(void) -{ - objc_deinit(); -} - -Ivar _Nullable *_Nullable __saveds -glue_class_copyIvarList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(unsigned int *_Nullable, outCount, a1) - - return class_copyIvarList(class, outCount); -} - -const char *_Nonnull __saveds -glue_ivar_getName PPC_PARAMS(Ivar _Nonnull ivar) -{ - M68K_ARG(Ivar _Nonnull, ivar, a0) - - return ivar_getName(ivar); -} - -const char *_Nonnull __saveds -glue_ivar_getTypeEncoding PPC_PARAMS(Ivar _Nonnull ivar) -{ - M68K_ARG(Ivar _Nonnull, ivar, a0) - - return ivar_getTypeEncoding(ivar); -} - -ptrdiff_t __saveds -glue_ivar_getOffset PPC_PARAMS(Ivar _Nonnull ivar) -{ - M68K_ARG(Ivar _Nonnull, ivar, a0) - - return ivar_getOffset(ivar); -} - -Method _Nullable *_Nullable __saveds -glue_class_copyMethodList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(unsigned int *_Nullable, outCount, a1) - - return class_copyMethodList(class, outCount); -} - -SEL _Nonnull __saveds -glue_method_getName PPC_PARAMS(Method _Nonnull method) -{ - M68K_ARG(Method _Nonnull, method, a0) - - return method_getName(method); -} - -const char *_Nullable __saveds -glue_method_getTypeEncoding PPC_PARAMS(Method _Nonnull method) -{ - M68K_ARG(Method _Nonnull, method, a0) - - return method_getTypeEncoding(method); -} - -objc_property_t _Nullable *_Nullable __saveds -glue_class_copyPropertyList PPC_PARAMS(Class _Nullable class, unsigned int *_Nullable outCount) -{ - M68K_ARG(Class _Nullable, class, a0) - M68K_ARG(unsigned int *_Nullable, outCount, a1) - - return class_copyPropertyList(class, outCount); -} - -const char *_Nonnull __saveds -glue_property_getName PPC_PARAMS(objc_property_t _Nonnull property) -{ - M68K_ARG(objc_property_t _Nonnull, property, a0) - - return property_getName(property); -} - -char *_Nullable __saveds -glue_property_copyAttributeValue PPC_PARAMS(objc_property_t _Nonnull property, const char *_Nonnull name) -{ - M68K_ARG(objc_property_t _Nonnull, property, a0) - M68K_ARG(const char *_Nonnull, name, a1) - - return property_copyAttributeValue(property, name); -} - -void *_Nullable __saveds -glue_objc_destructInstance PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return objc_destructInstance(object); -} - -void *_Null_unspecified __saveds -glue_objc_autoreleasePoolPush(void) -{ - return objc_autoreleasePoolPush(); -} - -void __saveds -glue_objc_autoreleasePoolPop PPC_PARAMS(void *_Null_unspecified pool) -{ - M68K_ARG(void *_Null_unspecified, pool, a0) - - objc_autoreleasePoolPop(pool); -} - -id _Nullable __saveds -glue__objc_rootAutorelease PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return _objc_rootAutorelease(object); -} - -struct objc_hashtable *_Nonnull __saveds -glue_objc_hashtable_new PPC_PARAMS(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size) -{ - M68K_ARG(objc_hashtable_hash_func, hash, a0) - M68K_ARG(objc_hashtable_equal_func, equal, a1) - M68K_ARG(uint32_t, size, d0) - - return objc_hashtable_new(hash, equal, size); -} - -void __saveds -glue_objc_hashtable_set PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object) -{ - M68K_ARG(struct objc_hashtable *_Nonnull, table, a0) - M68K_ARG(const void *_Nonnull, key, a1) - M68K_ARG(const void *_Nonnull, object, a2) - - objc_hashtable_set(table, key, object); -} - -void *_Nullable __saveds -glue_objc_hashtable_get PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) -{ - M68K_ARG(struct objc_hashtable *_Nonnull, table, a0) - M68K_ARG(const void *_Nonnull, key, a1) - - return objc_hashtable_get(table, key); -} - -void __saveds -glue_objc_hashtable_delete PPC_PARAMS(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) -{ - M68K_ARG(struct objc_hashtable *_Nonnull, table, a0) - M68K_ARG(const void *_Nonnull, key, a1) - - objc_hashtable_delete(table, key); -} - -void __saveds -glue_objc_hashtable_free PPC_PARAMS(struct objc_hashtable *_Nonnull table) -{ - M68K_ARG(struct objc_hashtable *_Nonnull, table, a0) - - objc_hashtable_free(table); -} - -void __saveds -glue_objc_setTaggedPointerSecret PPC_PARAMS(uintptr_t secret) -{ - M68K_ARG(uintptr_t, secret, d0) - - objc_setTaggedPointerSecret(secret); -} - -int __saveds -glue_objc_registerTaggedPointerClass PPC_PARAMS(Class _Nonnull class) -{ - M68K_ARG(Class _Nonnull, class, a0) - - return objc_registerTaggedPointerClass(class); -} - -bool __saveds -glue_object_isTaggedPointer PPC_PARAMS(id _Nullable object) -{ - M68K_ARG(id _Nullable, object, a0) - - return object_isTaggedPointer(object); -} - -uintptr_t __saveds -glue_object_getTaggedPointerValue PPC_PARAMS(id _Nonnull object) -{ - M68K_ARG(id _Nonnull, object, a0) - - return object_getTaggedPointerValue(object); -} - -id _Nullable __saveds -glue_objc_createTaggedPointer PPC_PARAMS(int class, uintptr_t value) -{ - M68K_ARG(int, class, d0) - M68K_ARG(uintptr_t, value, d1) - - return objc_createTaggedPointer(class, value); -} DELETED src/runtime/amiga-library.m Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -1,588 +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 "ObjFWRT.h" -#import "private.h" - -#import "amiga-glue.h" - -#include -#include -#include -#include - -#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) - -#if defined(OF_AMIGAOS_M68K) -# define DATA_OFFSET 0x7FFE -#elif defined(OF_MORPHOS) -# define DATA_OFFSET 0x8000 -#endif - -#ifdef OF_AMIGAOS_M68K -# define OBJC_M68K_REG(reg) __asm__(#reg) -#else -# define OBJC_M68K_REG(reg) -#endif - -/* This always needs to be the first thing in the file. */ -int -_start(void) -{ - return -1; -} - -#ifdef OF_AMIGAOS_M68K -void -__init_eh(void) -{ -} -#endif - -struct ObjFWRTBase { - struct Library library; - void *segList; - struct ObjFWRTBase *parent; - char *dataSeg; - bool initialized; -}; - -#ifdef OF_AMIGAOS_M68K -extern uintptr_t __CTOR_LIST__[]; -extern const void *_EH_FRAME_BEGINS__; -extern void *_EH_FRAME_OBJECTS__; -#endif - -#ifdef OF_MORPHOS -const ULONG __abox__ = 1; -#endif -struct ExecBase *SysBase; -struct objc_libc libc; - -#if defined(OF_AMIGAOS_M68K) -__asm__ ( - ".text\n" - ".globl ___restore_a4\n" - ".align 1\n" - "___restore_a4:\n" - " movea.l 42(a6), a4\n" - " rts" -); -#elif defined(OF_MORPHOS) -/* All __saveds functions in this file need to use the M68K ABI */ -__asm__ ( - ".section .text\n" - ".align 2\n" - "__restore_r13:\n" - " lwz %r13, 56(%r2)\n" - " lwz %r13, 44(%r13)\n" - " blr\n" -); -#endif - -static OF_INLINE char * -getDataSeg(void) -{ - char *dataSeg; - -#if defined(OF_AMIGAOS_M68K) - __asm__ ( - "move.l #___a4_init, %0" - : "=r"(dataSeg) - ); -#elif defined(OF_MORPHOS) - __asm__ ( - "lis %0, __r13_init@ha\n\t" - "la %0, __r13_init@l(%0)" - : "=r"(dataSeg) - ); -#endif - - return dataSeg; -} - -static OF_INLINE size_t -getDataSize(void) -{ - size_t dataSize; - -#if defined(OF_AMIGAOS_M68K) - __asm__ ( - "move.l #___data_size, %0\n\t" - "add.l #___bss_size, %0" - : "=r"(dataSize) - ); -#elif defined(OF_MORPHOS) - __asm__ ( - "lis %0, __sdata_size@ha\n\t" - "la %0, __sdata_size@l(%0)\n\t" - "lis %%r9, __sbss_size@ha\n\t" - "la %%r9, __sbss_size@l(%%r9)\n\t" - "add %0, %0, %%r9" - : "=r"(dataSize) - :: "r9" - ); -#endif - - return dataSize; -} - -static OF_INLINE size_t * -getDataDataRelocs(void) -{ - size_t *dataDataRelocs; - -#if defined(OF_AMIGAOS_M68K) - __asm__ ( - "move.l #___datadata_relocs, %0" - : "=r"(dataDataRelocs) - ); -#elif defined(OF_MORPHOS) - __asm__ ( - "lis %0, __datadata_relocs@ha\n\t" - "la %0, __datadata_relocs@l(%0)\n\t" - : "=r"(dataDataRelocs) - ); -#endif - - return dataDataRelocs; -} - -static struct Library * -lib_init(struct ObjFWRTBase *base OBJC_M68K_REG(d0), - void *segList OBJC_M68K_REG(a0), struct ExecBase *sysBase OBJC_M68K_REG(a6)) -{ -#if defined(OF_AMIGAOS_M68K) - __asm__ __volatile__ ( - "move.l a6, _SysBase" - :: "a"(sysBase) - ); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "lis %%r9, SysBase@ha\n\t" - "stw %0, SysBase@l(%%r9)" - :: "r"(sysBase) : "r9" - ); -#endif - - base->segList = segList; - base->parent = NULL; - base->dataSeg = getDataSeg(); - - return &base->library; -} - -struct Library *__saveds -lib_open(void) -{ - OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6) - - struct ObjFWRTBase *child; - size_t dataSize, *dataDataRelocs; - ptrdiff_t displacement; - - if (base->parent != NULL) - return NULL; - - base->library.lib_OpenCnt++; - base->library.lib_Flags &= ~LIBF_DELEXP; - - /* - * We cannot use malloc here, as that depends on the libc passed from - * the application. - */ - if ((child = AllocMem(base->library.lib_NegSize + - base->library.lib_PosSize, MEMF_ANY)) == NULL) { - base->library.lib_OpenCnt--; - return NULL; - } - - memcpy(child, (char *)base - base->library.lib_NegSize, - base->library.lib_NegSize + base->library.lib_PosSize); - - child = (struct ObjFWRTBase *) - ((char *)child + base->library.lib_NegSize); - child->library.lib_OpenCnt = 1; - child->parent = base; - - dataSize = getDataSize(); - - if ((child->dataSeg = AllocMem(dataSize, MEMF_ANY)) == NULL) { - FreeMem((char *)child - child->library.lib_NegSize, - child->library.lib_NegSize + child->library.lib_PosSize); - base->library.lib_OpenCnt--; - return NULL; - } - - memcpy(child->dataSeg, base->dataSeg - DATA_OFFSET, dataSize); - - dataDataRelocs = getDataDataRelocs(); - displacement = child->dataSeg - (base->dataSeg - DATA_OFFSET); - - for (size_t i = 1; i <= dataDataRelocs[0]; i++) - *(long *)(child->dataSeg + dataDataRelocs[i]) += displacement; - - child->dataSeg += DATA_OFFSET; - - return &child->library; -} - -static void * -expunge(struct ObjFWRTBase *base, struct ExecBase *sysBase) -{ -#define SysBase sysBase - void *segList; - - if (base->parent != NULL) { - base->parent->library.lib_Flags |= LIBF_DELEXP; - return 0; - } - - if (base->library.lib_OpenCnt > 0) { - base->library.lib_Flags |= LIBF_DELEXP; - return 0; - } - - segList = base->segList; - - Remove(&base->library.lib_Node); - FreeMem((char *)base - base->library.lib_NegSize, - base->library.lib_NegSize + base->library.lib_PosSize); - - return segList; -#undef SysBase -} - -static void *__saveds -lib_expunge(void) -{ - OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6) - - return expunge(base, SysBase); -} - -static void *__saveds -lib_close(void) -{ - /* - * SysBase becomes invalid during this function, so we store it in - * sysBase and add a define to make the inlines use the right one. - */ - struct ExecBase *sysBase = SysBase; -#define SysBase sysBase - - OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6) - - if (base->parent != NULL) { - struct ObjFWRTBase *parent; - -#ifdef OF_AMIGAOS_M68K - if (base->initialized) - for (void *const *frame = _EH_FRAME_BEGINS__; - *frame != NULL;) - libc.__deregister_frame_info(*frame++); -#endif - - parent = base->parent; - - FreeMem(base->dataSeg - DATA_OFFSET, getDataSize()); - FreeMem((char *)base - base->library.lib_NegSize, - base->library.lib_NegSize + base->library.lib_PosSize); - - base = parent; - } - - if (--base->library.lib_OpenCnt == 0 && - (base->library.lib_Flags & LIBF_DELEXP)) - return expunge(base, sysBase); - - return NULL; -#undef SysBase -} - -static void * -lib_null(void) -{ - return NULL; -} - -bool -objc_init(unsigned int version, struct objc_libc *libc_) -{ -#ifdef OF_AMIGAOS_M68K - OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6) -#else - register struct ObjFWRTBase *r12 __asm__("r12"); - struct ObjFWRTBase *base = r12; -#endif -#ifdef OF_MORPHOS - void *frame; -#endif - uintptr_t *iter, *iter0; - - if (version > 1) - return false; - - memcpy(&libc, libc_, sizeof(libc)); - -#ifdef OF_AMIGAOS_M68K - for (void *const *frame = _EH_FRAME_OBJECTS__, - **object = _EH_FRAME_OBJECTS__; *frame != NULL;) - libc.__register_frame_info(*frame++, *object++); - - iter0 = &__CTOR_LIST__[1]; -#elif defined(OF_MORPHOS) - __asm__ ( - "lis %0, __EH_FRAME_BEGIN__@ha\n\t" - "la %0, __EH_FRAME_BEGIN__@l(%0)\n\t" - "lis %1, __CTOR_LIST__@ha\n\t" - "la %1, __CTOR_LIST__@l(%1)\n\t" - : "=r"(frame), "=r"(iter0) - ); - - libc.__register_frame(frame); -#endif - - for (iter = iter0; *iter != 0; iter++); - - while (iter > iter0) { - void (*ctor)(void) = (void (*)(void))*--iter; - ctor(); - } - - base->initialized = true; - - return true; -} - -void * -malloc(size_t size) -{ - return libc.malloc(size); -} - -void * -calloc(size_t count, size_t size) -{ - return libc.calloc(count, size); -} - -void * -realloc(void *ptr, size_t size) -{ - return libc.realloc(ptr, size); -} - -void -free(void *ptr) -{ - libc.free(ptr); -} - -#ifdef HAVE_SJLJ_EXCEPTIONS -int -_Unwind_SjLj_RaiseException(void *ex) -{ - return libc._Unwind_SjLj_RaiseException(ex); -} -#else -int -_Unwind_RaiseException(void *ex) -{ - return libc._Unwind_RaiseException(ex); -} -#endif - -void -_Unwind_DeleteException(void *ex) -{ - libc._Unwind_DeleteException(ex); -} - -void * -_Unwind_GetLanguageSpecificData(void *ctx) -{ - return libc._Unwind_GetLanguageSpecificData(ctx); -} - -uintptr_t -_Unwind_GetRegionStart(void *ctx) -{ - return libc._Unwind_GetRegionStart(ctx); -} - -uintptr_t -_Unwind_GetDataRelBase(void *ctx) -{ - return libc._Unwind_GetDataRelBase(ctx); -} - -uintptr_t -_Unwind_GetTextRelBase(void *ctx) -{ - return libc._Unwind_GetTextRelBase(ctx); -} - -uintptr_t -_Unwind_GetIP(void *ctx) -{ - return libc._Unwind_GetIP(ctx); -} - -uintptr_t -_Unwind_GetGR(void *ctx, int gr) -{ - return libc._Unwind_GetGR(ctx, gr); -} - -void -_Unwind_SetIP(void *ctx, uintptr_t ip) -{ - libc._Unwind_SetIP(ctx, ip); -} - -void -_Unwind_SetGR(void *ctx, int gr, uintptr_t value) -{ - libc._Unwind_SetGR(ctx, gr, value); -} - -#ifdef HAVE_SJLJ_EXCEPTIONS -void -_Unwind_SjLj_Resume(void *ex) -{ - libc._Unwind_SjLj_Resume(ex); -} -#else -void -_Unwind_Resume(void *ex) -{ - libc._Unwind_Resume(ex); -} -#endif - -#ifdef OF_AMIGAOS_M68K -int -snprintf(char *restrict str, size_t size, const char *restrict fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vsnprintf(str, size, fmt, args); - va_end(args); - - return ret; -} - -int -vsnprintf(char *restrict str, size_t size, const char *restrict fmt, - va_list args) -{ - return libc.vsnprintf(str, size, fmt, args); -} -#endif - -int -atexit(void (*function)(void)) -{ - return libc.atexit(function); -} - -void -exit(int status) -{ - libc.exit(status); - - OF_UNREACHABLE -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -static CONST_APTR functionTable[] = { -#ifdef OF_MORPHOS - (CONST_APTR)FUNCARRAY_BEGIN, - (CONST_APTR)FUNCARRAY_32BIT_NATIVE, -#endif - (CONST_APTR)lib_open, - (CONST_APTR)lib_close, - (CONST_APTR)lib_expunge, - (CONST_APTR)lib_null, -#ifdef OF_MORPHOS - (CONST_APTR)-1, - (CONST_APTR)FUNCARRAY_32BIT_SYSTEMV, -#endif -#include "amiga-funcarray.inc" - (CONST_APTR)-1, -#ifdef OF_MORPHOS - (CONST_APTR)FUNCARRAY_END -#endif -}; -#pragma GCC diagnostic pop - -static struct { - ULONG dataSize; - CONST_APTR *functionTable; - ULONG *dataTable; - struct Library *(*initFunc)( - struct ObjFWRTBase *base OBJC_M68K_REG(d0), - void *segList OBJC_M68K_REG(a0), - struct ExecBase *execBase OBJC_M68K_REG(a6)); -} init_table = { - sizeof(struct ObjFWRTBase), - functionTable, - NULL, - lib_init -}; - -struct Resident resident = { - .rt_MatchWord = RTC_MATCHWORD, - .rt_MatchTag = &resident, - .rt_EndSkip = &resident + 1, - .rt_Flags = RTF_AUTOINIT -#ifdef OF_MORPHOS - | RTF_PPC | RTF_EXTENDED -#endif - , - .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", - .rt_Init = &init_table, -#ifdef OF_MORPHOS - .rt_Revision = OBJFWRT_LIB_MINOR, - .rt_Tags = NULL, -#endif -}; - -#ifdef OF_MORPHOS -__asm__ ( - ".section .eh_frame, \"aw\"\n" - ".globl __EH_FRAME_BEGIN__\n" - ".type __EH_FRAME_BEGIN__, @object\n" - "__EH_FRAME_BEGIN__:\n" - ".section .ctors, \"aw\"\n" - ".globl __CTOR_LIST__\n" - ".type __CTOR_LIST__, @object\n" - "__CTOR_LIST__:\n" - ".section .text" -); -#endif DELETED src/runtime/amiga-library.xml Index: src/runtime/amiga-library.xml ================================================================== --- src/runtime/amiga-library.xml +++ src/runtime/amiga-library.xml @@ -1,345 +0,0 @@ - - ObjFWRT.h - private.h - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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,10 +778,15 @@ objc_updateDTable(class); } Method +#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) { Method method; Class superclass; 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 DELETED src/runtime/linklib/Makefile Index: src/runtime/linklib/Makefile ================================================================== --- src/runtime/linklib/Makefile +++ src/runtime/linklib/Makefile @@ -1,13 +0,0 @@ -include ../../../extra.mk - -STATIC_LIB = libobjfwrt.library.a -SRCS = init.m \ - linklib.m - -include ../../../buildsys.mk - -CPPFLAGS += -I.. -I../.. -I../../.. \ - -DOBJC_COMPILING_AMIGA_LINKLIB \ - -DOBJFWRT_AMIGA_LIB=\"${OBJFWRT_AMIGA_LIB}\" \ - -DOBJFWRT_LIB_MINOR=${OBJFWRT_LIB_MINOR} -LD = ${OBJC} DELETED src/runtime/linklib/init.m Index: src/runtime/linklib/init.m ================================================================== --- src/runtime/linklib/init.m +++ src/runtime/linklib/init.m @@ -1,188 +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 "ObjFWRT.h" -#import "private.h" -#import "macros.h" - -#include -#include - -struct ObjFWRTBase; - -#include -#include - -#if defined(OF_AMIGAOS_M68K) -# include -#elif defined(OF_MORPHOS) -# include -#endif - -#ifdef HAVE_SJLJ_EXCEPTIONS -extern int _Unwind_SjLj_RaiseException(void *); -#else -extern int _Unwind_RaiseException(void *); -#endif -extern void _Unwind_DeleteException(void *); -extern void *_Unwind_GetLanguageSpecificData(void *); -extern uintptr_t _Unwind_GetRegionStart(void *); -extern uintptr_t _Unwind_GetDataRelBase(void *); -extern uintptr_t _Unwind_GetTextRelBase(void *); -extern uintptr_t _Unwind_GetIP(void *); -extern uintptr_t _Unwind_GetGR(void *, int); -extern void _Unwind_SetIP(void *, uintptr_t); -extern void _Unwind_SetGR(void *, int, uintptr_t); -#ifdef HAVE_SJLJ_EXCEPTIONS -extern void _Unwind_SjLj_Resume(void *); -#else -extern void _Unwind_Resume(void *); -#endif -#ifdef OF_AMIGAOS_M68K -extern void __register_frame_info(const void *, void *); -extern void *__deregister_frame_info(const void *); -#endif -#ifdef OF_MORPHOS -extern void __register_frame(void *); -extern void __deregister_frame(void *); -#endif - -struct Library *ObjFWRTBase; -void *__objc_class_name_Protocol; - -extern bool objc_init(unsigned int version, struct objc_libc *libc); - -static void -error(const char *string, ULONG arg) -{ - struct Library *IntuitionBase = OpenLibrary("intuition.library", 0); - - if (IntuitionBase != NULL) { - struct EasyStruct easy = { - .es_StructSize = sizeof(easy), - .es_Flags = 0, - .es_Title = (void *)NULL, - .es_TextFormat = (void *)string, - (void *)"OK" - }; - - EasyRequest(NULL, &easy, NULL, arg); - - CloseLibrary(IntuitionBase); - } - - exit(EXIT_FAILURE); -} - -static void __attribute__((__used__)) -ctor(void) -{ - static bool initialized = false; - struct objc_libc libc = { - .malloc = malloc, - .calloc = calloc, - .realloc = realloc, - .free = free, -#ifdef HAVE_SJLJ_EXCEPTIONS - ._Unwind_SjLj_RaiseException = _Unwind_SjLj_RaiseException, -#else - ._Unwind_RaiseException = _Unwind_RaiseException, -#endif - ._Unwind_DeleteException = _Unwind_DeleteException, - ._Unwind_GetLanguageSpecificData = - _Unwind_GetLanguageSpecificData, - ._Unwind_GetRegionStart = _Unwind_GetRegionStart, - ._Unwind_GetDataRelBase = _Unwind_GetDataRelBase, - ._Unwind_GetTextRelBase = _Unwind_GetTextRelBase, - ._Unwind_GetIP = _Unwind_GetIP, - ._Unwind_GetGR = _Unwind_GetGR, - ._Unwind_SetIP = _Unwind_SetIP, - ._Unwind_SetGR = _Unwind_SetGR, -#ifdef HAVE_SJLJ_EXCEPTIONS - ._Unwind_SjLj_Resume = _Unwind_SjLj_Resume, -#else - ._Unwind_Resume = _Unwind_Resume, -#endif -#ifdef OF_AMIGAOS_M68K - .__register_frame_info = __register_frame_info, - .__deregister_frame_info = __deregister_frame_info, -#endif -#ifdef OF_MORPHOS - .__register_frame = __register_frame, - .__deregister_frame = __deregister_frame, -#endif -#ifdef OF_AMIGAOS_M68K - .vsnprintf = vsnprintf, -#endif - .atexit = atexit, - .exit = exit, - }; - - if (initialized) - return; - - if ((ObjFWRTBase = OpenLibrary(OBJFWRT_AMIGA_LIB, - OBJFWRT_LIB_MINOR)) == NULL) - error("Failed to open " OBJFWRT_AMIGA_LIB " version %lu!", - OBJFWRT_LIB_MINOR); - - if (!objc_init(1, &libc)) - error("Failed to initialize " OBJFWRT_AMIGA_LIB "!", 0); - - initialized = true; -} - -static void __attribute__((__used__)) -dtor(void) -{ - CloseLibrary(ObjFWRTBase); -} - -#if defined(OF_AMIGAOS_M68K) -ADD2INIT(ctor, -5) -ADD2EXIT(dtor, -5) -#elif defined(OF_MORPHOS) -CONSTRUCTOR_P(ObjFWRT, 4000) -{ - ctor(); - - return 0; -} - -DESTRUCTOR_P(ObjFWRT, 0) -{ - dtor(); -} -#endif - -extern int __gnu_objc_personality(int version, int actions, uint64_t *exClass, - void *ex, void *ctx); - -int -#ifdef HAVE_SJLJ_EXCEPTIONS -__gnu_objc_personality_sj0( -#else -__gnu_objc_personality_v0( -#endif - int version, int actions, uint64_t exClass, void *ex, void *ctx) -{ -#ifdef OF_AMIGAOS_M68K - return __gnu_objc_personality(version, actions, &exClass, ex, ctx); -#else - return __gnu_objc_personality(version, actions, &exClass, ex, ctx); -#endif -} DELETED src/runtime/linklib/linklib.m Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -1,1538 +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. - */ - -/* This file is automatically generated from amiga-library.xml */ - -#include "config.h" - -#import "ObjFWRT.h" -#import "private.h" - -extern struct Library *ObjFWRTBase; - -bool -objc_init(unsigned int version, struct objc_libc *libc) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(unsigned int __asm__("d0"), struct objc_libc *__asm__("a0")))(((uintptr_t)ObjFWRTBase) - 30))(version, libc); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(unsigned int, struct objc_libc *))*(void **)(((uintptr_t)ObjFWRTBase) - 28))(version, libc); -#endif -} - -void -__objc_exec_class(struct objc_module *_Nonnull module) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(struct objc_module *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 36))(module); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(struct objc_module *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 34))(module); -#endif -} - -IMP _Nonnull -objc_msg_lookup(id _Nullable object, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nonnull (*)(id _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 42))(object, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nonnull (*)(id _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 40))(object, selector); -#endif -} - -IMP _Nonnull -objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nonnull (*)(id _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 48))(object, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nonnull (*)(id _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 46))(object, selector); -#endif -} - -IMP _Nonnull -objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nonnull (*)(struct objc_super *_Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 54))(super, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nonnull (*)(struct objc_super *_Nonnull, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 52))(super, selector); -#endif -} - -IMP _Nonnull -objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nonnull (*)(struct objc_super *_Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 60))(super, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nonnull (*)(struct objc_super *_Nonnull, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 58))(super, selector); -#endif -} - -Class _Nullable -objc_lookUpClass(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 66))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 64))(name); -#endif -} - -Class _Nullable -objc_getClass(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 72))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 70))(name); -#endif -} - -Class _Nonnull -objc_getRequiredClass(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nonnull (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 78))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nonnull (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 76))(name); -#endif -} - -Class _Nullable -objc_lookup_class(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 84))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 82))(name); -#endif -} - -Class _Nonnull -objc_get_class(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nonnull (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 90))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nonnull (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 88))(name); -#endif -} - -void -objc_exception_throw(id _Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 96))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 94))(object); -#endif - - OF_UNREACHABLE -} - -int -objc_sync_enter(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((int (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 102))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((int (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 100))(object); -#endif -} - -int -objc_sync_exit(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((int (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 108))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((int (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 106))(object); -#endif -} - -id _Nullable -objc_getProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, bool atomic) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1"), ptrdiff_t __asm__("d0"), bool __asm__("d1")))(((uintptr_t)ObjFWRTBase) - 114))(self, _cmd, offset, atomic); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nonnull, SEL _Nonnull, ptrdiff_t, bool))*(void **)(((uintptr_t)ObjFWRTBase) - 112))(self, _cmd, offset, atomic); -#endif -} - -void -objc_setProperty(id _Nonnull self, SEL _Nonnull _cmd, ptrdiff_t offset, id _Nullable value, bool atomic, signed char copy) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1"), ptrdiff_t __asm__("d0"), id _Nullable __asm__("a2"), bool __asm__("d1"), signed char __asm__("d2")))(((uintptr_t)ObjFWRTBase) - 120))(self, _cmd, offset, value, atomic, copy); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nonnull, SEL _Nonnull, ptrdiff_t, id _Nullable, bool, signed char))*(void **)(((uintptr_t)ObjFWRTBase) - 118))(self, _cmd, offset, value, atomic, copy); -#endif -} - -void -objc_getPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(void *_Nonnull __asm__("a0"), const void *_Nonnull __asm__("a1"), ptrdiff_t __asm__("d0"), bool __asm__("d1"), bool __asm__("d2")))(((uintptr_t)ObjFWRTBase) - 126))(dest, src, size, atomic, strong); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(void *_Nonnull, const void *_Nonnull, ptrdiff_t, bool, bool))*(void **)(((uintptr_t)ObjFWRTBase) - 124))(dest, src, size, atomic, strong); -#endif -} - -void -objc_setPropertyStruct(void *_Nonnull dest, const void *_Nonnull src, ptrdiff_t size, bool atomic, bool strong) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(void *_Nonnull __asm__("a0"), const void *_Nonnull __asm__("a1"), ptrdiff_t __asm__("d0"), bool __asm__("d1"), bool __asm__("d2")))(((uintptr_t)ObjFWRTBase) - 132))(dest, src, size, atomic, strong); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(void *_Nonnull, const void *_Nonnull, ptrdiff_t, bool, bool))*(void **)(((uintptr_t)ObjFWRTBase) - 130))(dest, src, size, atomic, strong); -#endif -} - -void -objc_enumerationMutation(id _Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 138))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 136))(object); -#endif -} - -int -__gnu_objc_personality(int version, int actions, uint64_t *_Nonnull exClass, void *_Nonnull ex, void *_Nonnull ctx) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((int (*)(int __asm__("d0"), int __asm__("d1"), uint64_t *_Nonnull __asm__("d2"), void *_Nonnull __asm__("a0"), void *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 144))(version, actions, exClass, ex, ctx); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((int (*)(int, int, uint64_t *_Nonnull, void *_Nonnull, void *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 142))(version, actions, exClass, ex, ctx); -#endif -} - -id _Nullable -objc_retain(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 150))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 148))(object); -#endif -} - -id _Nullable -objc_retainBlock(id _Nullable block) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 156))(block); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 154))(block); -#endif -} - -id _Nullable -objc_retainAutorelease(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 162))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 160))(object); -#endif -} - -void -objc_release(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 168))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 166))(object); -#endif -} - -id _Nullable -objc_autorelease(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 174))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 172))(object); -#endif -} - -id _Nullable -objc_autoreleaseReturnValue(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 180))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 178))(object); -#endif -} - -id _Nullable -objc_retainAutoreleaseReturnValue(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 186))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 184))(object); -#endif -} - -id _Nullable -objc_retainAutoreleasedReturnValue(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 192))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 190))(object); -#endif -} - -id _Nullable -objc_storeStrong(id _Nullable *_Nonnull object, id _Nullable value) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable *_Nonnull __asm__("a0"), id _Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 198))(object, value); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable *_Nonnull, id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 196))(object, value); -#endif -} - -id _Nullable -objc_storeWeak(id _Nullable *_Nonnull object, id _Nullable value) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable *_Nonnull __asm__("a0"), id _Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 204))(object, value); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable *_Nonnull, id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 202))(object, value); -#endif -} - -id _Nullable -objc_loadWeakRetained(id _Nullable *_Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 210))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 208))(object); -#endif -} - -id _Nullable -objc_initWeak(id _Nullable *_Nonnull object, id _Nullable value) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable *_Nonnull __asm__("a0"), id _Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 216))(object, value); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable *_Nonnull, id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 214))(object, value); -#endif -} - -void -objc_destroyWeak(id _Nullable *_Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nullable *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 222))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nullable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 220))(object); -#endif -} - -id _Nullable -objc_loadWeak(id _Nullable *_Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 228))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 226))(object); -#endif -} - -void -objc_copyWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nullable *_Nonnull __asm__("a0"), id _Nullable *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 234))(dest, src); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nullable *_Nonnull, id _Nullable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 232))(dest, src); -#endif -} - -void -objc_moveWeak(id _Nullable *_Nonnull dest, id _Nullable *_Nonnull src) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(id _Nullable *_Nonnull __asm__("a0"), id _Nullable *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 240))(dest, src); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(id _Nullable *_Nonnull, id _Nullable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 238))(dest, src); -#endif -} - -SEL _Nonnull -sel_registerName(const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((SEL _Nonnull (*)(const char *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 246))(name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((SEL _Nonnull (*)(const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 244))(name); -#endif -} - -const char *_Nonnull -sel_getName(SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nonnull (*)(SEL _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 252))(selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nonnull (*)(SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 250))(selector); -#endif -} - -bool -sel_isEqual(SEL _Nonnull selector1, SEL _Nonnull selector2) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(SEL _Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 258))(selector1, selector2); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(SEL _Nonnull, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 256))(selector1, selector2); -#endif -} - -Class _Nonnull -objc_allocateClassPair(Class _Nullable superclass, const char *_Nonnull name, size_t extraBytes) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nonnull (*)(Class _Nullable __asm__("a0"), const char *_Nonnull __asm__("a1"), size_t __asm__("d0")))(((uintptr_t)ObjFWRTBase) - 264))(superclass, name, extraBytes); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nonnull (*)(Class _Nullable, const char *_Nonnull, size_t))*(void **)(((uintptr_t)ObjFWRTBase) - 262))(superclass, name, extraBytes); -#endif -} - -void -objc_registerClassPair(Class _Nonnull class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(Class _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 270))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(Class _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 268))(class); -#endif -} - -unsigned int -objc_getClassList(Class _Nonnull *_Nullable buffer, unsigned int count) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((unsigned int (*)(Class _Nonnull *_Nullable __asm__("a0"), unsigned int __asm__("d0")))(((uintptr_t)ObjFWRTBase) - 276))(buffer, count); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((unsigned int (*)(Class _Nonnull *_Nullable, unsigned int))*(void **)(((uintptr_t)ObjFWRTBase) - 274))(buffer, count); -#endif -} - -Class _Nonnull *_Nonnull -objc_copyClassList(unsigned int *_Nullable length) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nonnull *_Nonnull (*)(unsigned int *_Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 282))(length); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nonnull *_Nonnull (*)(unsigned int *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 280))(length); -#endif -} - -bool -class_isMetaClass(Class _Nullable class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Class _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 288))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Class _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 286))(class); -#endif -} - -const char *_Nullable -class_getName(Class _Nullable class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nullable (*)(Class _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 294))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nullable (*)(Class _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 292))(class); -#endif -} - -Class _Nullable -class_getSuperclass(Class _Nullable class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(Class _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 300))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(Class _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 298))(class); -#endif -} - -unsigned long -class_getInstanceSize(Class _Nullable class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((unsigned long (*)(Class _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 306))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((unsigned long (*)(Class _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 304))(class); -#endif -} - -bool -class_respondsToSelector(Class _Nullable class, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Class _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 312))(class, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Class _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 310))(class, selector); -#endif -} - -bool -class_conformsToProtocol(Class _Nullable class, Protocol *_Nonnull p) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Class _Nullable __asm__("a0"), Protocol *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 318))(class, p); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Class _Nullable, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 316))(class, p); -#endif -} - -IMP _Nullable -class_getMethodImplementation(Class _Nullable class, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nullable (*)(Class _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 324))(class, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nullable (*)(Class _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 322))(class, selector); -#endif -} - -IMP _Nullable -class_getMethodImplementation_stret(Class _Nullable class, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nullable (*)(Class _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 330))(class, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nullable (*)(Class _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 328))(class, selector); -#endif -} - -Method _Nullable -class_getInstanceMethod(Class _Nullable class, SEL _Nonnull selector) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Method _Nullable (*)(Class _Nullable __asm__("a0"), SEL _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 336))(class, selector); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Method _Nullable (*)(Class _Nullable, SEL _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 334))(class, selector); -#endif -} - -bool -class_addMethod(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Class _Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1"), IMP _Nonnull __asm__("a2"), const char *_Nullable __asm__("a3")))(((uintptr_t)ObjFWRTBase) - 342))(class, selector, implementation, typeEncoding); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Class _Nonnull, SEL _Nonnull, IMP _Nonnull, const char *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 340))(class, selector, implementation, typeEncoding); -#endif -} - -IMP _Nullable -class_replaceMethod(Class _Nonnull class, SEL _Nonnull selector, IMP _Nonnull implementation, const char *_Nullable typeEncoding) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((IMP _Nullable (*)(Class _Nonnull __asm__("a0"), SEL _Nonnull __asm__("a1"), IMP _Nonnull __asm__("a2"), const char *_Nullable __asm__("a3")))(((uintptr_t)ObjFWRTBase) - 348))(class, selector, implementation, typeEncoding); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((IMP _Nullable (*)(Class _Nonnull, SEL _Nonnull, IMP _Nonnull, const char *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 346))(class, selector, implementation, typeEncoding); -#endif -} - -Class _Nullable -object_getClass(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 354))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 352))(object); -#endif -} - -Class _Nullable -object_setClass(id _Nullable object, Class _Nonnull class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Class _Nullable (*)(id _Nullable __asm__("a0"), Class _Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 360))(object, class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Class _Nullable (*)(id _Nullable, Class _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 358))(object, class); -#endif -} - -const char *_Nullable -object_getClassName(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 366))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 364))(object); -#endif -} - -const char *_Nonnull -protocol_getName(Protocol *_Nonnull protocol) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nonnull (*)(Protocol *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 372))(protocol); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nonnull (*)(Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 370))(protocol); -#endif -} - -bool -protocol_isEqual(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Protocol *_Nonnull __asm__("a0"), Protocol *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 378))(protocol1, protocol2); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Protocol *_Nonnull, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 376))(protocol1, protocol2); -#endif -} - -bool -protocol_conformsToProtocol(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(Protocol *_Nonnull __asm__("a0"), Protocol *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 384))(protocol1, protocol2); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(Protocol *_Nonnull, Protocol *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 382))(protocol1, protocol2); -#endif -} - -_Nullable objc_uncaught_exception_handler -objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler _Nullable handler) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 390))(handler); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((_Nullable objc_uncaught_exception_handler (*)(objc_uncaught_exception_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 388))(handler); -#endif -} - -void -objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(IMP _Nullable __asm__("a0"), IMP _Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 396))(forward, stretForward); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(IMP _Nullable, IMP _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 394))(forward, stretForward); -#endif -} - -void -objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler _Nullable hadler) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(objc_enumeration_mutation_handler _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 402))(hadler); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(objc_enumeration_mutation_handler _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 400))(hadler); -#endif -} - -id _Nullable -objc_constructInstance(Class _Nullable class, void *_Nullable bytes) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(Class _Nullable __asm__("a0"), void *_Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 408))(class, bytes); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(Class _Nullable, void *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 406))(class, bytes); -#endif -} - -void -objc_deinit() -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)())(((uintptr_t)ObjFWRTBase) - 414))(); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)())*(void **)(((uintptr_t)ObjFWRTBase) - 412))(); -#endif -} - -Ivar _Nullable *_Nullable -class_copyIvarList(Class _Nullable class, unsigned int *_Nullable outCount) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Ivar _Nullable *_Nullable (*)(Class _Nullable __asm__("a0"), unsigned int *_Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 420))(class, outCount); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Ivar _Nullable *_Nullable (*)(Class _Nullable, unsigned int *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 418))(class, outCount); -#endif -} - -const char *_Nonnull -ivar_getName(Ivar _Nonnull ivar) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nonnull (*)(Ivar _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 426))(ivar); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nonnull (*)(Ivar _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 424))(ivar); -#endif -} - -const char *_Nonnull -ivar_getTypeEncoding(Ivar _Nonnull ivar) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nonnull (*)(Ivar _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 432))(ivar); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nonnull (*)(Ivar _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 430))(ivar); -#endif -} - -ptrdiff_t -ivar_getOffset(Ivar _Nonnull ivar) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((ptrdiff_t (*)(Ivar _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 438))(ivar); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((ptrdiff_t (*)(Ivar _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 436))(ivar); -#endif -} - -Method _Nullable *_Nullable -class_copyMethodList(Class _Nullable class, unsigned int *_Nullable outCount) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((Method _Nullable *_Nullable (*)(Class _Nullable __asm__("a0"), unsigned int *_Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 444))(class, outCount); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((Method _Nullable *_Nullable (*)(Class _Nullable, unsigned int *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 442))(class, outCount); -#endif -} - -SEL _Nonnull -method_getName(Method _Nonnull method) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((SEL _Nonnull (*)(Method _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 450))(method); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((SEL _Nonnull (*)(Method _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 448))(method); -#endif -} - -const char *_Nullable -method_getTypeEncoding(Method _Nonnull method) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nullable (*)(Method _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 456))(method); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nullable (*)(Method _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 454))(method); -#endif -} - -objc_property_t _Nullable *_Nullable -class_copyPropertyList(Class _Nullable class, unsigned int *_Nullable outCount) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((objc_property_t _Nullable *_Nullable (*)(Class _Nullable __asm__("a0"), unsigned int *_Nullable __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 462))(class, outCount); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((objc_property_t _Nullable *_Nullable (*)(Class _Nullable, unsigned int *_Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 460))(class, outCount); -#endif -} - -const char *_Nonnull -property_getName(objc_property_t _Nonnull property) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((const char *_Nonnull (*)(objc_property_t _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 468))(property); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((const char *_Nonnull (*)(objc_property_t _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 466))(property); -#endif -} - -char *_Nullable -property_copyAttributeValue(objc_property_t _Nonnull property, const char *_Nonnull name) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((char *_Nullable (*)(objc_property_t _Nonnull __asm__("a0"), const char *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 474))(property, name); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((char *_Nullable (*)(objc_property_t _Nonnull, const char *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 472))(property, name); -#endif -} - -void *_Nullable -objc_destructInstance(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((void *_Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 480))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((void *_Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 478))(object); -#endif -} - -void *_Null_unspecified -objc_autoreleasePoolPush() -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((void *_Null_unspecified (*)())(((uintptr_t)ObjFWRTBase) - 486))(); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((void *_Null_unspecified (*)())*(void **)(((uintptr_t)ObjFWRTBase) - 484))(); -#endif -} - -void -objc_autoreleasePoolPop(void *_Null_unspecified pool) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(void *_Null_unspecified __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 492))(pool); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(void *_Null_unspecified))*(void **)(((uintptr_t)ObjFWRTBase) - 490))(pool); -#endif -} - -id _Nullable -_objc_rootAutorelease(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 498))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 496))(object); -#endif -} - -struct objc_hashtable *_Nonnull -objc_hashtable_new(objc_hashtable_hash_func hash, objc_hashtable_equal_func equal, uint32_t size) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((struct objc_hashtable *_Nonnull (*)(objc_hashtable_hash_func __asm__("a0"), objc_hashtable_equal_func __asm__("a1"), uint32_t __asm__("d0")))(((uintptr_t)ObjFWRTBase) - 504))(hash, equal, size); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((struct objc_hashtable *_Nonnull (*)(objc_hashtable_hash_func, objc_hashtable_equal_func, uint32_t))*(void **)(((uintptr_t)ObjFWRTBase) - 502))(hash, equal, size); -#endif -} - -void -objc_hashtable_set(struct objc_hashtable *_Nonnull table, const void *_Nonnull key, const void *_Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(struct objc_hashtable *_Nonnull __asm__("a0"), const void *_Nonnull __asm__("a1"), const void *_Nonnull __asm__("a2")))(((uintptr_t)ObjFWRTBase) - 510))(table, key, object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(struct objc_hashtable *_Nonnull, const void *_Nonnull, const void *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 508))(table, key, object); -#endif -} - -void *_Nullable -objc_hashtable_get(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((void *_Nullable (*)(struct objc_hashtable *_Nonnull __asm__("a0"), const void *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 516))(table, key); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((void *_Nullable (*)(struct objc_hashtable *_Nonnull, const void *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 514))(table, key); -#endif -} - -void -objc_hashtable_delete(struct objc_hashtable *_Nonnull table, const void *_Nonnull key) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(struct objc_hashtable *_Nonnull __asm__("a0"), const void *_Nonnull __asm__("a1")))(((uintptr_t)ObjFWRTBase) - 522))(table, key); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(struct objc_hashtable *_Nonnull, const void *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 520))(table, key); -#endif -} - -void -objc_hashtable_free(struct objc_hashtable *_Nonnull table) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(struct objc_hashtable *_Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 528))(table); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(struct objc_hashtable *_Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 526))(table); -#endif -} - -void -objc_setTaggedPointerSecret(uintptr_t secret) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - ((void (*)(uintptr_t __asm__("d0")))(((uintptr_t)ObjFWRTBase) - 534))(secret); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - __extension__ ((void (*)(uintptr_t))*(void **)(((uintptr_t)ObjFWRTBase) - 532))(secret); -#endif -} - -int -objc_registerTaggedPointerClass(Class _Nonnull class) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((int (*)(Class _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 540))(class); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((int (*)(Class _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 538))(class); -#endif -} - -bool -object_isTaggedPointer(id _Nullable object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((bool (*)(id _Nullable __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 546))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((bool (*)(id _Nullable))*(void **)(((uintptr_t)ObjFWRTBase) - 544))(object); -#endif -} - -uintptr_t -object_getTaggedPointerValue(id _Nonnull object) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((uintptr_t (*)(id _Nonnull __asm__("a0")))(((uintptr_t)ObjFWRTBase) - 552))(object); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((uintptr_t (*)(id _Nonnull))*(void **)(((uintptr_t)ObjFWRTBase) - 550))(object); -#endif -} - -id _Nullable -objc_createTaggedPointer(int class, uintptr_t value) -{ -#if defined(OF_AMIGAOS_M68K) - register struct Library *a6 __asm__("a6") = ObjFWRTBase; - (void)a6; - return ((id _Nullable (*)(int __asm__("d0"), uintptr_t __asm__("d1")))(((uintptr_t)ObjFWRTBase) - 558))(class, value); -#elif defined(OF_MORPHOS) - __asm__ __volatile__ ( - "mr %%r12, %0" - :: "r"(ObjFWRTBase) : "r12" - ); - - return __extension__ ((id _Nullable (*)(int, uintptr_t))*(void **)(((uintptr_t)ObjFWRTBase) - 556))(class, value); -#endif -} Index: src/runtime/lookup-asm/Makefile ================================================================== --- src/runtime/lookup-asm/Makefile +++ src/runtime/lookup-asm/Makefile @@ -1,12 +1,10 @@ include ../../../extra.mk STATIC_PIC_LIB_NOINST = ${LOOKUP_ASM_LIB_A} -STATIC_AMIGA_LIB_NOINST = ${LOOKUP_ASM_AMIGALIB_A} STATIC_LIB_NOINST = ${LOOKUP_ASM_A} SRCS = lookup-asm.S include ../../../buildsys.mk ASFLAGS += -I../../.. -I../.. -ASFLAGS_lookup-asm.amigalib.o += -DOF_BASEREL 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-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-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,11 +38,11 @@ # include "lookup-asm-sparc64-elf.S" # elif defined(OF_SPARC) # include "lookup-asm-sparc-elf.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 @@ -14,11 +14,10 @@ */ #include "config.h" #import "macros.h" -#import "platform.h" #if !defined(__has_feature) || !__has_feature(nullability) # ifndef _Nonnull # define _Nonnull # endif @@ -214,75 +213,10 @@ IMP _Nullable buckets[256]; #endif } *_Nonnull buckets[256]; }; -#if defined(OBJC_COMPILING_AMIGA_LIBRARY) || \ - defined(OBJC_COMPILING_AMIGA_LINKLIB) -struct objc_libc { - void *_Nullable (*_Nonnull malloc)(size_t); - void *_Nullable (*_Nonnull calloc)(size_t, size_t); - void *_Nullable (*_Nonnull realloc)(void *_Nullable, size_t); - void (*_Nonnull free)(void *_Nullable); -# ifdef HAVE_SJLJ_EXCEPTIONS - int (*_Nonnull _Unwind_SjLj_RaiseException)(void *_Nonnull); -# else - int (*_Nonnull _Unwind_RaiseException)(void *_Nonnull); -# endif - void (*_Nonnull _Unwind_DeleteException)(void *_Nonnull); - void *_Nullable (*_Nonnull _Unwind_GetLanguageSpecificData)( - void *_Nonnull); - uintptr_t (*_Nonnull _Unwind_GetRegionStart)(void *_Nonnull); - uintptr_t (*_Nonnull _Unwind_GetDataRelBase)(void *_Nonnull); - uintptr_t (*_Nonnull _Unwind_GetTextRelBase)(void *_Nonnull); - uintptr_t (*_Nonnull _Unwind_GetIP)(void *_Nonnull); - uintptr_t (*_Nonnull _Unwind_GetGR)(void *_Nonnull, int); - void (*_Nonnull _Unwind_SetIP)(void *_Nonnull, uintptr_t); - void (*_Nonnull _Unwind_SetGR)(void *_Nonnull, int, uintptr_t); -# ifdef HAVE_SJLJ_EXCEPTIONS - void (*_Nonnull _Unwind_SjLj_Resume)(void *_Nonnull); -# else - void (*_Nonnull _Unwind_Resume)(void *_Nonnull); -# endif -# ifdef OF_AMIGAOS_M68K - void (*_Nonnull __register_frame_info)(const void *_Nonnull, - void *_Nonnull); - void *(*_Nonnull __deregister_frame_info)(const void *_Nonnull); -# endif -# ifdef OF_MORPHOS - void (*_Nonnull __register_frame)(void *_Nonnull); - void (*_Nonnull __deregister_frame)(void *_Nonnull); -# endif -# ifdef OF_AMIGAOS_M68K - int (*_Nonnull vsnprintf)(char *restrict _Nonnull str, size_t size, - const char *_Nonnull restrict fmt, va_list args); -# endif - int (*_Nonnull atexit)(void (*_Nonnull)(void)); - void (*_Nonnull exit)(int); -}; -#endif - -#ifdef OBJC_COMPILING_AMIGA_LIBRARY -# if defined(__MORPHOS__) -# include -# define OBJC_M68K_ARG(type, name, reg) type name = (type)REG_##reg; -# else -# define OBJC_M68K_ARG(type, name, reg) \ - register type reg_##name __asm__(#reg); \ - type name = reg_##name; -# endif - -extern bool objc_init(unsigned int, struct objc_libc *); -# ifdef HAVE_SJLJ_EXCEPTIONS -# define __gnu_objc_personality(version, actions, exClass, ex, ctx) \ - __gnu_objc_personality_sj0(version, actions, *exClass, ex, ctx) -# else -# define __gnu_objc_personality(version, actions, exClass, ex, ctx) \ - __gnu_objc_personality_v0(version, actions, *exClass, ex, ctx) -# endif -#endif - extern void objc_registerAllCategories(struct objc_symtab *_Nonnull); extern struct objc_category *_Nullable *_Nullable objc_categoriesForClass(Class _Nonnull); extern void objc_unregisterAllCategories(void); extern void objc_initializeClass(Class _Nonnull); @@ -356,19 +290,19 @@ #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_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 @@ -206,12 +206,12 @@ isEqual: RESULT]) /* * Don't try fpret on Win64 if we don't have stret forwarding, as * long double is handled as a struct there. */ -# if !defined(OF_WINDOWS) || !defined(OF_X86_64) || \ - defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET) +# if !defined(OF_WINDOWS) || !defined(OF_AMD64) || \ + defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET) TEST(@"-[forwardingTargetForSelector:] fp return", [testObject forwardingTargetFPRetTest] == 12345678.00006103515625) # endif # ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET TEST(@"-[forwardingTargetForSelector:] struct return", 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} \ @@ -73,12 +72,14 @@ OFHTTPCookieManagerTests.m \ OFKernelEventObserverTests.m \ OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ + ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} +SRCS_APPLETALK = OFDDPSocketTests.m SRCS_IPX = OFIPXSocketTests.m \ OFSPXSocketTests.m \ OFSPXStreamSocketTests.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ OFUNIXStreamSocketTests.m @@ -88,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 $@ @@ -104,11 +103,10 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib - rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../src/libobjfw.so; then \ ${LN_S} ../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -137,14 +135,10 @@ fi if test -f ../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi - if test -f ../src/runtime/${OBJFWRT_AMIGA_LIB}; then \ - ${LN_S} ../src/runtime/${OBJFWRT_AMIGA_LIB} \ - ${OBJFWRT_AMIGA_LIB}; \ - fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_FRAMEWORK_PATH=../src:../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ 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 ADDED tests/OFDDPSocketTests.m Index: tests/OFDDPSocketTests.m ================================================================== --- tests/OFDDPSocketTests.m +++ tests/OFDDPSocketTests.m @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2023 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It 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 "TestsAppDelegate.h" + +static OFString *const module = @"OFDDPSocket"; + +@implementation TestsAppDelegate (OFDDPSocketTests) +- (void)DDPSocketTests +{ + void *pool = objc_autoreleasePoolPush(); + OFDDPSocket *sock; + OFSocketAddress address1, address2; + char buffer[5]; + + TEST(@"+[socket]", (sock = [OFDDPSocket socket])) + + @try { + TEST(@"-[bindToNetwork:node:port:]", + R(address1 = [sock bindToNetwork: 0 + node: 0 + 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"]; + break; + case EADDRNOTAVAIL: + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeLine: + @"\r[OFDDPSocket] -[bindToNetwork:node:port:" + @"protocolType:] AppleTalk not configured, " + @"skipping tests"]; + break; + default: + @throw e; + } + + objc_autoreleasePoolPop(pool); + return; + } + + TEST(@"-[sendBuffer:length:receiver:]", + R([sock sendBuffer: "Hello" length: 5 receiver: &address1])) + + TEST(@"-[receiveIntoBuffer:length:sender:]", + [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 && + memcmp(buffer, "Hello", 5) == 0 && + OFSocketAddressEqual(&address1, &address2) && + OFSocketAddressHash(&address1) == OFSocketAddressHash(&address2)) + + objc_autoreleasePoolPop(pool); +} +@end 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 @@ -22,49 +22,91 @@ static OFString *const module = @"OFIPXSocket"; @implementation TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests { + 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(@"-[bindToPort:packetType:]", - R(address1 = [sock bindToPort: 0 packetType: 0])) - } @catch (OFBindFailedException *e) { + TEST(@"-[bindToNetwork:node:port:packetType:]", + R(address1 = [sock bindToNetwork: 0 + node: zeroNode + port: 0 + packetType: 0])) + } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFIPXSocket] -[bindToPort:packetType:]: " - @"IPX unsupported, skipping tests"]; + @"\r[OFIPXSocket] -[bindToNetwork:node:port:" + @"packetType:]: IPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFIPXSocket] -[bindToPort:packetType:]: " - @"IPX not configured, skipping tests"]; + @"\r[OFIPXSocket] -[bindToNetwork:node:port:" + @"packetType:]: IPX not configured, skipping " + @"tests"]; break; default: @throw e; } 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:]", [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 && memcmp(buffer, "Hello", 5) == 0 && - OFSocketAddressEqual(&address1, &address2) && - OFSocketAddressHash(&address1) == OFSocketAddressHash(&address2)) + R(OFSocketAddressGetIPXNode(&address1, node1)) && + R(OFSocketAddressGetIPXNode(&address2, node2)) && + memcmp(node1, node2, IPX_NODE_LEN) == 0 && + OFSocketAddressIPXPort(&address1) == + OFSocketAddressIPXPort(&address2)) objc_autoreleasePoolPop(pool); } @end 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 @@ -13,11 +13,10 @@ * file. */ #include "config.h" -#include #include #if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) # include #endif @@ -57,14 +56,10 @@ st.i = 0xAAAAAAAA; TEST(@"+[invocationWithMethodSignature:]", (invocation = [OFInvocation invocationWithMethodSignature: sig])) -#ifdef __clang_analyzer__ - assert(invocation != nil); -#endif - TEST(@"-[setReturnValue]", R([invocation setReturnValue: &st])) TEST(@"-[getReturnValue]", R([invocation getReturnValue: &st2]) && memcmp(&st, &st2, sizeof(st)) == 0) 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 @@ -50,11 +50,11 @@ return false; } - (void)socket: (OFSPXSocket *)sock didConnectToNetwork: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port exception: (id)exception { OFEnsure(!_connected); @@ -69,44 +69,48 @@ @end @implementation TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests { + const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; void *pool = objc_autoreleasePoolPush(); OFSPXSocket *sockClient, *sockServer = nil, *sockAccepted; 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])) @try { - TEST(@"-[bindToPort:]", - R(address1 = [sockServer bindToPort: 0])) - } @catch (OFBindFailedException *e) { + TEST(@"-[bindToNetwork:node:port:]", + R(address1 = [sockServer bindToNetwork: 0 + node: zeroNode + port: 0])) + } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXSocket] -[bindToPort:]: " + @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: " @"IPX unsupported, skipping tests"]; break; case ESOCKTNOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXSocket] -[bindToPort:]: " + @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: " @"SPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXSocket] -[bindToPort:]: " + @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: " @"IPX not configured, skipping tests"]; break; default: @throw e; } @@ -114,14 +118,32 @@ objc_autoreleasePoolPop(pool); return; } network = OFSocketAddressIPXNetwork(&address1); - OFSocketAddressIPXNode(&address1, node); - port = OFSocketAddressPort(&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])) @@ -133,12 +155,11 @@ [sockClient receiveIntoBuffer: buffer length: 5] == 5 && memcmp(buffer, "Hello", 5) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - OFSocketAddressIPXNetwork(address2) == network && - R(OFSocketAddressIPXNode(address2, node2)) && + R(OFSocketAddressGetIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXSocket socket]; @@ -147,19 +168,19 @@ sockClient = [OFSPXSocket socket]; delegate->_expectedClientSocket = sockClient; sockClient.delegate = delegate; - address1 = [sockServer bindToPort: 0]; + address1 = [sockServer bindToNetwork: 0 node: zeroNode port: 0]; [sockServer listen]; [sockServer asyncAccept]; delegate->_expectedNetwork = network = OFSocketAddressIPXNetwork(&address1); - OFSocketAddressIPXNode(&address1, node); + OFSocketAddressGetIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); - delegate->_expectedPort = port = OFSocketAddressPort(&address1); + delegate->_expectedPort = port = OFSocketAddressIPXPort(&address1); @try { [sockClient asyncConnectToNetwork: network node: node port: port]; @@ -168,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 @@ -50,11 +50,11 @@ return false; } - (void)socket: (OFSPXStreamSocket *)sock didConnectToNetwork: (uint32_t)network - node: (unsigned char [IPX_NODE_LEN])node + node: (const unsigned char [IPX_NODE_LEN])node port: (uint16_t)port exception: (id)exception { OFEnsure(!_connected); @@ -69,46 +69,50 @@ @end @implementation TestsAppDelegate (OFSPXStreamSocketTests) - (void)SPXStreamSocketTests { + const unsigned char zeroNode[IPX_NODE_LEN] = { 0 }; void *pool = objc_autoreleasePoolPush(); OFSPXStreamSocket *sockClient, *sockServer = nil, *sockAccepted; 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])) @try { - TEST(@"-[bindToPort:]", - R(address1 = [sockServer bindToPort: 0])) - } @catch (OFBindFailedException *e) { + TEST(@"-[bindToNetwork:node:port:]", + R(address1 = [sockServer bindToNetwork: 0 + node: zeroNode + port: 0])) + } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXStreamSocket] -[bindToPort:]: " - @"IPX unsupported, skipping tests"]; + @"\r[OFSPXStreamSocket] -[bindToNetwork:node:" + @"port:]: IPX unsupported, skipping tests"]; break; case ESOCKTNOSUPPORT: case EPROTONOSUPPORT: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXStreamSocket] -[bindToPort:]: " - @"SPX unsupported, skipping tests"]; + @"\r[OFSPXStreamSocket] -[bindToNetwork:node:" + @"port:]: SPX unsupported, skipping tests"]; break; case EADDRNOTAVAIL: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: - @"\r[OFSPXStreamSocket] -[bindToPort:]: " - @"IPX not configured, skipping tests"]; + @"\r[OFSPXStreamSocket] -[bindToNetwork:node:" + @"port:]: IPX not configured, skipping tests"]; break; default: @throw e; } @@ -115,14 +119,32 @@ objc_autoreleasePoolPop(pool); return; } network = OFSocketAddressIPXNetwork(&address1); - OFSocketAddressIPXNode(&address1, node); - port = OFSocketAddressPort(&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])) @@ -137,12 +159,11 @@ [sockClient readIntoBuffer: buffer length: 3] == 3 && memcmp(buffer, "llo", 3) == 0) TEST(@"-[remoteAddress]", (address2 = sockAccepted.remoteAddress) && - OFSocketAddressIPXNetwork(address2) == network && - R(OFSocketAddressIPXNode(address2, node2)) && + R(OFSocketAddressGetIPXNode(address2, node2)) && memcmp(node, node2, IPX_NODE_LEN) == 0) delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease]; sockServer = [OFSPXStreamSocket socket]; @@ -151,19 +172,19 @@ sockClient = [OFSPXStreamSocket socket]; delegate->_expectedClientSocket = sockClient; sockClient.delegate = delegate; - address1 = [sockServer bindToPort: 0]; + address1 = [sockServer bindToNetwork: 0 node: zeroNode port: 0]; [sockServer listen]; [sockServer asyncAccept]; delegate->_expectedNetwork = network = OFSocketAddressIPXNetwork(&address1); - OFSocketAddressIPXNode(&address1, node); + OFSocketAddressGetIPXNode(&address1, node); memcpy(delegate->_expectedNode, node, IPX_NODE_LEN); - delegate->_expectedPort = port = OFSocketAddressPort(&address1); + delegate->_expectedPort = port = OFSocketAddressIPXPort(&address1); @try { [sockClient asyncConnectToNetwork: network node: node port: port]; @@ -172,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 @@ -81,11 +81,11 @@ OFSocketAddressParseIP(@"127.0.a.1", 1234)) EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", OFInvalidFormatException, OFSocketAddressParseIP(@"127.0..1", 1234)) - TEST(@"Port of an IPv4 address", OFSocketAddressPort(&addr) == 1234) + TEST(@"Port of an IPv4 address", OFSocketAddressIPPort(&addr) == 1234) TEST(@"Converting an IPv4 to a string", [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"]) TEST(@"Parsing an IPv6 #1", @@ -113,10 +113,26 @@ TEST(@"Parsing an IPv6 #5", R(addr = OFSocketAddressParseIP(@"::aaAa", 1234)) && COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) + TEST(@"Parsing an IPv6 #6", + 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)) @@ -143,11 +159,13 @@ OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234)) EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", OFInvalidFormatException, OFSocketAddressParseIP(@"1:2", 1234)) - TEST(@"Port of an IPv6 address", OFSocketAddressPort(&addr) == 1234) + TEST(@"Port of an IPv6 address", OFSocketAddressIPPort(&addr) == 1234) + + addr.sockaddr.in6.sin6_scope_id = 0; SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) TEST(@"Converting an IPv6 to a string #1", [OFSocketAddressString(&addr) isEqual: @"::"]) 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,28 +67,34 @@ [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", [OFSystemInfo CPUModel]]; -#if defined(OF_X86_64) || defined(OF_X86) +#if defined(OF_AMD64) || 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"] && - OFSocketAddressPort(&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 @@ -48,11 +48,11 @@ TEST(@"+[socket]", (sock = [OFUNIXDatagramSocket socket])) @try { TEST(@"-[bindToPath:]", R(address1 = [sock bindToPath: path])) - } @catch (OFBindFailedException *e) { + } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: case EPERM: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: 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 @@ -48,11 +48,11 @@ TEST(@"+[socket]", (sockClient = [OFUNIXStreamSocket socket]) && (sockServer = [OFUNIXStreamSocket socket])) @try { TEST(@"-[bindToPath:]", R([sockServer bindToPath: path])) - } @catch (OFBindFailedException *e) { + } @catch (OFBindSocketFailedException *e) { switch (e.errNo) { case EAFNOSUPPORT: case EPERM: [OFStdOut setForegroundColor: [OFColor lime]]; [OFStdOut writeLine: @@ -79,16 +79,16 @@ TEST(@"-[readIntoBuffer:length:]", [sockClient readIntoBuffer: buffer length: 5] == 5 && memcmp(buffer, "Hello", 5) == 0) - TEST(@"-[remoteAddress]", - OFSocketAddressUNIXPath(sockAccepted.remoteAddress) == nil) + TEST(@"-[remoteAddress]", OFSocketAddressUNIXPath( + sockAccepted.remoteAddress).length == 0) } @finally { #ifdef OF_HAVE_FILES [[OFFileManager defaultManager] removeItemAtPath: path]; #endif } objc_autoreleasePoolPop(pool); } @end 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 @@ -25,11 +25,11 @@ @implementation RuntimeARCTest - (instancetype)init { self = [super init]; -#if defined(OF_WINDOWS) && defined(OF_X86_64) +#if defined(OF_WINDOWS) && defined(OF_AMD64) /* * Clang has a bug on Windows where it creates an invalid call into * objc_retainAutoreleasedReturnValue(). Work around it by not using an * autoreleased exception. */ 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,18 @@ @end @interface TestsAppDelegate (OFCharacterSetTests) - (void)characterSetTests; @end + +@interface TestsAppDelegate (OFColorTests) +- (void)colorTests; +@end + +@interface TestsAppDelegate (OFDDPSocketTests) +- (void)DDPSocketTests; +@end @interface TestsAppDelegate (OFDNSResolverTests) - (void)DNSResolverTests; @end @@ -104,10 +112,14 @@ @end @interface TestsAppDelegate (OFINIFileTests) - (void)INIFileTests; @end + +@interface TestsAppDelegate (OFIRITests) +- (void)IRITests; +@end @interface TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests; @end @@ -136,10 +148,14 @@ @end @interface TestsAppDelegate (OFMD5HashTests) - (void)MD5HashTests; @end + +@interface TestsAppDelegate (OFMatrix4x4Tests) +- (void)matrix4x4Tests; +@end @interface TestsAppDelegate (OFMemoryStreamTests) - (void)memoryStreamTests; @end @@ -213,14 +229,10 @@ @interface TestsAppDelegate (OFSPXStreamSocketTests) - (void)SPXStreamSocketTests; @end -@interface TestsAppDelegate (OFSerializationTests) -- (void)serializationTests; -@end - @interface TestsAppDelegate (OFSetTests) - (void)setTests; @end @interface TestsAppDelegate (OFSystemInfoTests) @@ -257,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 @@ -347,11 +347,11 @@ [OFStdOut reset]; [OFStdOut eraseLine]; } } -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { #if defined(OF_IOS) && defined(OF_HAVE_FILES) CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); UInt8 resourcesPath[PATH_MAX]; @@ -389,10 +389,11 @@ [self listTests]; [self setTests]; [self dateTests]; [self valueTests]; [self numberTests]; + [self colorTests]; [self streamTests]; [self memoryStreamTests]; [self notificationCenterTests]; [self MD5HashTests]; [self RIPEMD160HashTests]; @@ -409,25 +410,28 @@ #endif #ifdef OF_HAVE_SOCKETS [self socketTests]; [self TCPSocketTests]; [self UDPSocketTests]; +# ifdef OF_HAVE_UNIX_SOCKETS + [self UNIXDatagramSocketTests]; + [self UNIXStreamSocketTests]; +# endif # ifdef OF_HAVE_IPX [self IPXSocketTests]; [self SPXSocketTests]; [self SPXStreamSocketTests]; # endif -# ifdef OF_HAVE_UNIX_SOCKETS - [self UNIXDatagramSocketTests]; - [self UNIXStreamSocketTests]; +# ifdef OF_HAVE_APPLETALK + [self DDPSocketTests]; # endif [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]; @@ -434,13 +438,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/Makefile ================================================================== --- tests/objc_sync/Makefile +++ tests/objc_sync/Makefile @@ -12,11 +12,10 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib - rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -45,14 +44,10 @@ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi - if test -f ../../src/runtime/${OBJFWRT_AMIGA_LIB}; then \ - ${LN_S} ../../src/runtime/${OBJFWRT_AMIGA_LIB} \ - ${OBJFWRT_AMIGA_LIB}; \ - fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ 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/Makefile ================================================================== --- tests/terminal/Makefile +++ tests/terminal/Makefile @@ -12,11 +12,10 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib - rm -f ${OBJFWRT_AMIGA_LIB} if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -45,14 +44,10 @@ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi - if test -f ../../src/runtime/${OBJFWRT_AMIGA_LIB}; then \ - ${LN_S} ../../src/runtime/${OBJFWRT_AMIGA_LIB} \ - ${OBJFWRT_AMIGA_LIB}; \ - fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ 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 @@ -25,11 +25,11 @@ @end OF_APPLICATION_DELEGATE(TerminalTests) @implementation TerminalTests -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { OFArray *colors = [OFArray arrayWithObjects: [OFColor black], [OFColor silver], [OFColor grey], [OFColor white], [OFColor maroon], [OFColor red], [OFColor purple], [OFColor fuchsia], [OFColor green], [OFColor lime], [OFColor olive], 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 @@ -8,11 +8,15 @@ cat < #include -extern void OFRegisterEmbeddedFile(const char *, const uint8_t *, size_t); +#ifdef OF_COMPILING_OBJFW +# import "OFEmbeddedIRIHandler.h" +#else +# 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/$/,/' cat < + * Copyright (c) 2008-2023 Jonathan Schleifer * * All rights reserved. * * This file is part of ObjFW. It 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,14 +46,15 @@ @"@end\n" @"\n" @"OF_APPLICATION_DELEGATE(%@)\n" @"\n" @"@implementation %@\n" - @"- (void)applicationDidFinishLaunching\n" + @"- (void)applicationDidFinishLaunching: " + @"(OFNotification *)notification\n" @"{\n" @" [OFApplication terminate];\n" @"}\n" @"@end\n", name, name, name]; [file close]; } 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 @@ -38,11 +38,11 @@ [OFApplication terminateWithStatus: 1]; } @implementation ObjFWNew -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { bool app, class; OFString *superclass = nil, *name; OFMutableArray OF_GENERIC(OFString *) *properties = nil; const OFOptionsParserOption options[] = { 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 @@ -51,11 +51,12 @@ - (void)parseString: (OFString *)string { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = string.UTF8String; - size_t length = string.UTF8StringLength, nameIdx = -1; + size_t length = string.UTF8StringLength; + ssize_t nameIdx = -1; OFMutableArray *attributes = nil; if (length > SSIZE_MAX) @throw [OFOutOfRangeException exception]; 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" @@ -165,11 +165,11 @@ [archive addFiles: expandedFiles]; } @implementation OFArc -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { OFString *outputDir, *encodingString, *type; const OFOptionsParserOption options[] = { { 'a', @"append", 0, NULL, NULL }, { 'c', @"create", 0, NULL, NULL }, @@ -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 { @@ -437,13 +443,10 @@ @"file", fileName)]; entry = [OFMutableZIPArchiveEntry entryWithFileName: fileName]; size = (isDirectory ? 0 : attributes.fileSize); - if (size < 0 || size > ULLONG_MAX) - @throw [OFOutOfRangeException exception]; - entry.compressedSize = size; entry.uncompressedSize = size; entry.compressionMethod = OFZIPArchiveEntryCompressionMethodNone; 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]; } @@ -78,18 +81,20 @@ if (_inFlight == 0) [OFApplication terminateWithStatus: _errors]; } -- (void)applicationDidFinishLaunching +- (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" @@ -66,11 +67,11 @@ [OFStdOut writeFormat: @" %@\n", path]; } @implementation OFHash -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { int exitStatus = 0; bool calculateMD5, calculateRIPEMD160, calculateSHA1, calculateSHA224; bool calculateSHA256, calculateSHA384, calculateSHA512; const OFOptionsParserOption options[] = { @@ -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,26 +34,26 @@ #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 -#import "OFConnectionFailedException.h" +#import "OFConnectSocketFailedException.h" #import "OFGetItemAttributesFailedException.h" #import "OFHTTPRequestFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #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", @@ -410,11 +412,11 @@ @"prog", [OFApplication programName])]; [OFApplication terminateWithStatus: 1]; } } -- (void)applicationDidFinishLaunching +- (void)applicationDidFinishLaunching: (OFNotification *)notification { OFString *outputPath; const OFOptionsParserOption options[] = { { 'b', @"body", 1, NULL, NULL }, { 'c', @"continue", 0, &_continue, NULL }, @@ -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: - [OFConnectionFailedException class]]) { + [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; } @@ -1078,31 +1114,31 @@ if (size > ULLONG_MAX) @throw [OFOutOfRangeException exception]; _resumedFrom = (unsigned long long)size; - range = [OFString stringWithFormat: @"bytes=%jd-", + range = [OFString stringWithFormat: @"bytes=%ju-", _resumedFrom]; [clientHeaders setObject: range forKey: @"Range"]; } @catch (OFGetItemAttributesFailedException *e) { } } 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": [